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: 354903 $")
00095
00096 #include "asterisk/paths.h"
00097 #include <sys/time.h>
00098 #include <sys/stat.h>
00099 #include <sys/mman.h>
00100 #include <time.h>
00101 #include <dirent.h>
00102 #if defined(__FreeBSD__) || defined(__OpenBSD__)
00103 #include <sys/wait.h>
00104 #endif
00105
00106 #include "asterisk/logger.h"
00107 #include "asterisk/lock.h"
00108 #include "asterisk/file.h"
00109 #include "asterisk/channel.h"
00110 #include "asterisk/pbx.h"
00111 #include "asterisk/config.h"
00112 #include "asterisk/say.h"
00113 #include "asterisk/module.h"
00114 #include "asterisk/adsi.h"
00115 #include "asterisk/app.h"
00116 #include "asterisk/manager.h"
00117 #include "asterisk/dsp.h"
00118 #include "asterisk/localtime.h"
00119 #include "asterisk/cli.h"
00120 #include "asterisk/utils.h"
00121 #include "asterisk/stringfields.h"
00122 #include "asterisk/smdi.h"
00123 #include "asterisk/astobj2.h"
00124 #include "asterisk/event.h"
00125 #include "asterisk/taskprocessor.h"
00126 #include "asterisk/test.h"
00127
00128 #ifdef ODBC_STORAGE
00129 #include "asterisk/res_odbc.h"
00130 #endif
00131
00132 #ifdef IMAP_STORAGE
00133 #include "asterisk/threadstorage.h"
00134 #endif
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
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 #ifdef IMAP_STORAGE
00436 static char imapserver[48];
00437 static char imapport[8];
00438 static char imapflags[128];
00439 static char imapfolder[64];
00440 static char imapparentfolder[64] = "\0";
00441 static char greetingfolder[64];
00442 static char authuser[32];
00443 static char authpassword[42];
00444 static int imapversion = 1;
00445
00446 static int expungeonhangup = 1;
00447 static int imapgreetings = 0;
00448 static char delimiter = '\0';
00449
00450 struct vm_state;
00451 struct ast_vm_user;
00452
00453 AST_THREADSTORAGE(ts_vmstate);
00454
00455
00456 static int init_mailstream(struct vm_state *vms, int box);
00457 static void write_file(char *filename, char *buffer, unsigned long len);
00458 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len);
00459 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu);
00460 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len);
00461 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive);
00462 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive);
00463 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu);
00464 static void vmstate_insert(struct vm_state *vms);
00465 static void vmstate_delete(struct vm_state *vms);
00466 static void set_update(MAILSTREAM * stream);
00467 static void init_vm_state(struct vm_state *vms);
00468 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro);
00469 static void get_mailbox_delimiter(struct vm_state *vms, MAILSTREAM *stream);
00470 static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
00471 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
00472 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);
00473 static void update_messages_by_imapuser(const char *user, unsigned long number);
00474 static int vm_delete(char *file);
00475
00476 static int imap_remove_file (char *dir, int msgnum);
00477 static int imap_retrieve_file (const char *dir, const int msgnum, const char *mailbox, const char *context);
00478 static int imap_delete_old_greeting (char *dir, struct vm_state *vms);
00479 static void check_quota(struct vm_state *vms, char *mailbox);
00480 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00481 struct vmstate {
00482 struct vm_state *vms;
00483 AST_LIST_ENTRY(vmstate) list;
00484 };
00485
00486 static AST_LIST_HEAD_STATIC(vmstates, vmstate);
00487
00488 #endif
00489
00490 #define SMDI_MWI_WAIT_TIMEOUT 1000
00491
00492 #define COMMAND_TIMEOUT 5000
00493
00494 #define VOICEMAIL_DIR_MODE 0777
00495 #define VOICEMAIL_FILE_MODE 0666
00496 #define CHUNKSIZE 65536
00497
00498 #define VOICEMAIL_CONFIG "voicemail.conf"
00499 #define ASTERISK_USERNAME "asterisk"
00500
00501
00502
00503
00504 #define DEFAULT_LISTEN_CONTROL_FORWARD_KEY "#"
00505 #define DEFAULT_LISTEN_CONTROL_REVERSE_KEY "*"
00506 #define DEFAULT_LISTEN_CONTROL_PAUSE_KEY "0"
00507 #define DEFAULT_LISTEN_CONTROL_RESTART_KEY "2"
00508 #define DEFAULT_LISTEN_CONTROL_STOP_KEY "13456789"
00509 #define VALID_DTMF "1234567890*#"
00510
00511
00512
00513 #define SENDMAIL "/usr/sbin/sendmail -t"
00514
00515 #define INTRO "vm-intro"
00516
00517 #define MAXMSG 100
00518 #define MAXMSGLIMIT 9999
00519
00520 #define MINPASSWORD 0
00521
00522 #define BASELINELEN 72
00523 #define BASEMAXINLINE 256
00524 #ifdef IMAP_STORAGE
00525 #define ENDL "\r\n"
00526 #else
00527 #define ENDL "\n"
00528 #endif
00529
00530 #define MAX_DATETIME_FORMAT 512
00531 #define MAX_NUM_CID_CONTEXTS 10
00532
00533 #define VM_REVIEW (1 << 0)
00534 #define VM_OPERATOR (1 << 1)
00535 #define VM_SAYCID (1 << 2)
00536 #define VM_SVMAIL (1 << 3)
00537 #define VM_ENVELOPE (1 << 4)
00538 #define VM_SAYDURATION (1 << 5)
00539 #define VM_SKIPAFTERCMD (1 << 6)
00540 #define VM_FORCENAME (1 << 7)
00541 #define VM_FORCEGREET (1 << 8)
00542 #define VM_PBXSKIP (1 << 9)
00543 #define VM_DIRECFORWARD (1 << 10)
00544 #define VM_ATTACH (1 << 11)
00545 #define VM_DELETE (1 << 12)
00546 #define VM_ALLOCED (1 << 13)
00547 #define VM_SEARCH (1 << 14)
00548 #define VM_TEMPGREETWARN (1 << 15)
00549 #define VM_MOVEHEARD (1 << 16)
00550 #define VM_MESSAGEWRAP (1 << 17)
00551 #define VM_FWDURGAUTO (1 << 18)
00552 #define ERROR_LOCK_PATH -100
00553 #define OPERATOR_EXIT 300
00554
00555
00556 enum vm_box {
00557 NEW_FOLDER,
00558 OLD_FOLDER,
00559 WORK_FOLDER,
00560 FAMILY_FOLDER,
00561 FRIENDS_FOLDER,
00562 GREETINGS_FOLDER
00563 };
00564
00565 enum vm_option_flags {
00566 OPT_SILENT = (1 << 0),
00567 OPT_BUSY_GREETING = (1 << 1),
00568 OPT_UNAVAIL_GREETING = (1 << 2),
00569 OPT_RECORDGAIN = (1 << 3),
00570 OPT_PREPEND_MAILBOX = (1 << 4),
00571 OPT_AUTOPLAY = (1 << 6),
00572 OPT_DTMFEXIT = (1 << 7),
00573 OPT_MESSAGE_Urgent = (1 << 8),
00574 OPT_MESSAGE_PRIORITY = (1 << 9)
00575 };
00576
00577 enum vm_option_args {
00578 OPT_ARG_RECORDGAIN = 0,
00579 OPT_ARG_PLAYFOLDER = 1,
00580 OPT_ARG_DTMFEXIT = 2,
00581
00582 OPT_ARG_ARRAY_SIZE = 3,
00583 };
00584
00585 enum vm_passwordlocation {
00586 OPT_PWLOC_VOICEMAILCONF = 0,
00587 OPT_PWLOC_SPOOLDIR = 1,
00588 OPT_PWLOC_USERSCONF = 2,
00589 };
00590
00591 AST_APP_OPTIONS(vm_app_options, {
00592 AST_APP_OPTION('s', OPT_SILENT),
00593 AST_APP_OPTION('b', OPT_BUSY_GREETING),
00594 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
00595 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
00596 AST_APP_OPTION_ARG('d', OPT_DTMFEXIT, OPT_ARG_DTMFEXIT),
00597 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
00598 AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
00599 AST_APP_OPTION('U', OPT_MESSAGE_Urgent),
00600 AST_APP_OPTION('P', OPT_MESSAGE_PRIORITY)
00601 });
00602
00603 static int load_config(int reload);
00604 #ifdef TEST_FRAMEWORK
00605 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg);
00606 #endif
00607 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg);
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
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 struct baseio {
00693 int iocp;
00694 int iolen;
00695 int linelength;
00696 int ateof;
00697 unsigned char iobuf[BASEMAXINLINE];
00698 };
00699
00700
00701
00702 struct ast_vm_user {
00703 char context[AST_MAX_CONTEXT];
00704 char mailbox[AST_MAX_EXTENSION];
00705 char password[80];
00706 char fullname[80];
00707 char email[80];
00708 char *emailsubject;
00709 char *emailbody;
00710 char pager[80];
00711 char serveremail[80];
00712 char mailcmd[160];
00713 char language[MAX_LANGUAGE];
00714 char zonetag[80];
00715 char locale[20];
00716 char callback[80];
00717 char dialout[80];
00718 char uniqueid[80];
00719 char exit[80];
00720 char attachfmt[20];
00721 unsigned int flags;
00722 int saydurationm;
00723 int minsecs;
00724 int maxmsg;
00725 int maxdeletedmsg;
00726 int maxsecs;
00727 int passwordlocation;
00728 #ifdef IMAP_STORAGE
00729 char imapserver[48];
00730 char imapport[8];
00731 char imapflags[128];
00732 char imapuser[80];
00733 char imappassword[80];
00734 char imapfolder[64];
00735 char imapvmshareid[80];
00736 int imapversion;
00737 #endif
00738 double volgain;
00739 AST_LIST_ENTRY(ast_vm_user) list;
00740 };
00741
00742
00743 struct vm_zone {
00744 AST_LIST_ENTRY(vm_zone) list;
00745 char name[80];
00746 char timezone[80];
00747 char msg_format[512];
00748 };
00749
00750 #define VMSTATE_MAX_MSG_ARRAY 256
00751
00752
00753 struct vm_state {
00754 char curbox[80];
00755 char username[80];
00756 char context[80];
00757 char curdir[PATH_MAX];
00758 char vmbox[PATH_MAX];
00759 char fn[PATH_MAX];
00760 char intro[PATH_MAX];
00761 int *deleted;
00762 int *heard;
00763 int dh_arraysize;
00764 int curmsg;
00765 int lastmsg;
00766 int newmessages;
00767 int oldmessages;
00768 int urgentmessages;
00769 int starting;
00770 int repeats;
00771 #ifdef IMAP_STORAGE
00772 ast_mutex_t lock;
00773 int updated;
00774 long msgArray[VMSTATE_MAX_MSG_ARRAY];
00775 MAILSTREAM *mailstream;
00776 int vmArrayIndex;
00777 char imapuser[80];
00778 char imapfolder[64];
00779 char imapserver[48];
00780 char imapport[8];
00781 char imapflags[128];
00782 int imapversion;
00783 int interactive;
00784 char introfn[PATH_MAX];
00785 unsigned int quota_limit;
00786 unsigned int quota_usage;
00787 struct vm_state *persist_vms;
00788 #endif
00789 };
00790
00791 #ifdef ODBC_STORAGE
00792 static char odbc_database[80];
00793 static char odbc_table[80];
00794 #define RETRIEVE(a,b,c,d) retrieve_file(a,b)
00795 #define DISPOSE(a,b) remove_file(a,b)
00796 #define STORE(a,b,c,d,e,f,g,h,i,j) store_file(a,b,c,d)
00797 #define EXISTS(a,b,c,d) (message_exists(a,b))
00798 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
00799 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
00800 #define DELETE(a,b,c,d) (delete_file(a,b))
00801 #else
00802 #ifdef IMAP_STORAGE
00803 #define DISPOSE(a,b) (imap_remove_file(a,b))
00804 #define STORE(a,b,c,d,e,f,g,h,i,j) (imap_store_file(a,b,c,d,e,f,g,h,i,j))
00805 #define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
00806 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00807 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00808 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
00809 #define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
00810 #else
00811 #define RETRIEVE(a,b,c,d)
00812 #define DISPOSE(a,b)
00813 #define STORE(a,b,c,d,e,f,g,h,i,j)
00814 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00815 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00816 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
00817 #define DELETE(a,b,c,d) (vm_delete(c))
00818 #endif
00819 #endif
00820
00821 static char VM_SPOOL_DIR[PATH_MAX];
00822
00823 static char ext_pass_cmd[128];
00824 static char ext_pass_check_cmd[128];
00825
00826 static int my_umask;
00827
00828 #define PWDCHANGE_INTERNAL (1 << 1)
00829 #define PWDCHANGE_EXTERNAL (1 << 2)
00830 static int pwdchange = PWDCHANGE_INTERNAL;
00831
00832 #ifdef ODBC_STORAGE
00833 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
00834 #else
00835 # ifdef IMAP_STORAGE
00836 # define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
00837 # else
00838 # define tdesc "Comedian Mail (Voicemail System)"
00839 # endif
00840 #endif
00841
00842 static char userscontext[AST_MAX_EXTENSION] = "default";
00843
00844 static char *addesc = "Comedian Mail";
00845
00846
00847 static char *app = "VoiceMail";
00848
00849
00850 static char *app2 = "VoiceMailMain";
00851
00852 static char *app3 = "MailboxExists";
00853 static char *app4 = "VMAuthenticate";
00854
00855 static char *sayname_app = "VMSayName";
00856
00857 static AST_LIST_HEAD_STATIC(users, ast_vm_user);
00858 static AST_LIST_HEAD_STATIC(zones, vm_zone);
00859 static char zonetag[80];
00860 static char locale[20];
00861 static int maxsilence;
00862 static int maxmsg;
00863 static int maxdeletedmsg;
00864 static int silencethreshold = 128;
00865 static char serveremail[80];
00866 static char mailcmd[160];
00867 static char externnotify[160];
00868 static struct ast_smdi_interface *smdi_iface = NULL;
00869 static char vmfmts[80];
00870 static double volgain;
00871 static int vmminsecs;
00872 static int vmmaxsecs;
00873 static int maxgreet;
00874 static int skipms;
00875 static int maxlogins;
00876 static int minpassword;
00877 static int passwordlocation;
00878
00879
00880
00881 static unsigned int poll_mailboxes;
00882
00883
00884 static unsigned int poll_freq;
00885
00886 #define DEFAULT_POLL_FREQ 30
00887
00888 AST_MUTEX_DEFINE_STATIC(poll_lock);
00889 static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
00890 static pthread_t poll_thread = AST_PTHREADT_NULL;
00891 static unsigned char poll_thread_run;
00892
00893
00894 static struct ast_event_sub *mwi_sub_sub;
00895
00896 static struct ast_event_sub *mwi_unsub_sub;
00897
00898
00899
00900
00901
00902
00903
00904
00905 struct mwi_sub {
00906 AST_RWLIST_ENTRY(mwi_sub) entry;
00907 int old_urgent;
00908 int old_new;
00909 int old_old;
00910 uint32_t uniqueid;
00911 char mailbox[1];
00912 };
00913
00914 struct mwi_sub_task {
00915 const char *mailbox;
00916 const char *context;
00917 uint32_t uniqueid;
00918 };
00919
00920 static struct ast_taskprocessor *mwi_subscription_tps;
00921
00922 static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
00923
00924
00925 static char listen_control_forward_key[12];
00926 static char listen_control_reverse_key[12];
00927 static char listen_control_pause_key[12];
00928 static char listen_control_restart_key[12];
00929 static char listen_control_stop_key[12];
00930
00931
00932 static char vm_password[80] = "vm-password";
00933 static char vm_newpassword[80] = "vm-newpassword";
00934 static char vm_passchanged[80] = "vm-passchanged";
00935 static char vm_reenterpassword[80] = "vm-reenterpassword";
00936 static char vm_mismatch[80] = "vm-mismatch";
00937 static char vm_invalid_password[80] = "vm-invalid-password";
00938 static char vm_pls_try_again[80] = "vm-pls-try-again";
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950 static char vm_prepend_timeout[80] = "vm-then-pound";
00951
00952 static struct ast_flags globalflags = {0};
00953
00954 static int saydurationminfo;
00955
00956 static char dialcontext[AST_MAX_CONTEXT] = "";
00957 static char callcontext[AST_MAX_CONTEXT] = "";
00958 static char exitcontext[AST_MAX_CONTEXT] = "";
00959
00960 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
00961
00962
00963 static char *emailbody = NULL;
00964 static char *emailsubject = NULL;
00965 static char *pagerbody = NULL;
00966 static char *pagersubject = NULL;
00967 static char fromstring[100];
00968 static char pagerfromstring[100];
00969 static char charset[32] = "ISO-8859-1";
00970
00971 static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
00972 static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
00973 static int adsiver = 1;
00974 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
00975 static char pagerdateformat[32] = "%A, %B %d, %Y at %r";
00976
00977
00978 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00979 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);
00980 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
00981 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
00982 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
00983 signed char record_gain, struct vm_state *vms, char *flag);
00984 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
00985 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
00986 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);
00987 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);
00988 static void apply_options(struct ast_vm_user *vmu, const char *options);
00989 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);
00990 static int is_valid_dtmf(const char *key);
00991 static void read_password_from_file(const char *secretfn, char *password, int passwordlen);
00992 static int write_password_to_file(const char *secretfn, const char *password);
00993 static const char *substitute_escapes(const char *value);
00994
00995 struct ao2_container *inprocess_container;
00996
00997 struct inprocess {
00998 int count;
00999 char *context;
01000 char mailbox[0];
01001 };
01002
01003 static int inprocess_hash_fn(const void *obj, const int flags)
01004 {
01005 const struct inprocess *i = obj;
01006 return atoi(i->mailbox);
01007 }
01008
01009 static int inprocess_cmp_fn(void *obj, void *arg, int flags)
01010 {
01011 struct inprocess *i = obj, *j = arg;
01012 if (strcmp(i->mailbox, j->mailbox)) {
01013 return 0;
01014 }
01015 return !strcmp(i->context, j->context) ? CMP_MATCH : 0;
01016 }
01017
01018 static int inprocess_count(const char *context, const char *mailbox, int delta)
01019 {
01020 struct inprocess *i, *arg = alloca(sizeof(*arg) + strlen(context) + strlen(mailbox) + 2);
01021 arg->context = arg->mailbox + strlen(mailbox) + 1;
01022 strcpy(arg->mailbox, mailbox);
01023 strcpy(arg->context, context);
01024 ao2_lock(inprocess_container);
01025 if ((i = ao2_find(inprocess_container, arg, 0))) {
01026 int ret = ast_atomic_fetchadd_int(&i->count, delta);
01027 ao2_unlock(inprocess_container);
01028 ao2_ref(i, -1);
01029 return ret;
01030 }
01031 if (delta < 0) {
01032 ast_log(LOG_WARNING, "BUG: ref count decrement on non-existing object???\n");
01033 }
01034 if (!(i = ao2_alloc(sizeof(*i) + strlen(context) + strlen(mailbox) + 2, NULL))) {
01035 ao2_unlock(inprocess_container);
01036 return 0;
01037 }
01038 i->context = i->mailbox + strlen(mailbox) + 1;
01039 strcpy(i->mailbox, mailbox);
01040 strcpy(i->context, context);
01041 i->count = delta;
01042 ao2_link(inprocess_container, i);
01043 ao2_unlock(inprocess_container);
01044 ao2_ref(i, -1);
01045 return 0;
01046 }
01047
01048 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
01049 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
01050 #endif
01051
01052
01053
01054
01055
01056
01057
01058 static char *strip_control_and_high(const char *input, char *buf, size_t buflen)
01059 {
01060 char *bufptr = buf;
01061 for (; *input; input++) {
01062 if (*input < 32) {
01063 continue;
01064 }
01065 *bufptr++ = *input;
01066 if (bufptr == buf + buflen - 1) {
01067 break;
01068 }
01069 }
01070 *bufptr = '\0';
01071 return buf;
01072 }
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088 static void populate_defaults(struct ast_vm_user *vmu)
01089 {
01090 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
01091 vmu->passwordlocation = passwordlocation;
01092 if (saydurationminfo) {
01093 vmu->saydurationm = saydurationminfo;
01094 }
01095 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
01096 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
01097 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
01098 ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
01099 ast_copy_string(vmu->locale, locale, sizeof(vmu->locale));
01100 if (vmminsecs) {
01101 vmu->minsecs = vmminsecs;
01102 }
01103 if (vmmaxsecs) {
01104 vmu->maxsecs = vmmaxsecs;
01105 }
01106 if (maxmsg) {
01107 vmu->maxmsg = maxmsg;
01108 }
01109 if (maxdeletedmsg) {
01110 vmu->maxdeletedmsg = maxdeletedmsg;
01111 }
01112 vmu->volgain = volgain;
01113 ast_free(vmu->emailsubject);
01114 vmu->emailsubject = NULL;
01115 ast_free(vmu->emailbody);
01116 vmu->emailbody = NULL;
01117 #ifdef IMAP_STORAGE
01118 ast_copy_string(vmu->imapfolder, imapfolder, sizeof(vmu->imapfolder));
01119 ast_copy_string(vmu->imapserver, imapserver, sizeof(vmu->imapserver));
01120 ast_copy_string(vmu->imapport, imapport, sizeof(vmu->imapport));
01121 ast_copy_string(vmu->imapflags, imapflags, sizeof(vmu->imapflags));
01122 #endif
01123 }
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
01134 {
01135 int x;
01136 if (!strcasecmp(var, "attach")) {
01137 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
01138 } else if (!strcasecmp(var, "attachfmt")) {
01139 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
01140 } else if (!strcasecmp(var, "serveremail")) {
01141 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
01142 } else if (!strcasecmp(var, "emailbody")) {
01143 ast_free(vmu->emailbody);
01144 vmu->emailbody = ast_strdup(substitute_escapes(value));
01145 } else if (!strcasecmp(var, "emailsubject")) {
01146 ast_free(vmu->emailsubject);
01147 vmu->emailsubject = ast_strdup(substitute_escapes(value));
01148 } else if (!strcasecmp(var, "language")) {
01149 ast_copy_string(vmu->language, value, sizeof(vmu->language));
01150 } else if (!strcasecmp(var, "tz")) {
01151 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
01152 } else if (!strcasecmp(var, "locale")) {
01153 ast_copy_string(vmu->locale, value, sizeof(vmu->locale));
01154 #ifdef IMAP_STORAGE
01155 } else if (!strcasecmp(var, "imapuser")) {
01156 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
01157 vmu->imapversion = imapversion;
01158 } else if (!strcasecmp(var, "imapserver")) {
01159 ast_copy_string(vmu->imapserver, value, sizeof(vmu->imapserver));
01160 vmu->imapversion = imapversion;
01161 } else if (!strcasecmp(var, "imapport")) {
01162 ast_copy_string(vmu->imapport, value, sizeof(vmu->imapport));
01163 vmu->imapversion = imapversion;
01164 } else if (!strcasecmp(var, "imapflags")) {
01165 ast_copy_string(vmu->imapflags, value, sizeof(vmu->imapflags));
01166 vmu->imapversion = imapversion;
01167 } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
01168 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
01169 vmu->imapversion = imapversion;
01170 } else if (!strcasecmp(var, "imapfolder")) {
01171 ast_copy_string(vmu->imapfolder, value, sizeof(vmu->imapfolder));
01172 vmu->imapversion = imapversion;
01173 } else if (!strcasecmp(var, "imapvmshareid")) {
01174 ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
01175 vmu->imapversion = imapversion;
01176 #endif
01177 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
01178 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
01179 } else if (!strcasecmp(var, "saycid")){
01180 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
01181 } else if (!strcasecmp(var, "sendvoicemail")){
01182 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
01183 } else if (!strcasecmp(var, "review")){
01184 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
01185 } else if (!strcasecmp(var, "tempgreetwarn")){
01186 ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
01187 } else if (!strcasecmp(var, "messagewrap")){
01188 ast_set2_flag(vmu, ast_true(value), VM_MESSAGEWRAP);
01189 } else if (!strcasecmp(var, "operator")) {
01190 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
01191 } else if (!strcasecmp(var, "envelope")){
01192 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
01193 } else if (!strcasecmp(var, "moveheard")){
01194 ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD);
01195 } else if (!strcasecmp(var, "sayduration")){
01196 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
01197 } else if (!strcasecmp(var, "saydurationm")){
01198 if (sscanf(value, "%30d", &x) == 1) {
01199 vmu->saydurationm = x;
01200 } else {
01201 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
01202 }
01203 } else if (!strcasecmp(var, "forcename")){
01204 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
01205 } else if (!strcasecmp(var, "forcegreetings")){
01206 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
01207 } else if (!strcasecmp(var, "callback")) {
01208 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
01209 } else if (!strcasecmp(var, "dialout")) {
01210 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
01211 } else if (!strcasecmp(var, "exitcontext")) {
01212 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
01213 } else if (!strcasecmp(var, "minsecs")) {
01214 if (sscanf(value, "%30d", &x) == 1 && x >= 0) {
01215 vmu->minsecs = x;
01216 } else {
01217 ast_log(LOG_WARNING, "Invalid min message length of %s. Using global value %d\n", value, vmminsecs);
01218 vmu->minsecs = vmminsecs;
01219 }
01220 } else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
01221 vmu->maxsecs = atoi(value);
01222 if (vmu->maxsecs <= 0) {
01223 ast_log(AST_LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
01224 vmu->maxsecs = vmmaxsecs;
01225 } else {
01226 vmu->maxsecs = atoi(value);
01227 }
01228 if (!strcasecmp(var, "maxmessage"))
01229 ast_log(AST_LOG_WARNING, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
01230 } else if (!strcasecmp(var, "maxmsg")) {
01231 vmu->maxmsg = atoi(value);
01232
01233 if (vmu->maxmsg < 0) {
01234 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
01235 vmu->maxmsg = MAXMSG;
01236 } else if (vmu->maxmsg > MAXMSGLIMIT) {
01237 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
01238 vmu->maxmsg = MAXMSGLIMIT;
01239 }
01240 } else if (!strcasecmp(var, "nextaftercmd")) {
01241 ast_set2_flag(vmu, ast_true(value), VM_SKIPAFTERCMD);
01242 } else if (!strcasecmp(var, "backupdeleted")) {
01243 if (sscanf(value, "%30d", &x) == 1)
01244 vmu->maxdeletedmsg = x;
01245 else if (ast_true(value))
01246 vmu->maxdeletedmsg = MAXMSG;
01247 else
01248 vmu->maxdeletedmsg = 0;
01249
01250 if (vmu->maxdeletedmsg < 0) {
01251 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
01252 vmu->maxdeletedmsg = MAXMSG;
01253 } else if (vmu->maxdeletedmsg > MAXMSGLIMIT) {
01254 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
01255 vmu->maxdeletedmsg = MAXMSGLIMIT;
01256 }
01257 } else if (!strcasecmp(var, "volgain")) {
01258 sscanf(value, "%30lf", &vmu->volgain);
01259 } else if (!strcasecmp(var, "passwordlocation")) {
01260 if (!strcasecmp(value, "spooldir")) {
01261 vmu->passwordlocation = OPT_PWLOC_SPOOLDIR;
01262 } else {
01263 vmu->passwordlocation = OPT_PWLOC_VOICEMAILCONF;
01264 }
01265 } else if (!strcasecmp(var, "options")) {
01266 apply_options(vmu, value);
01267 }
01268 }
01269
01270 static char *vm_check_password_shell(char *command, char *buf, size_t len)
01271 {
01272 int fds[2], pid = 0;
01273
01274 memset(buf, 0, len);
01275
01276 if (pipe(fds)) {
01277 snprintf(buf, len, "FAILURE: Pipe failed: %s", strerror(errno));
01278 } else {
01279
01280 pid = ast_safe_fork(0);
01281
01282 if (pid < 0) {
01283
01284 close(fds[0]);
01285 close(fds[1]);
01286 snprintf(buf, len, "FAILURE: Fork failed");
01287 } else if (pid) {
01288
01289 close(fds[1]);
01290 if (read(fds[0], buf, len) < 0) {
01291 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
01292 }
01293 close(fds[0]);
01294 } else {
01295
01296 AST_DECLARE_APP_ARGS(arg,
01297 AST_APP_ARG(v)[20];
01298 );
01299 char *mycmd = ast_strdupa(command);
01300
01301 close(fds[0]);
01302 dup2(fds[1], STDOUT_FILENO);
01303 close(fds[1]);
01304 ast_close_fds_above_n(STDOUT_FILENO);
01305
01306 AST_NONSTANDARD_APP_ARGS(arg, mycmd, ' ');
01307
01308 execv(arg.v[0], arg.v);
01309 printf("FAILURE: %s", strerror(errno));
01310 _exit(0);
01311 }
01312 }
01313 return buf;
01314 }
01315
01316
01317
01318
01319
01320
01321
01322
01323 static int check_password(struct ast_vm_user *vmu, char *password)
01324 {
01325
01326 if (strlen(password) < minpassword)
01327 return 1;
01328
01329 if (!ast_strlen_zero(password) && password[0] == '*')
01330 return 1;
01331 if (!ast_strlen_zero(ext_pass_check_cmd)) {
01332 char cmd[255], buf[255];
01333
01334 ast_debug(1, "Verify password policies for %s\n", password);
01335
01336 snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
01337 if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
01338 ast_debug(5, "Result: %s\n", buf);
01339 if (!strncasecmp(buf, "VALID", 5)) {
01340 ast_debug(3, "Passed password check: '%s'\n", buf);
01341 return 0;
01342 } else if (!strncasecmp(buf, "FAILURE", 7)) {
01343 ast_log(AST_LOG_WARNING, "Unable to execute password validation script: '%s'.\n", buf);
01344 return 0;
01345 } else {
01346 ast_log(AST_LOG_NOTICE, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
01347 return 1;
01348 }
01349 }
01350 }
01351 return 0;
01352 }
01353
01354
01355
01356
01357
01358
01359
01360
01361
01362
01363
01364 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
01365 {
01366 int res = -1;
01367 if (!strcmp(vmu->password, password)) {
01368
01369 return 0;
01370 }
01371
01372 if (strlen(password) > 10) {
01373 ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL);
01374 }
01375 if (ast_update2_realtime("voicemail", "context", vmu->context, "mailbox", vmu->mailbox, SENTINEL, "password", password, SENTINEL) > 0) {
01376 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: realtime engine updated with new password\r\nPasswordSource: realtime");
01377 ast_copy_string(vmu->password, password, sizeof(vmu->password));
01378 res = 0;
01379 }
01380 return res;
01381 }
01382
01383
01384
01385
01386 static void apply_options(struct ast_vm_user *vmu, const char *options)
01387 {
01388 char *stringp;
01389 char *s;
01390 char *var, *value;
01391 stringp = ast_strdupa(options);
01392 while ((s = strsep(&stringp, "|"))) {
01393 value = s;
01394 if ((var = strsep(&value, "=")) && value) {
01395 apply_option(vmu, var, value);
01396 }
01397 }
01398 }
01399
01400
01401
01402
01403
01404
01405 static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
01406 {
01407 for (; var; var = var->next) {
01408 if (!strcasecmp(var->name, "vmsecret")) {
01409 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01410 } else if (!strcasecmp(var->name, "secret") || !strcasecmp(var->name, "password")) {
01411 if (ast_strlen_zero(retval->password)) {
01412 if (!ast_strlen_zero(var->value) && var->value[0] == '*') {
01413 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
01414 "\n\tmust be reset in voicemail.conf.\n", retval->mailbox);
01415 } else {
01416 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01417 }
01418 }
01419 } else if (!strcasecmp(var->name, "uniqueid")) {
01420 ast_copy_string(retval->uniqueid, var->value, sizeof(retval->uniqueid));
01421 } else if (!strcasecmp(var->name, "pager")) {
01422 ast_copy_string(retval->pager, var->value, sizeof(retval->pager));
01423 } else if (!strcasecmp(var->name, "email")) {
01424 ast_copy_string(retval->email, var->value, sizeof(retval->email));
01425 } else if (!strcasecmp(var->name, "fullname")) {
01426 ast_copy_string(retval->fullname, var->value, sizeof(retval->fullname));
01427 } else if (!strcasecmp(var->name, "context")) {
01428 ast_copy_string(retval->context, var->value, sizeof(retval->context));
01429 } else if (!strcasecmp(var->name, "emailsubject")) {
01430 ast_free(retval->emailsubject);
01431 retval->emailsubject = ast_strdup(substitute_escapes(var->value));
01432 } else if (!strcasecmp(var->name, "emailbody")) {
01433 ast_free(retval->emailbody);
01434 retval->emailbody = ast_strdup(substitute_escapes(var->value));
01435 #ifdef IMAP_STORAGE
01436 } else if (!strcasecmp(var->name, "imapuser")) {
01437 ast_copy_string(retval->imapuser, var->value, sizeof(retval->imapuser));
01438 retval->imapversion = imapversion;
01439 } else if (!strcasecmp(var->name, "imapserver")) {
01440 ast_copy_string(retval->imapserver, var->value, sizeof(retval->imapserver));
01441 retval->imapversion = imapversion;
01442 } else if (!strcasecmp(var->name, "imapport")) {
01443 ast_copy_string(retval->imapport, var->value, sizeof(retval->imapport));
01444 retval->imapversion = imapversion;
01445 } else if (!strcasecmp(var->name, "imapflags")) {
01446 ast_copy_string(retval->imapflags, var->value, sizeof(retval->imapflags));
01447 retval->imapversion = imapversion;
01448 } else if (!strcasecmp(var->name, "imappassword") || !strcasecmp(var->name, "imapsecret")) {
01449 ast_copy_string(retval->imappassword, var->value, sizeof(retval->imappassword));
01450 retval->imapversion = imapversion;
01451 } else if (!strcasecmp(var->name, "imapfolder")) {
01452 ast_copy_string(retval->imapfolder, var->value, sizeof(retval->imapfolder));
01453 retval->imapversion = imapversion;
01454 } else if (!strcasecmp(var->name, "imapvmshareid")) {
01455 ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
01456 retval->imapversion = imapversion;
01457 #endif
01458 } else
01459 apply_option(retval, var->name, var->value);
01460 }
01461 }
01462
01463
01464
01465
01466
01467
01468
01469
01470 static int is_valid_dtmf(const char *key)
01471 {
01472 int i;
01473 char *local_key = ast_strdupa(key);
01474
01475 for (i = 0; i < strlen(key); ++i) {
01476 if (!strchr(VALID_DTMF, *local_key)) {
01477 ast_log(AST_LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
01478 return 0;
01479 }
01480 local_key++;
01481 }
01482 return 1;
01483 }
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493
01494
01495 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01496 {
01497 struct ast_variable *var;
01498 struct ast_vm_user *retval;
01499
01500 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
01501 if (!ivm)
01502 ast_set_flag(retval, VM_ALLOCED);
01503 else
01504 memset(retval, 0, sizeof(*retval));
01505 if (mailbox)
01506 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
01507 populate_defaults(retval);
01508 if (!context && ast_test_flag((&globalflags), VM_SEARCH))
01509 var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
01510 else
01511 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
01512 if (var) {
01513 apply_options_full(retval, var);
01514 ast_variables_destroy(var);
01515 } else {
01516 if (!ivm)
01517 ast_free(retval);
01518 retval = NULL;
01519 }
01520 }
01521 return retval;
01522 }
01523
01524
01525
01526
01527
01528
01529
01530
01531
01532 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01533 {
01534
01535 struct ast_vm_user *vmu = NULL, *cur;
01536 AST_LIST_LOCK(&users);
01537
01538 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
01539 context = "default";
01540
01541 AST_LIST_TRAVERSE(&users, cur, list) {
01542 #ifdef IMAP_STORAGE
01543 if (cur->imapversion != imapversion) {
01544 continue;
01545 }
01546 #endif
01547 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
01548 break;
01549 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
01550 break;
01551 }
01552 if (cur) {
01553
01554 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
01555 *vmu = *cur;
01556 if (!ivm) {
01557 vmu->emailbody = ast_strdup(cur->emailbody);
01558 vmu->emailsubject = ast_strdup(cur->emailsubject);
01559 }
01560 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
01561 AST_LIST_NEXT(vmu, list) = NULL;
01562 }
01563 } else
01564 vmu = find_user_realtime(ivm, context, mailbox);
01565 AST_LIST_UNLOCK(&users);
01566 return vmu;
01567 }
01568
01569
01570
01571
01572
01573
01574
01575
01576
01577
01578
01579 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
01580 {
01581
01582 struct ast_vm_user *cur;
01583 int res = -1;
01584 AST_LIST_LOCK(&users);
01585 AST_LIST_TRAVERSE(&users, cur, list) {
01586 if ((!context || !strcasecmp(context, cur->context)) &&
01587 (!strcasecmp(mailbox, cur->mailbox)))
01588 break;
01589 }
01590 if (cur) {
01591 ast_copy_string(cur->password, newpass, sizeof(cur->password));
01592 res = 0;
01593 }
01594 AST_LIST_UNLOCK(&users);
01595 return res;
01596 }
01597
01598
01599
01600
01601
01602
01603
01604
01605 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
01606 {
01607 struct ast_config *cfg = NULL;
01608 struct ast_variable *var = NULL;
01609 struct ast_category *cat = NULL;
01610 char *category = NULL, *value = NULL, *new = NULL;
01611 const char *tmp = NULL;
01612 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
01613 char secretfn[PATH_MAX] = "";
01614 int found = 0;
01615
01616 if (!change_password_realtime(vmu, newpassword))
01617 return;
01618
01619
01620 switch (vmu->passwordlocation) {
01621 case OPT_PWLOC_SPOOLDIR:
01622 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
01623 if (write_password_to_file(secretfn, newpassword) == 0) {
01624 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: secret.conf updated with new password\r\nPasswordSource: secret.conf");
01625 ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn);
01626 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01627 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01628 break;
01629 } else {
01630 ast_verb(4, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
01631 }
01632
01633 case OPT_PWLOC_VOICEMAILCONF:
01634 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01635 while ((category = ast_category_browse(cfg, category))) {
01636 if (!strcasecmp(category, vmu->context)) {
01637 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
01638 ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
01639 break;
01640 }
01641 value = strstr(tmp, ",");
01642 if (!value) {
01643 new = alloca(strlen(newpassword)+1);
01644 sprintf(new, "%s", newpassword);
01645 } else {
01646 new = alloca((strlen(value) + strlen(newpassword) + 1));
01647 sprintf(new, "%s%s", newpassword, value);
01648 }
01649 if (!(cat = ast_category_get(cfg, category))) {
01650 ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
01651 break;
01652 }
01653 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
01654 found = 1;
01655 }
01656 }
01657
01658 if (found) {
01659 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
01660 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01661 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01662 ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
01663 break;
01664 }
01665 }
01666
01667 case OPT_PWLOC_USERSCONF:
01668
01669
01670 if ((cfg = ast_config_load("users.conf", config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01671 ast_debug(4, "we are looking for %s\n", vmu->mailbox);
01672 for (category = ast_category_browse(cfg, NULL); category; category = ast_category_browse(cfg, category)) {
01673 ast_debug(4, "users.conf: %s\n", category);
01674 if (!strcasecmp(category, vmu->mailbox)) {
01675 if (!(tmp = ast_variable_retrieve(cfg, category, "vmsecret"))) {
01676 ast_debug(3, "looks like we need to make vmsecret!\n");
01677 var = ast_variable_new("vmsecret", newpassword, "");
01678 } else {
01679 var = NULL;
01680 }
01681 new = alloca(strlen(newpassword) + 1);
01682 sprintf(new, "%s", newpassword);
01683 if (!(cat = ast_category_get(cfg, category))) {
01684 ast_debug(4, "failed to get category!\n");
01685 ast_free(var);
01686 break;
01687 }
01688 if (!var) {
01689 ast_variable_update(cat, "vmsecret", new, NULL, 0);
01690 } else {
01691 ast_variable_append(cat, var);
01692 }
01693 found = 1;
01694 break;
01695 }
01696 }
01697
01698 if (found) {
01699 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: users.conf updated with new password\r\nPasswordSource: users.conf");
01700 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01701 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01702 ast_config_text_file_save("users.conf", cfg, "AppVoicemail");
01703 }
01704 }
01705 }
01706 }
01707
01708 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
01709 {
01710 char buf[255];
01711 snprintf(buf, sizeof(buf), "%s %s %s %s", ext_pass_cmd, vmu->context, vmu->mailbox, newpassword);
01712 ast_debug(1, "External password: %s\n",buf);
01713 if (!ast_safe_system(buf)) {
01714 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: external script updated with new password\r\nPasswordSource: external");
01715 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01716
01717 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01718 }
01719 }
01720
01721
01722
01723
01724
01725
01726
01727
01728
01729
01730
01731
01732
01733
01734 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
01735 {
01736 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
01737 }
01738
01739
01740
01741
01742
01743
01744
01745
01746
01747
01748
01749
01750
01751 static int make_file(char *dest, const int len, const char *dir, const int num)
01752 {
01753 return snprintf(dest, len, "%s/msg%04d", dir, num);
01754 }
01755
01756
01757 static FILE *vm_mkftemp(char *template)
01758 {
01759 FILE *p = NULL;
01760 int pfd = mkstemp(template);
01761 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01762 if (pfd > -1) {
01763 p = fdopen(pfd, "w+");
01764 if (!p) {
01765 close(pfd);
01766 pfd = -1;
01767 }
01768 }
01769 return p;
01770 }
01771
01772
01773
01774
01775
01776
01777
01778
01779
01780 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
01781 {
01782 mode_t mode = VOICEMAIL_DIR_MODE;
01783 int res;
01784
01785 make_dir(dest, len, context, ext, folder);
01786 if ((res = ast_mkdir(dest, mode))) {
01787 ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
01788 return -1;
01789 }
01790 return 0;
01791 }
01792
01793 static const char * const mailbox_folders[] = {
01794 #ifdef IMAP_STORAGE
01795 imapfolder,
01796 #else
01797 "INBOX",
01798 #endif
01799 "Old",
01800 "Work",
01801 "Family",
01802 "Friends",
01803 "Cust1",
01804 "Cust2",
01805 "Cust3",
01806 "Cust4",
01807 "Cust5",
01808 "Deleted",
01809 "Urgent",
01810 };
01811
01812 static const char *mbox(struct ast_vm_user *vmu, int id)
01813 {
01814 #ifdef IMAP_STORAGE
01815 if (vmu && id == 0) {
01816 return vmu->imapfolder;
01817 }
01818 #endif
01819 return (id >= 0 && id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] : "Unknown";
01820 }
01821
01822 static int get_folder_by_name(const char *name)
01823 {
01824 size_t i;
01825
01826 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
01827 if (strcasecmp(name, mailbox_folders[i]) == 0) {
01828 return i;
01829 }
01830 }
01831
01832 return -1;
01833 }
01834
01835 static void free_user(struct ast_vm_user *vmu)
01836 {
01837 if (ast_test_flag(vmu, VM_ALLOCED)) {
01838
01839 ast_free(vmu->emailbody);
01840 vmu->emailbody = NULL;
01841
01842 ast_free(vmu->emailsubject);
01843 vmu->emailsubject = NULL;
01844
01845 ast_free(vmu);
01846 }
01847 }
01848
01849 static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
01850
01851 int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
01852 if (!vms->dh_arraysize) {
01853
01854 if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
01855 return -1;
01856 }
01857 if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
01858 return -1;
01859 }
01860 vms->dh_arraysize = arraysize;
01861 } else if (vms->dh_arraysize < arraysize) {
01862 if (!(vms->deleted = ast_realloc(vms->deleted, arraysize * sizeof(int)))) {
01863 return -1;
01864 }
01865 if (!(vms->heard = ast_realloc(vms->heard, arraysize * sizeof(int)))) {
01866 return -1;
01867 }
01868 memset(vms->deleted, 0, arraysize * sizeof(int));
01869 memset(vms->heard, 0, arraysize * sizeof(int));
01870 vms->dh_arraysize = arraysize;
01871 }
01872
01873 return 0;
01874 }
01875
01876
01877
01878 #ifdef IMAP_STORAGE
01879 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
01880 {
01881 char arg[10];
01882 struct vm_state *vms;
01883 unsigned long messageNum;
01884
01885
01886 if (msgnum < 0 && !imapgreetings) {
01887 ast_filedelete(file, NULL);
01888 return;
01889 }
01890
01891 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01892 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);
01893 return;
01894 }
01895
01896
01897
01898 messageNum = vms->msgArray[msgnum];
01899 if (messageNum == 0) {
01900 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
01901 return;
01902 }
01903 ast_debug(3, "deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
01904
01905 snprintf (arg, sizeof(arg), "%lu", messageNum);
01906 ast_mutex_lock(&vms->lock);
01907 mail_setflag (vms->mailstream, arg, "\\DELETED");
01908 mail_expunge(vms->mailstream);
01909 ast_mutex_unlock(&vms->lock);
01910 }
01911
01912 static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_vm_user *vmu)
01913 {
01914 struct vm_state *vms_p;
01915 char *file, *filename;
01916 char *attachment;
01917 int i;
01918 BODY *body;
01919
01920
01921
01922
01923 if (msgnum > -1 || !imapgreetings) {
01924 return 0;
01925 } else {
01926 file = strrchr(ast_strdupa(dir), '/');
01927 if (file)
01928 *file++ = '\0';
01929 else {
01930 ast_debug(1, "Failed to procure file name from directory passed.\n");
01931 return -1;
01932 }
01933 }
01934
01935
01936 if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) &&
01937 !(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01938
01939
01940
01941
01942 if (!(vms_p = create_vm_state_from_user(vmu))) {
01943 ast_log(LOG_NOTICE, "Unable to create vm_state object!\n");
01944 return -1;
01945 }
01946 }
01947
01948
01949 *vms_p->introfn = '\0';
01950
01951 ast_mutex_lock(&vms_p->lock);
01952 if (init_mailstream(vms_p, GREETINGS_FOLDER) || !vms_p->mailstream) {
01953 ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL or can't init_mailstream\n");
01954 ast_mutex_unlock(&vms_p->lock);
01955 return -1;
01956 }
01957
01958
01959 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
01960 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
01961
01962 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01963 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
01964 } else {
01965 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
01966 ast_mutex_unlock(&vms_p->lock);
01967 return -1;
01968 }
01969 filename = strsep(&attachment, ".");
01970 if (!strcmp(filename, file)) {
01971 ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
01972 vms_p->msgArray[vms_p->curmsg] = i + 1;
01973 save_body(body, vms_p, "2", attachment, 0);
01974 ast_mutex_unlock(&vms_p->lock);
01975 return 0;
01976 }
01977 }
01978 ast_mutex_unlock(&vms_p->lock);
01979
01980 return -1;
01981 }
01982
01983 static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
01984 {
01985 BODY *body;
01986 char *header_content;
01987 char *attachedfilefmt;
01988 char buf[80];
01989 struct vm_state *vms;
01990 char text_file[PATH_MAX];
01991 FILE *text_file_ptr;
01992 int res = 0;
01993 struct ast_vm_user *vmu;
01994
01995 if (!(vmu = find_user(NULL, context, mailbox))) {
01996 ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
01997 return -1;
01998 }
01999
02000 if (msgnum < 0) {
02001 if (imapgreetings) {
02002 res = imap_retrieve_greeting(dir, msgnum, vmu);
02003 goto exit;
02004 } else {
02005 res = 0;
02006 goto exit;
02007 }
02008 }
02009
02010
02011
02012
02013 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
02014
02015
02016
02017
02018
02019
02020
02021 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
02022 res = -1;
02023 goto exit;
02024 }
02025
02026 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
02027 snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
02028
02029
02030 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
02031 res = 0;
02032 goto exit;
02033 }
02034
02035 ast_debug(3, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
02036 if (vms->msgArray[msgnum] == 0) {
02037 ast_log(LOG_WARNING, "Trying to access unknown message\n");
02038 res = -1;
02039 goto exit;
02040 }
02041
02042
02043 ast_mutex_lock(&vms->lock);
02044 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
02045 ast_mutex_unlock(&vms->lock);
02046
02047 if (ast_strlen_zero(header_content)) {
02048 ast_log(LOG_ERROR, "Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
02049 res = -1;
02050 goto exit;
02051 }
02052
02053 ast_mutex_lock(&vms->lock);
02054 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
02055 ast_mutex_unlock(&vms->lock);
02056
02057
02058 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
02059 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
02060 } else {
02061 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
02062 res = -1;
02063 goto exit;
02064 }
02065
02066
02067
02068 strsep(&attachedfilefmt, ".");
02069 if (!attachedfilefmt) {
02070 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
02071 res = -1;
02072 goto exit;
02073 }
02074
02075 save_body(body, vms, "2", attachedfilefmt, 0);
02076 if (save_body(body, vms, "3", attachedfilefmt, 1)) {
02077 *vms->introfn = '\0';
02078 }
02079
02080
02081 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
02082
02083 if (!(text_file_ptr = fopen(text_file, "w"))) {
02084 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
02085 }
02086
02087 fprintf(text_file_ptr, "%s\n", "[message]");
02088
02089 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf));
02090 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
02091 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf));
02092 fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
02093 get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf));
02094 fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
02095 get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf));
02096 fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
02097 get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf));
02098 fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
02099 get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf));
02100 fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
02101 get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf));
02102 fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
02103 fclose(text_file_ptr);
02104
02105 exit:
02106 free_user(vmu);
02107 return res;
02108 }
02109
02110 static int folder_int(const char *folder)
02111 {
02112
02113 if (!folder) {
02114 return 0;
02115 }
02116 if (!strcasecmp(folder, imapfolder)) {
02117 return 0;
02118 } else if (!strcasecmp(folder, "Old")) {
02119 return 1;
02120 } else if (!strcasecmp(folder, "Work")) {
02121 return 2;
02122 } else if (!strcasecmp(folder, "Family")) {
02123 return 3;
02124 } else if (!strcasecmp(folder, "Friends")) {
02125 return 4;
02126 } else if (!strcasecmp(folder, "Cust1")) {
02127 return 5;
02128 } else if (!strcasecmp(folder, "Cust2")) {
02129 return 6;
02130 } else if (!strcasecmp(folder, "Cust3")) {
02131 return 7;
02132 } else if (!strcasecmp(folder, "Cust4")) {
02133 return 8;
02134 } else if (!strcasecmp(folder, "Cust5")) {
02135 return 9;
02136 } else if (!strcasecmp(folder, "Urgent")) {
02137 return 11;
02138 } else {
02139 return 0;
02140 }
02141 }
02142
02143 static int __messagecount(const char *context, const char *mailbox, const char *folder)
02144 {
02145 SEARCHPGM *pgm;
02146 SEARCHHEADER *hdr;
02147
02148 struct ast_vm_user *vmu, vmus;
02149 struct vm_state *vms_p;
02150 int ret = 0;
02151 int fold = folder_int(folder);
02152 int urgent = 0;
02153
02154
02155 if (fold == 11) {
02156 fold = NEW_FOLDER;
02157 urgent = 1;
02158 }
02159
02160 if (ast_strlen_zero(mailbox))
02161 return 0;
02162
02163
02164 vmu = find_user(&vmus, context, mailbox);
02165 if (!vmu) {
02166 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
02167 return -1;
02168 } else {
02169
02170 if (vmu->imapuser[0] == '\0') {
02171 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02172 return -1;
02173 }
02174 }
02175
02176
02177 if (vmu->imapuser[0] == '\0') {
02178 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02179 free_user(vmu);
02180 return -1;
02181 }
02182
02183
02184 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
02185 if (!vms_p) {
02186 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
02187 }
02188 if (vms_p) {
02189 ast_debug(3, "Returning before search - user is logged in\n");
02190 if (fold == 0) {
02191 return urgent ? vms_p->urgentmessages : vms_p->newmessages;
02192 }
02193 if (fold == 1) {
02194 return vms_p->oldmessages;
02195 }
02196 }
02197
02198
02199 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
02200 if (!vms_p) {
02201 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
02202 }
02203
02204 if (!vms_p) {
02205 vms_p = create_vm_state_from_user(vmu);
02206 }
02207 ret = init_mailstream(vms_p, fold);
02208 if (!vms_p->mailstream) {
02209 ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
02210 return -1;
02211 }
02212 if (ret == 0) {
02213 ast_mutex_lock(&vms_p->lock);
02214 pgm = mail_newsearchpgm ();
02215 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
02216 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
02217 pgm->header = hdr;
02218 if (fold != OLD_FOLDER) {
02219 pgm->unseen = 1;
02220 pgm->seen = 0;
02221 }
02222
02223
02224
02225 else {
02226 pgm->unseen = 0;
02227 pgm->seen = 1;
02228 }
02229
02230 if (fold == NEW_FOLDER) {
02231 if (urgent) {
02232 pgm->flagged = 1;
02233 pgm->unflagged = 0;
02234 } else {
02235 pgm->flagged = 0;
02236 pgm->unflagged = 1;
02237 }
02238 }
02239 pgm->undeleted = 1;
02240 pgm->deleted = 0;
02241
02242 vms_p->vmArrayIndex = 0;
02243 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
02244 if (fold == 0 && urgent == 0)
02245 vms_p->newmessages = vms_p->vmArrayIndex;
02246 if (fold == 1)
02247 vms_p->oldmessages = vms_p->vmArrayIndex;
02248 if (fold == 0 && urgent == 1)
02249 vms_p->urgentmessages = vms_p->vmArrayIndex;
02250
02251 mail_free_searchpgm(&pgm);
02252 ast_mutex_unlock(&vms_p->lock);
02253 vms_p->updated = 0;
02254 return vms_p->vmArrayIndex;
02255 } else {
02256 ast_mutex_lock(&vms_p->lock);
02257 mail_ping(vms_p->mailstream);
02258 ast_mutex_unlock(&vms_p->lock);
02259 }
02260 return 0;
02261 }
02262
02263 static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
02264 {
02265
02266 check_quota(vms, vmu->imapfolder);
02267 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
02268 ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
02269 ast_play_and_wait(chan, "vm-mailboxfull");
02270 return -1;
02271 }
02272
02273
02274 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));
02275 if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
02276 ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
02277 ast_play_and_wait(chan, "vm-mailboxfull");
02278 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
02279 return -1;
02280 }
02281
02282 return 0;
02283 }
02284
02285
02286
02287
02288
02289
02290
02291
02292
02293
02294 static int messagecount(const char *context, const char *mailbox, const char *folder)
02295 {
02296 if (ast_strlen_zero(folder) || !strcmp(folder, "INBOX")) {
02297 return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
02298 } else {
02299 return __messagecount(context, mailbox, folder);
02300 }
02301 }
02302
02303 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)
02304 {
02305 char *myserveremail = serveremail;
02306 char fn[PATH_MAX];
02307 char introfn[PATH_MAX];
02308 char mailbox[256];
02309 char *stringp;
02310 FILE *p = NULL;
02311 char tmp[80] = "/tmp/astmail-XXXXXX";
02312 long len;
02313 void *buf;
02314 int tempcopy = 0;
02315 STRING str;
02316 int ret;
02317 char *imap_flags = NIL;
02318 int msgcount = (messagecount(vmu->context, vmu->mailbox, "INBOX") + messagecount(vmu->context, vmu->mailbox, "Old"));
02319 int box = NEW_FOLDER;
02320
02321
02322 if (msgnum < 0) {
02323 if(!imapgreetings) {
02324 return 0;
02325 } else {
02326 box = GREETINGS_FOLDER;
02327 }
02328 }
02329
02330 if (imap_check_limits(chan, vms, vmu, msgcount)) {
02331 return -1;
02332 }
02333
02334
02335 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
02336 ast_debug(3, "Setting message flag \\\\FLAGGED.\n");
02337 imap_flags = "\\FLAGGED";
02338 }
02339
02340
02341 fmt = ast_strdupa(fmt);
02342 stringp = fmt;
02343 strsep(&stringp, "|");
02344
02345 if (!ast_strlen_zero(vmu->serveremail))
02346 myserveremail = vmu->serveremail;
02347
02348 if (msgnum > -1)
02349 make_file(fn, sizeof(fn), dir, msgnum);
02350 else
02351 ast_copy_string (fn, dir, sizeof(fn));
02352
02353 snprintf(introfn, sizeof(introfn), "%sintro", fn);
02354 if (ast_fileexists(introfn, NULL, NULL) <= 0) {
02355 *introfn = '\0';
02356 }
02357
02358 if (ast_strlen_zero(vmu->email)) {
02359
02360
02361
02362
02363
02364 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
02365 tempcopy = 1;
02366 }
02367
02368 if (!strcmp(fmt, "wav49"))
02369 fmt = "WAV";
02370 ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
02371
02372
02373
02374 if (!(p = vm_mkftemp(tmp))) {
02375 ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
02376 if (tempcopy)
02377 *(vmu->email) = '\0';
02378 return -1;
02379 }
02380
02381 if (msgnum < 0 && imapgreetings) {
02382 if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
02383 ast_log(AST_LOG_WARNING, "Unable to open mailstream.\n");
02384 return -1;
02385 }
02386 imap_delete_old_greeting(fn, vms);
02387 }
02388
02389 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX",
02390 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
02391 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
02392 fn, introfn, fmt, duration, 1, chan, NULL, 1, flag);
02393
02394 len = ftell(p);
02395 rewind(p);
02396 if (!(buf = ast_malloc(len + 1))) {
02397 ast_log(AST_LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
02398 fclose(p);
02399 if (tempcopy)
02400 *(vmu->email) = '\0';
02401 return -1;
02402 }
02403 if (fread(buf, len, 1, p) < len) {
02404 if (ferror(p)) {
02405 ast_log(LOG_ERROR, "Short read while reading in mail file.\n");
02406 return -1;
02407 }
02408 }
02409 ((char *) buf)[len] = '\0';
02410 INIT(&str, mail_string, buf, len);
02411 ret = init_mailstream(vms, box);
02412 if (ret == 0) {
02413 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
02414 ast_mutex_lock(&vms->lock);
02415 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
02416 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
02417 ast_mutex_unlock(&vms->lock);
02418 fclose(p);
02419 unlink(tmp);
02420 ast_free(buf);
02421 } else {
02422 ast_log(LOG_ERROR, "Could not initialize mailstream for %s\n", mailbox);
02423 fclose(p);
02424 unlink(tmp);
02425 ast_free(buf);
02426 return -1;
02427 }
02428 ast_debug(3, "%s stored\n", fn);
02429
02430 if (tempcopy)
02431 *(vmu->email) = '\0';
02432 inprocess_count(vmu->mailbox, vmu->context, -1);
02433 return 0;
02434
02435 }
02436
02437
02438
02439
02440
02441
02442
02443
02444
02445
02446
02447
02448
02449
02450 static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
02451 {
02452 char tmp[PATH_MAX] = "";
02453 char *mailboxnc;
02454 char *context;
02455 char *mb;
02456 char *cur;
02457 if (newmsgs)
02458 *newmsgs = 0;
02459 if (oldmsgs)
02460 *oldmsgs = 0;
02461 if (urgentmsgs)
02462 *urgentmsgs = 0;
02463
02464 ast_debug(3, "Mailbox is set to %s\n", mailbox_context);
02465
02466 if (ast_strlen_zero(mailbox_context))
02467 return 0;
02468
02469 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02470 context = strchr(tmp, '@');
02471 if (strchr(mailbox_context, ',')) {
02472 int tmpnew, tmpold, tmpurgent;
02473 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02474 mb = tmp;
02475 while ((cur = strsep(&mb, ", "))) {
02476 if (!ast_strlen_zero(cur)) {
02477 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
02478 return -1;
02479 else {
02480 if (newmsgs)
02481 *newmsgs += tmpnew;
02482 if (oldmsgs)
02483 *oldmsgs += tmpold;
02484 if (urgentmsgs)
02485 *urgentmsgs += tmpurgent;
02486 }
02487 }
02488 }
02489 return 0;
02490 }
02491 if (context) {
02492 *context = '\0';
02493 mailboxnc = tmp;
02494 context++;
02495 } else {
02496 context = "default";
02497 mailboxnc = (char *) mailbox_context;
02498 }
02499
02500 if (newmsgs) {
02501 struct ast_vm_user *vmu = find_user(NULL, context, mailboxnc);
02502 if (!vmu) {
02503 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailboxnc, context);
02504 return -1;
02505 }
02506 if ((*newmsgs = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
02507 return -1;
02508 }
02509 }
02510 if (oldmsgs) {
02511 if ((*oldmsgs = __messagecount(context, mailboxnc, "Old")) < 0) {
02512 return -1;
02513 }
02514 }
02515 if (urgentmsgs) {
02516 if ((*urgentmsgs = __messagecount(context, mailboxnc, "Urgent")) < 0) {
02517 return -1;
02518 }
02519 }
02520 return 0;
02521 }
02522
02523
02524
02525
02526
02527
02528
02529
02530
02531
02532
02533 static int has_voicemail(const char *mailbox, const char *folder)
02534 {
02535 char tmp[256], *tmp2, *box, *context;
02536 ast_copy_string(tmp, mailbox, sizeof(tmp));
02537 tmp2 = tmp;
02538 if (strchr(tmp2, ',') || strchr(tmp2, '&')) {
02539 while ((box = strsep(&tmp2, ",&"))) {
02540 if (!ast_strlen_zero(box)) {
02541 if (has_voicemail(box, folder)) {
02542 return 1;
02543 }
02544 }
02545 }
02546 }
02547 if ((context = strchr(tmp, '@'))) {
02548 *context++ = '\0';
02549 } else {
02550 context = "default";
02551 }
02552 return __messagecount(context, tmp, folder) ? 1 : 0;
02553 }
02554
02555
02556
02557
02558
02559
02560
02561
02562
02563
02564
02565
02566
02567
02568
02569
02570 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)
02571 {
02572 struct vm_state *sendvms = NULL;
02573 char messagestring[10];
02574 if (msgnum >= recip->maxmsg) {
02575 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
02576 return -1;
02577 }
02578 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
02579 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
02580 return -1;
02581 }
02582 if (!get_vm_state_by_imapuser(recip->imapuser, 0)) {
02583 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
02584 return -1;
02585 }
02586 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
02587 ast_mutex_lock(&sendvms->lock);
02588 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(vmu, imbox)) == T)) {
02589 ast_mutex_unlock(&sendvms->lock);
02590 return 0;
02591 }
02592 ast_mutex_unlock(&sendvms->lock);
02593 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
02594 return -1;
02595 }
02596
02597 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
02598 {
02599 char tmp[256], *t = tmp;
02600 size_t left = sizeof(tmp);
02601
02602 if (box == OLD_FOLDER) {
02603 ast_copy_string(vms->curbox, mbox(NULL, NEW_FOLDER), sizeof(vms->curbox));
02604 } else {
02605 ast_copy_string(vms->curbox, mbox(NULL, box), sizeof(vms->curbox));
02606 }
02607
02608 if (box == NEW_FOLDER) {
02609 ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
02610 } else {
02611 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(NULL, box));
02612 }
02613
02614
02615 ast_build_string(&t, &left, "{%s:%s/imap", S_OR(vms->imapserver, imapserver), S_OR(vms->imapport, imapport));
02616
02617
02618 if (!ast_strlen_zero(authuser))
02619 ast_build_string(&t, &left, "/authuser=%s", authuser);
02620
02621
02622 if (!ast_strlen_zero(imapflags) || !(ast_strlen_zero(vms->imapflags))) {
02623 ast_build_string(&t, &left, "/%s", S_OR(vms->imapflags, imapflags));
02624 }
02625
02626
02627 #if 1
02628 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
02629 #else
02630 ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
02631 #endif
02632 if (box == NEW_FOLDER || box == OLD_FOLDER)
02633 snprintf(spec, len, "%s%s", tmp, use_folder? vms->imapfolder: "INBOX");
02634 else if (box == GREETINGS_FOLDER)
02635 snprintf(spec, len, "%s%s", tmp, greetingfolder);
02636 else {
02637 if (!ast_strlen_zero(imapparentfolder)) {
02638
02639 snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(NULL, box));
02640 } else {
02641 snprintf(spec, len, "%s%s", tmp, mbox(NULL, box));
02642 }
02643 }
02644 }
02645
02646 static int init_mailstream(struct vm_state *vms, int box)
02647 {
02648 MAILSTREAM *stream = NIL;
02649 long debug;
02650 char tmp[256];
02651
02652 if (!vms) {
02653 ast_log(LOG_ERROR, "vm_state is NULL!\n");
02654 return -1;
02655 }
02656 ast_debug(3, "vm_state user is:%s\n", vms->imapuser);
02657 if (vms->mailstream == NIL || !vms->mailstream) {
02658 ast_debug(1, "mailstream not set.\n");
02659 } else {
02660 stream = vms->mailstream;
02661 }
02662
02663 debug = NIL;
02664
02665 if (delimiter == '\0') {
02666 char *cp;
02667 #ifdef USE_SYSTEM_IMAP
02668 #include <imap/linkage.c>
02669 #elif defined(USE_SYSTEM_CCLIENT)
02670 #include <c-client/linkage.c>
02671 #else
02672 #include "linkage.c"
02673 #endif
02674
02675 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
02676 ast_mutex_lock(&vms->lock);
02677 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02678 ast_mutex_unlock(&vms->lock);
02679 if (stream == NIL) {
02680 ast_log(LOG_ERROR, "Can't connect to imap server %s\n", tmp);
02681 return -1;
02682 }
02683 get_mailbox_delimiter(vms, stream);
02684
02685 for (cp = vms->imapfolder; *cp; cp++)
02686 if (*cp == '/')
02687 *cp = delimiter;
02688 }
02689
02690 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
02691 ast_debug(3, "Before mail_open, server: %s, box:%d\n", tmp, box);
02692 ast_mutex_lock(&vms->lock);
02693 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02694 ast_mutex_unlock(&vms->lock);
02695 if (vms->mailstream == NIL) {
02696 return -1;
02697 } else {
02698 return 0;
02699 }
02700 }
02701
02702 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
02703 {
02704 SEARCHPGM *pgm;
02705 SEARCHHEADER *hdr;
02706 int urgent = 0;
02707
02708
02709 if (box == 11) {
02710 box = NEW_FOLDER;
02711 urgent = 1;
02712 }
02713
02714 ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser));
02715 ast_copy_string(vms->imapfolder, vmu->imapfolder, sizeof(vms->imapfolder));
02716 ast_copy_string(vms->imapserver, vmu->imapserver, sizeof(vms->imapserver));
02717 ast_copy_string(vms->imapport, vmu->imapport, sizeof(vms->imapport));
02718 ast_copy_string(vms->imapflags, vmu->imapflags, sizeof(vms->imapflags));
02719 vms->imapversion = vmu->imapversion;
02720 ast_debug(3, "Before init_mailstream, user is %s\n", vmu->imapuser);
02721
02722 if (init_mailstream(vms, box) || !vms->mailstream) {
02723 ast_log(AST_LOG_ERROR, "Could not initialize mailstream\n");
02724 return -1;
02725 }
02726
02727 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
02728
02729
02730 if (box == 0) {
02731 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(vmu, box));
02732 check_quota(vms, (char *) mbox(vmu, box));
02733 }
02734
02735 ast_mutex_lock(&vms->lock);
02736 pgm = mail_newsearchpgm();
02737
02738
02739 hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
02740 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
02741 pgm->header = hdr;
02742 pgm->deleted = 0;
02743 pgm->undeleted = 1;
02744
02745
02746 if (box == NEW_FOLDER && urgent == 1) {
02747 pgm->unseen = 1;
02748 pgm->seen = 0;
02749 pgm->flagged = 1;
02750 pgm->unflagged = 0;
02751 } else if (box == NEW_FOLDER && urgent == 0) {
02752 pgm->unseen = 1;
02753 pgm->seen = 0;
02754 pgm->flagged = 0;
02755 pgm->unflagged = 1;
02756 } else if (box == OLD_FOLDER) {
02757 pgm->seen = 1;
02758 pgm->unseen = 0;
02759 }
02760
02761 ast_debug(3, "Before mail_search_full, user is %s\n", vmu->imapuser);
02762
02763 vms->vmArrayIndex = 0;
02764 mail_search_full (vms->mailstream, NULL, pgm, NIL);
02765 vms->lastmsg = vms->vmArrayIndex - 1;
02766 mail_free_searchpgm(&pgm);
02767
02768
02769
02770
02771 if (box == 0 && !vms->dh_arraysize) {
02772 ast_log(LOG_WARNING, "The code expects the old messages to be checked first, fix the code.\n");
02773 }
02774 if (vm_allocate_dh(vms, vmu, box == 0 ? vms->vmArrayIndex + vms->oldmessages : vms->lastmsg)) {
02775 ast_mutex_unlock(&vms->lock);
02776 return -1;
02777 }
02778
02779 ast_mutex_unlock(&vms->lock);
02780 return 0;
02781 }
02782
02783 static void write_file(char *filename, char *buffer, unsigned long len)
02784 {
02785 FILE *output;
02786
02787 output = fopen (filename, "w");
02788 if (fwrite(buffer, len, 1, output) != 1) {
02789 if (ferror(output)) {
02790 ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno));
02791 }
02792 }
02793 fclose (output);
02794 }
02795
02796 static void update_messages_by_imapuser(const char *user, unsigned long number)
02797 {
02798 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
02799
02800 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
02801 return;
02802 }
02803
02804 ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
02805 vms->msgArray[vms->vmArrayIndex++] = number;
02806 }
02807
02808 void mm_searched(MAILSTREAM *stream, unsigned long number)
02809 {
02810 char *mailbox = stream->mailbox, buf[1024] = "", *user;
02811
02812 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
02813 return;
02814
02815 update_messages_by_imapuser(user, number);
02816 }
02817
02818 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
02819 {
02820 struct ast_variable *var;
02821 struct ast_vm_user *vmu;
02822
02823 vmu = ast_calloc(1, sizeof *vmu);
02824 if (!vmu)
02825 return NULL;
02826 ast_set_flag(vmu, VM_ALLOCED);
02827 populate_defaults(vmu);
02828
02829 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
02830 if (var) {
02831 apply_options_full(vmu, var);
02832 ast_variables_destroy(var);
02833 return vmu;
02834 } else {
02835 ast_free(vmu);
02836 return NULL;
02837 }
02838 }
02839
02840
02841
02842 void mm_exists(MAILSTREAM * stream, unsigned long number)
02843 {
02844
02845 ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
02846 if (number == 0) return;
02847 set_update(stream);
02848 }
02849
02850
02851 void mm_expunged(MAILSTREAM * stream, unsigned long number)
02852 {
02853
02854 ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
02855 if (number == 0) return;
02856 set_update(stream);
02857 }
02858
02859
02860 void mm_flags(MAILSTREAM * stream, unsigned long number)
02861 {
02862
02863 ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
02864 if (number == 0) return;
02865 set_update(stream);
02866 }
02867
02868
02869 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
02870 {
02871 ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string);
02872 mm_log (string, errflg);
02873 }
02874
02875
02876 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02877 {
02878 if (delimiter == '\0') {
02879 delimiter = delim;
02880 }
02881
02882 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02883 if (attributes & LATT_NOINFERIORS)
02884 ast_debug(5, "no inferiors\n");
02885 if (attributes & LATT_NOSELECT)
02886 ast_debug(5, "no select\n");
02887 if (attributes & LATT_MARKED)
02888 ast_debug(5, "marked\n");
02889 if (attributes & LATT_UNMARKED)
02890 ast_debug(5, "unmarked\n");
02891 }
02892
02893
02894 void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02895 {
02896 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02897 if (attributes & LATT_NOINFERIORS)
02898 ast_debug(5, "no inferiors\n");
02899 if (attributes & LATT_NOSELECT)
02900 ast_debug(5, "no select\n");
02901 if (attributes & LATT_MARKED)
02902 ast_debug(5, "marked\n");
02903 if (attributes & LATT_UNMARKED)
02904 ast_debug(5, "unmarked\n");
02905 }
02906
02907
02908 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
02909 {
02910 ast_log(AST_LOG_NOTICE, " Mailbox %s", mailbox);
02911 if (status->flags & SA_MESSAGES)
02912 ast_log(AST_LOG_NOTICE, ", %lu messages", status->messages);
02913 if (status->flags & SA_RECENT)
02914 ast_log(AST_LOG_NOTICE, ", %lu recent", status->recent);
02915 if (status->flags & SA_UNSEEN)
02916 ast_log(AST_LOG_NOTICE, ", %lu unseen", status->unseen);
02917 if (status->flags & SA_UIDVALIDITY)
02918 ast_log(AST_LOG_NOTICE, ", %lu UID validity", status->uidvalidity);
02919 if (status->flags & SA_UIDNEXT)
02920 ast_log(AST_LOG_NOTICE, ", %lu next UID", status->uidnext);
02921 ast_log(AST_LOG_NOTICE, "\n");
02922 }
02923
02924
02925 void mm_log(char *string, long errflg)
02926 {
02927 switch ((short) errflg) {
02928 case NIL:
02929 ast_debug(1, "IMAP Info: %s\n", string);
02930 break;
02931 case PARSE:
02932 case WARN:
02933 ast_log(AST_LOG_WARNING, "IMAP Warning: %s\n", string);
02934 break;
02935 case ERROR:
02936 ast_log(AST_LOG_ERROR, "IMAP Error: %s\n", string);
02937 break;
02938 }
02939 }
02940
02941
02942 void mm_dlog(char *string)
02943 {
02944 ast_log(AST_LOG_NOTICE, "%s\n", string);
02945 }
02946
02947
02948 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
02949 {
02950 struct ast_vm_user *vmu;
02951
02952 ast_debug(4, "Entering callback mm_login\n");
02953
02954 ast_copy_string(user, mb->user, MAILTMPLEN);
02955
02956
02957 if (!ast_strlen_zero(authpassword)) {
02958 ast_copy_string(pwd, authpassword, MAILTMPLEN);
02959 } else {
02960 AST_LIST_TRAVERSE(&users, vmu, list) {
02961 if (!strcasecmp(mb->user, vmu->imapuser)) {
02962 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02963 break;
02964 }
02965 }
02966 if (!vmu) {
02967 if ((vmu = find_user_realtime_imapuser(mb->user))) {
02968 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02969 free_user(vmu);
02970 }
02971 }
02972 }
02973 }
02974
02975
02976 void mm_critical(MAILSTREAM * stream)
02977 {
02978 }
02979
02980
02981 void mm_nocritical(MAILSTREAM * stream)
02982 {
02983 }
02984
02985
02986 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
02987 {
02988 kill (getpid (), SIGSTOP);
02989 return NIL;
02990 }
02991
02992
02993 void mm_fatal(char *string)
02994 {
02995 ast_log(AST_LOG_ERROR, "IMAP access FATAL error: %s\n", string);
02996 }
02997
02998
02999 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
03000 {
03001 struct vm_state *vms;
03002 char *mailbox = stream->mailbox, *user;
03003 char buf[1024] = "";
03004 unsigned long usage = 0, limit = 0;
03005
03006 while (pquota) {
03007 usage = pquota->usage;
03008 limit = pquota->limit;
03009 pquota = pquota->next;
03010 }
03011
03012 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)))) {
03013 ast_log(AST_LOG_ERROR, "No state found.\n");
03014 return;
03015 }
03016
03017 ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
03018
03019 vms->quota_usage = usage;
03020 vms->quota_limit = limit;
03021 }
03022
03023 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
03024 {
03025 char *start, *eol_pnt;
03026 int taglen;
03027
03028 if (ast_strlen_zero(header) || ast_strlen_zero(tag))
03029 return NULL;
03030
03031 taglen = strlen(tag) + 1;
03032 if (taglen < 1)
03033 return NULL;
03034
03035 if (!(start = strstr(header, tag)))
03036 return NULL;
03037
03038
03039 memset(buf, 0, len);
03040
03041 ast_copy_string(buf, start+taglen, len);
03042 if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n')))
03043 *eol_pnt = '\0';
03044 return buf;
03045 }
03046
03047 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
03048 {
03049 char *start, *eol_pnt, *quote;
03050
03051 if (ast_strlen_zero(mailbox))
03052 return NULL;
03053
03054 if (!(start = strstr(mailbox, "/user=")))
03055 return NULL;
03056
03057 ast_copy_string(buf, start+6, len);
03058
03059 if (!(quote = strchr(buf, '"'))) {
03060 if ((eol_pnt = strchr(buf, '/')) || (eol_pnt = strchr(buf, '}'))) {
03061 *eol_pnt = '\0';
03062 }
03063 return buf;
03064 } else {
03065 if ((eol_pnt = strchr(quote + 1, '"'))) {
03066 *eol_pnt = '\0';
03067 }
03068 return quote + 1;
03069 }
03070 }
03071
03072 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
03073 {
03074 struct vm_state *vms_p;
03075
03076 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03077 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
03078 return vms_p;
03079 }
03080 ast_debug(5, "Adding new vmstate for %s\n", vmu->imapuser);
03081 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
03082 return NULL;
03083 ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
03084 ast_copy_string(vms_p->imapfolder, vmu->imapfolder, sizeof(vms_p->imapfolder));
03085 ast_copy_string(vms_p->imapserver, vmu->imapserver, sizeof(vms_p->imapserver));
03086 ast_copy_string(vms_p->imapport, vmu->imapport, sizeof(vms_p->imapport));
03087 ast_copy_string(vms_p->imapflags, vmu->imapflags, sizeof(vms_p->imapflags));
03088 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
03089 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
03090 vms_p->mailstream = NIL;
03091 vms_p->imapversion = vmu->imapversion;
03092 ast_debug(5, "Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
03093 vms_p->updated = 1;
03094
03095 ast_copy_string(vms_p->curbox, mbox(vmu, 0), sizeof(vms_p->curbox));
03096 init_vm_state(vms_p);
03097 vmstate_insert(vms_p);
03098 return vms_p;
03099 }
03100
03101 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
03102 {
03103 struct vmstate *vlist = NULL;
03104
03105 if (interactive) {
03106 struct vm_state *vms;
03107 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03108 vms = pthread_getspecific(ts_vmstate.key);
03109 return vms;
03110 }
03111
03112 AST_LIST_LOCK(&vmstates);
03113 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03114 if (!vlist->vms) {
03115 ast_debug(3, "error: vms is NULL for %s\n", user);
03116 continue;
03117 }
03118 if (vlist->vms->imapversion != imapversion) {
03119 continue;
03120 }
03121 if (!vlist->vms->imapuser) {
03122 ast_debug(3, "error: imapuser is NULL for %s\n", user);
03123 continue;
03124 }
03125
03126 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
03127 AST_LIST_UNLOCK(&vmstates);
03128 return vlist->vms;
03129 }
03130 }
03131 AST_LIST_UNLOCK(&vmstates);
03132
03133 ast_debug(3, "%s not found in vmstates\n", user);
03134
03135 return NULL;
03136 }
03137
03138 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
03139 {
03140
03141 struct vmstate *vlist = NULL;
03142 const char *local_context = S_OR(context, "default");
03143
03144 if (interactive) {
03145 struct vm_state *vms;
03146 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03147 vms = pthread_getspecific(ts_vmstate.key);
03148 return vms;
03149 }
03150
03151 AST_LIST_LOCK(&vmstates);
03152 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03153 if (!vlist->vms) {
03154 ast_debug(3, "error: vms is NULL for %s\n", mailbox);
03155 continue;
03156 }
03157 if (vlist->vms->imapversion != imapversion) {
03158 continue;
03159 }
03160 if (!vlist->vms->username || !vlist->vms->context) {
03161 ast_debug(3, "error: username is NULL for %s\n", mailbox);
03162 continue;
03163 }
03164
03165 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);
03166
03167 if (!strcmp(vlist->vms->username, mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
03168 ast_debug(3, "Found it!\n");
03169 AST_LIST_UNLOCK(&vmstates);
03170 return vlist->vms;
03171 }
03172 }
03173 AST_LIST_UNLOCK(&vmstates);
03174
03175 ast_debug(3, "%s not found in vmstates\n", mailbox);
03176
03177 return NULL;
03178 }
03179
03180 static void vmstate_insert(struct vm_state *vms)
03181 {
03182 struct vmstate *v;
03183 struct vm_state *altvms;
03184
03185
03186
03187
03188 if (vms->interactive == 1) {
03189 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
03190 if (altvms) {
03191 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03192 vms->newmessages = altvms->newmessages;
03193 vms->oldmessages = altvms->oldmessages;
03194 vms->vmArrayIndex = altvms->vmArrayIndex;
03195 vms->lastmsg = altvms->lastmsg;
03196 vms->curmsg = altvms->curmsg;
03197
03198 vms->persist_vms = altvms;
03199
03200 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
03201 vms->mailstream = altvms->mailstream;
03202 #else
03203 vms->mailstream = NIL;
03204 #endif
03205 }
03206 return;
03207 }
03208
03209 if (!(v = ast_calloc(1, sizeof(*v))))
03210 return;
03211
03212 v->vms = vms;
03213
03214 ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03215
03216 AST_LIST_LOCK(&vmstates);
03217 AST_LIST_INSERT_TAIL(&vmstates, v, list);
03218 AST_LIST_UNLOCK(&vmstates);
03219 }
03220
03221 static void vmstate_delete(struct vm_state *vms)
03222 {
03223 struct vmstate *vc = NULL;
03224 struct vm_state *altvms = NULL;
03225
03226
03227
03228 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
03229 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03230 altvms->newmessages = vms->newmessages;
03231 altvms->oldmessages = vms->oldmessages;
03232 altvms->updated = 1;
03233 vms->mailstream = mail_close(vms->mailstream);
03234
03235
03236 return;
03237 }
03238
03239 ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03240
03241 AST_LIST_LOCK(&vmstates);
03242 AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
03243 if (vc->vms == vms) {
03244 AST_LIST_REMOVE_CURRENT(list);
03245 break;
03246 }
03247 }
03248 AST_LIST_TRAVERSE_SAFE_END
03249 AST_LIST_UNLOCK(&vmstates);
03250
03251 if (vc) {
03252 ast_mutex_destroy(&vc->vms->lock);
03253 ast_free(vc);
03254 }
03255 else
03256 ast_log(AST_LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03257 }
03258
03259 static void set_update(MAILSTREAM * stream)
03260 {
03261 struct vm_state *vms;
03262 char *mailbox = stream->mailbox, *user;
03263 char buf[1024] = "";
03264
03265 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
03266 if (user && option_debug > 2)
03267 ast_log(AST_LOG_WARNING, "User %s mailbox not found for update.\n", user);
03268 return;
03269 }
03270
03271 ast_debug(3, "User %s mailbox set for update.\n", user);
03272
03273 vms->updated = 1;
03274 }
03275
03276 static void init_vm_state(struct vm_state *vms)
03277 {
03278 int x;
03279 vms->vmArrayIndex = 0;
03280 for (x = 0; x < VMSTATE_MAX_MSG_ARRAY; x++) {
03281 vms->msgArray[x] = 0;
03282 }
03283 ast_mutex_init(&vms->lock);
03284 }
03285
03286 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro)
03287 {
03288 char *body_content;
03289 char *body_decoded;
03290 char *fn = is_intro ? vms->introfn : vms->fn;
03291 unsigned long len;
03292 unsigned long newlen;
03293 char filename[256];
03294
03295 if (!body || body == NIL)
03296 return -1;
03297
03298 ast_mutex_lock(&vms->lock);
03299 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
03300 ast_mutex_unlock(&vms->lock);
03301 if (body_content != NIL) {
03302 snprintf(filename, sizeof(filename), "%s.%s", fn, format);
03303
03304 body_decoded = rfc822_base64((unsigned char *) body_content, len, &newlen);
03305
03306 if (!newlen) {
03307 return -1;
03308 }
03309 write_file(filename, (char *) body_decoded, newlen);
03310 } else {
03311 ast_debug(5, "Body of message is NULL.\n");
03312 return -1;
03313 }
03314 return 0;
03315 }
03316
03317
03318
03319
03320
03321
03322
03323
03324
03325 static void get_mailbox_delimiter(struct vm_state *vms, MAILSTREAM *stream) {
03326 char tmp[50];
03327 snprintf(tmp, sizeof(tmp), "{%s}", S_OR(vms->imapserver, imapserver));
03328 mail_list(stream, tmp, "*");
03329 }
03330
03331
03332
03333
03334
03335
03336
03337
03338 static void check_quota(struct vm_state *vms, char *mailbox) {
03339 ast_mutex_lock(&vms->lock);
03340 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
03341 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox);
03342 if (vms && vms->mailstream != NULL) {
03343 imap_getquotaroot(vms->mailstream, mailbox);
03344 } else {
03345 ast_log(AST_LOG_WARNING, "Mailstream not available for mailbox: %s\n", mailbox);
03346 }
03347 ast_mutex_unlock(&vms->lock);
03348 }
03349
03350 #endif
03351
03352
03353
03354
03355
03356 static int vm_lock_path(const char *path)
03357 {
03358 switch (ast_lock_path(path)) {
03359 case AST_LOCK_TIMEOUT:
03360 return -1;
03361 default:
03362 return 0;
03363 }
03364 }
03365
03366
03367 #ifdef ODBC_STORAGE
03368 struct generic_prepare_struct {
03369 char *sql;
03370 int argc;
03371 char **argv;
03372 };
03373
03374 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
03375 {
03376 struct generic_prepare_struct *gps = data;
03377 int res, i;
03378 SQLHSTMT stmt;
03379
03380 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03381 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03382 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03383 return NULL;
03384 }
03385 res = SQLPrepare(stmt, (unsigned char *) gps->sql, SQL_NTS);
03386 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03387 ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
03388 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03389 return NULL;
03390 }
03391 for (i = 0; i < gps->argc; i++)
03392 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
03393
03394 return stmt;
03395 }
03396
03397
03398
03399
03400
03401
03402
03403
03404
03405
03406
03407
03408
03409
03410
03411 static int retrieve_file(char *dir, int msgnum)
03412 {
03413 int x = 0;
03414 int res;
03415 int fd = -1;
03416 size_t fdlen = 0;
03417 void *fdm = MAP_FAILED;
03418 SQLSMALLINT colcount = 0;
03419 SQLHSTMT stmt;
03420 char sql[PATH_MAX];
03421 char fmt[80]="";
03422 char *c;
03423 char coltitle[256];
03424 SQLSMALLINT collen;
03425 SQLSMALLINT datatype;
03426 SQLSMALLINT decimaldigits;
03427 SQLSMALLINT nullable;
03428 SQLULEN colsize;
03429 SQLLEN colsize2;
03430 FILE *f = NULL;
03431 char rowdata[80];
03432 char fn[PATH_MAX];
03433 char full_fn[PATH_MAX];
03434 char msgnums[80];
03435 char *argv[] = { dir, msgnums };
03436 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03437
03438 struct odbc_obj *obj;
03439 obj = ast_odbc_request_obj(odbc_database, 0);
03440 if (obj) {
03441 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03442 c = strchr(fmt, '|');
03443 if (c)
03444 *c = '\0';
03445 if (!strcasecmp(fmt, "wav49"))
03446 strcpy(fmt, "WAV");
03447 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03448 if (msgnum > -1)
03449 make_file(fn, sizeof(fn), dir, msgnum);
03450 else
03451 ast_copy_string(fn, dir, sizeof(fn));
03452
03453
03454 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03455
03456 if (!(f = fopen(full_fn, "w+"))) {
03457 ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
03458 goto yuck;
03459 }
03460
03461 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03462 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03463 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03464 if (!stmt) {
03465 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03466 ast_odbc_release_obj(obj);
03467 goto yuck;
03468 }
03469 res = SQLFetch(stmt);
03470 if (res == SQL_NO_DATA) {
03471 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03472 ast_odbc_release_obj(obj);
03473 goto yuck;
03474 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03475 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03476 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03477 ast_odbc_release_obj(obj);
03478 goto yuck;
03479 }
03480 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
03481 if (fd < 0) {
03482 ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
03483 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03484 ast_odbc_release_obj(obj);
03485 goto yuck;
03486 }
03487 res = SQLNumResultCols(stmt, &colcount);
03488 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03489 ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
03490 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03491 ast_odbc_release_obj(obj);
03492 goto yuck;
03493 }
03494 if (f)
03495 fprintf(f, "[message]\n");
03496 for (x = 0; x < colcount; x++) {
03497 rowdata[0] = '\0';
03498 colsize = 0;
03499 collen = sizeof(coltitle);
03500 res = SQLDescribeCol(stmt, x + 1, (unsigned char *) coltitle, sizeof(coltitle), &collen,
03501 &datatype, &colsize, &decimaldigits, &nullable);
03502 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03503 ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
03504 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03505 ast_odbc_release_obj(obj);
03506 goto yuck;
03507 }
03508 if (!strcasecmp(coltitle, "recording")) {
03509 off_t offset;
03510 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
03511 fdlen = colsize2;
03512 if (fd > -1) {
03513 char tmp[1]="";
03514 lseek(fd, fdlen - 1, SEEK_SET);
03515 if (write(fd, tmp, 1) != 1) {
03516 close(fd);
03517 fd = -1;
03518 continue;
03519 }
03520
03521 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
03522 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
03523 ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
03524 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03525 ast_odbc_release_obj(obj);
03526 goto yuck;
03527 } else {
03528 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
03529 munmap(fdm, CHUNKSIZE);
03530 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03531 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03532 unlink(full_fn);
03533 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03534 ast_odbc_release_obj(obj);
03535 goto yuck;
03536 }
03537 }
03538 }
03539 if (truncate(full_fn, fdlen) < 0) {
03540 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
03541 }
03542 }
03543 } else {
03544 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03545 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03546 ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
03547 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03548 ast_odbc_release_obj(obj);
03549 goto yuck;
03550 }
03551 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
03552 fprintf(f, "%s=%s\n", coltitle, rowdata);
03553 }
03554 }
03555 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03556 ast_odbc_release_obj(obj);
03557 } else
03558 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03559 yuck:
03560 if (f)
03561 fclose(f);
03562 if (fd > -1)
03563 close(fd);
03564 return x - 1;
03565 }
03566
03567
03568
03569
03570
03571
03572
03573
03574
03575
03576
03577
03578 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03579 {
03580 int x = 0;
03581 int res;
03582 SQLHSTMT stmt;
03583 char sql[PATH_MAX];
03584 char rowdata[20];
03585 char *argv[] = { dir };
03586 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03587
03588 struct odbc_obj *obj;
03589 obj = ast_odbc_request_obj(odbc_database, 0);
03590 if (obj) {
03591 snprintf(sql, sizeof(sql), "SELECT msgnum FROM %s WHERE dir=? order by msgnum desc", odbc_table);
03592
03593 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03594 if (!stmt) {
03595 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03596 ast_odbc_release_obj(obj);
03597 goto yuck;
03598 }
03599 res = SQLFetch(stmt);
03600 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03601 if (res == SQL_NO_DATA) {
03602 ast_log(AST_LOG_DEBUG, "Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
03603 } else {
03604 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03605 }
03606
03607 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03608 ast_odbc_release_obj(obj);
03609 goto yuck;
03610 }
03611 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03612 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03613 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03614 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03615 ast_odbc_release_obj(obj);
03616 goto yuck;
03617 }
03618 if (sscanf(rowdata, "%30d", &x) != 1)
03619 ast_log(AST_LOG_WARNING, "Failed to read message index!\n");
03620 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03621 ast_odbc_release_obj(obj);
03622 return x;
03623 } else
03624 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03625 yuck:
03626 return x - 1;
03627 }
03628
03629
03630
03631
03632
03633
03634
03635
03636
03637
03638 static int message_exists(char *dir, int msgnum)
03639 {
03640 int x = 0;
03641 int res;
03642 SQLHSTMT stmt;
03643 char sql[PATH_MAX];
03644 char rowdata[20];
03645 char msgnums[20];
03646 char *argv[] = { dir, msgnums };
03647 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03648
03649 struct odbc_obj *obj;
03650 obj = ast_odbc_request_obj(odbc_database, 0);
03651 if (obj) {
03652 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03653 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03654 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03655 if (!stmt) {
03656 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03657 ast_odbc_release_obj(obj);
03658 goto yuck;
03659 }
03660 res = SQLFetch(stmt);
03661 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03662 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03663 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03664 ast_odbc_release_obj(obj);
03665 goto yuck;
03666 }
03667 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03668 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03669 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03670 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03671 ast_odbc_release_obj(obj);
03672 goto yuck;
03673 }
03674 if (sscanf(rowdata, "%30d", &x) != 1)
03675 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03676 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03677 ast_odbc_release_obj(obj);
03678 } else
03679 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03680 yuck:
03681 return x;
03682 }
03683
03684
03685
03686
03687
03688
03689
03690
03691
03692
03693 static int count_messages(struct ast_vm_user *vmu, char *dir)
03694 {
03695 int x = 0;
03696 int res;
03697 SQLHSTMT stmt;
03698 char sql[PATH_MAX];
03699 char rowdata[20];
03700 char *argv[] = { dir };
03701 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03702
03703 struct odbc_obj *obj;
03704 obj = ast_odbc_request_obj(odbc_database, 0);
03705 if (obj) {
03706 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
03707 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03708 if (!stmt) {
03709 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03710 ast_odbc_release_obj(obj);
03711 goto yuck;
03712 }
03713 res = SQLFetch(stmt);
03714 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03715 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03716 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03717 ast_odbc_release_obj(obj);
03718 goto yuck;
03719 }
03720 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03721 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03722 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03723 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03724 ast_odbc_release_obj(obj);
03725 goto yuck;
03726 }
03727 if (sscanf(rowdata, "%30d", &x) != 1)
03728 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03729 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03730 ast_odbc_release_obj(obj);
03731 return x;
03732 } else
03733 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03734 yuck:
03735 return x - 1;
03736
03737 }
03738
03739
03740
03741
03742
03743
03744
03745
03746
03747
03748
03749 static void delete_file(const char *sdir, int smsg)
03750 {
03751 SQLHSTMT stmt;
03752 char sql[PATH_MAX];
03753 char msgnums[20];
03754 char *argv[] = { NULL, msgnums };
03755 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03756 struct odbc_obj *obj;
03757
03758 argv[0] = ast_strdupa(sdir);
03759
03760 obj = ast_odbc_request_obj(odbc_database, 0);
03761 if (obj) {
03762 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03763 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03764 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03765 if (!stmt)
03766 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03767 else
03768 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03769 ast_odbc_release_obj(obj);
03770 } else
03771 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03772 return;
03773 }
03774
03775
03776
03777
03778
03779
03780
03781
03782
03783
03784
03785
03786 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
03787 {
03788 SQLHSTMT stmt;
03789 char sql[512];
03790 char msgnums[20];
03791 char msgnumd[20];
03792 struct odbc_obj *obj;
03793 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
03794 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03795
03796 delete_file(ddir, dmsg);
03797 obj = ast_odbc_request_obj(odbc_database, 0);
03798 if (obj) {
03799 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03800 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03801 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir, msgnum, context, macrocontext, callerid, origtime, duration, recording, flag, mailboxuser, mailboxcontext) SELECT ?,?,context,macrocontext,callerid,origtime,duration,recording,flag,?,? FROM %s WHERE dir=? AND msgnum=?", odbc_table, odbc_table);
03802 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03803 if (!stmt)
03804 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
03805 else
03806 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03807 ast_odbc_release_obj(obj);
03808 } else
03809 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03810 return;
03811 }
03812
03813 struct insert_data {
03814 char *sql;
03815 const char *dir;
03816 const char *msgnums;
03817 void *data;
03818 SQLLEN datalen;
03819 SQLLEN indlen;
03820 const char *context;
03821 const char *macrocontext;
03822 const char *callerid;
03823 const char *origtime;
03824 const char *duration;
03825 const char *mailboxuser;
03826 const char *mailboxcontext;
03827 const char *category;
03828 const char *flag;
03829 };
03830
03831 static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
03832 {
03833 struct insert_data *data = vdata;
03834 int res;
03835 SQLHSTMT stmt;
03836
03837 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03838 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03839 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03840 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03841 return NULL;
03842 }
03843
03844 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (void *) data->dir, 0, NULL);
03845 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (void *) data->msgnums, 0, NULL);
03846 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (void *) data->data, data->datalen, &data->indlen);
03847 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (void *) data->context, 0, NULL);
03848 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (void *) data->macrocontext, 0, NULL);
03849 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (void *) data->callerid, 0, NULL);
03850 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (void *) data->origtime, 0, NULL);
03851 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (void *) data->duration, 0, NULL);
03852 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (void *) data->mailboxuser, 0, NULL);
03853 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (void *) data->mailboxcontext, 0, NULL);
03854 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (void *) data->flag, 0, NULL);
03855 if (!ast_strlen_zero(data->category)) {
03856 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *) data->category, 0, NULL);
03857 }
03858 res = SQLExecDirect(stmt, (unsigned char *) data->sql, SQL_NTS);
03859 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03860 ast_log(AST_LOG_WARNING, "SQL Direct Execute failed!\n");
03861 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03862 return NULL;
03863 }
03864
03865 return stmt;
03866 }
03867
03868
03869
03870
03871
03872
03873
03874
03875
03876
03877
03878
03879
03880
03881 static int store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum)
03882 {
03883 int res = 0;
03884 int fd = -1;
03885 void *fdm = MAP_FAILED;
03886 size_t fdlen = -1;
03887 SQLHSTMT stmt;
03888 char sql[PATH_MAX];
03889 char msgnums[20];
03890 char fn[PATH_MAX];
03891 char full_fn[PATH_MAX];
03892 char fmt[80]="";
03893 char *c;
03894 struct ast_config *cfg = NULL;
03895 struct odbc_obj *obj;
03896 struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
03897 .context = "", .macrocontext = "", .callerid = "", .origtime = "", .duration = "", .category = "", .flag = "" };
03898 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03899
03900 delete_file(dir, msgnum);
03901 if (!(obj = ast_odbc_request_obj(odbc_database, 0))) {
03902 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03903 return -1;
03904 }
03905
03906 do {
03907 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03908 c = strchr(fmt, '|');
03909 if (c)
03910 *c = '\0';
03911 if (!strcasecmp(fmt, "wav49"))
03912 strcpy(fmt, "WAV");
03913 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03914 if (msgnum > -1)
03915 make_file(fn, sizeof(fn), dir, msgnum);
03916 else
03917 ast_copy_string(fn, dir, sizeof(fn));
03918 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03919 cfg = ast_config_load(full_fn, config_flags);
03920 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03921 fd = open(full_fn, O_RDWR);
03922 if (fd < 0) {
03923 ast_log(AST_LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
03924 res = -1;
03925 break;
03926 }
03927 if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
03928 if (!(idata.context = ast_variable_retrieve(cfg, "message", "context"))) {
03929 idata.context = "";
03930 }
03931 if (!(idata.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"))) {
03932 idata.macrocontext = "";
03933 }
03934 if (!(idata.callerid = ast_variable_retrieve(cfg, "message", "callerid"))) {
03935 idata.callerid = "";
03936 }
03937 if (!(idata.origtime = ast_variable_retrieve(cfg, "message", "origtime"))) {
03938 idata.origtime = "";
03939 }
03940 if (!(idata.duration = ast_variable_retrieve(cfg, "message", "duration"))) {
03941 idata.duration = "";
03942 }
03943 if (!(idata.category = ast_variable_retrieve(cfg, "message", "category"))) {
03944 idata.category = "";
03945 }
03946 if (!(idata.flag = ast_variable_retrieve(cfg, "message", "flag"))) {
03947 idata.flag = "";
03948 }
03949 }
03950 fdlen = lseek(fd, 0, SEEK_END);
03951 lseek(fd, 0, SEEK_SET);
03952 printf("Length is %zd\n", fdlen);
03953 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
03954 if (fdm == MAP_FAILED) {
03955 ast_log(AST_LOG_WARNING, "Memory map failed!\n");
03956 res = -1;
03957 break;
03958 }
03959 idata.data = fdm;
03960 idata.datalen = idata.indlen = fdlen;
03961
03962 if (!ast_strlen_zero(idata.category))
03963 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03964 else
03965 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag) VALUES (?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03966
03967 if ((stmt = ast_odbc_direct_execute(obj, insert_data_cb, &idata))) {
03968 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03969 } else {
03970 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03971 res = -1;
03972 }
03973 } while (0);
03974 if (obj) {
03975 ast_odbc_release_obj(obj);
03976 }
03977 if (cfg)
03978 ast_config_destroy(cfg);
03979 if (fdm != MAP_FAILED)
03980 munmap(fdm, fdlen);
03981 if (fd > -1)
03982 close(fd);
03983 return res;
03984 }
03985
03986
03987
03988
03989
03990
03991
03992
03993
03994
03995
03996
03997
03998
03999 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
04000 {
04001 SQLHSTMT stmt;
04002 char sql[PATH_MAX];
04003 char msgnums[20];
04004 char msgnumd[20];
04005 struct odbc_obj *obj;
04006 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
04007 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
04008
04009 delete_file(ddir, dmsg);
04010 obj = ast_odbc_request_obj(odbc_database, 0);
04011 if (obj) {
04012 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
04013 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
04014 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table);
04015 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
04016 if (!stmt)
04017 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
04018 else
04019 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
04020 ast_odbc_release_obj(obj);
04021 } else
04022 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
04023 return;
04024 }
04025
04026
04027
04028
04029
04030
04031
04032
04033
04034
04035
04036
04037 static int remove_file(char *dir, int msgnum)
04038 {
04039 char fn[PATH_MAX];
04040 char full_fn[PATH_MAX];
04041 char msgnums[80];
04042
04043 if (msgnum > -1) {
04044 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
04045 make_file(fn, sizeof(fn), dir, msgnum);
04046 } else
04047 ast_copy_string(fn, dir, sizeof(fn));
04048 ast_filedelete(fn, NULL);
04049 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
04050 unlink(full_fn);
04051 return 0;
04052 }
04053 #else
04054 #ifndef IMAP_STORAGE
04055
04056
04057
04058
04059
04060
04061
04062
04063
04064 static int count_messages(struct ast_vm_user *vmu, char *dir)
04065 {
04066
04067 int vmcount = 0;
04068 DIR *vmdir = NULL;
04069 struct dirent *vment = NULL;
04070
04071 if (vm_lock_path(dir))
04072 return ERROR_LOCK_PATH;
04073
04074 if ((vmdir = opendir(dir))) {
04075 while ((vment = readdir(vmdir))) {
04076 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
04077 vmcount++;
04078 }
04079 }
04080 closedir(vmdir);
04081 }
04082 ast_unlock_path(dir);
04083
04084 return vmcount;
04085 }
04086
04087
04088
04089
04090
04091
04092
04093
04094 static void rename_file(char *sfn, char *dfn)
04095 {
04096 char stxt[PATH_MAX];
04097 char dtxt[PATH_MAX];
04098 ast_filerename(sfn, dfn, NULL);
04099 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
04100 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
04101 if (ast_check_realtime("voicemail_data")) {
04102 ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL);
04103 }
04104 rename(stxt, dtxt);
04105 }
04106
04107
04108
04109
04110
04111
04112
04113
04114
04115
04116
04117
04118 static int last_message_index(struct ast_vm_user *vmu, char *dir)
04119 {
04120 int x;
04121 unsigned char map[MAXMSGLIMIT] = "";
04122 DIR *msgdir;
04123 struct dirent *msgdirent;
04124 int msgdirint;
04125 char extension[4];
04126 int stopcount = 0;
04127
04128
04129
04130
04131
04132 if (!(msgdir = opendir(dir))) {
04133 return -1;
04134 }
04135
04136 while ((msgdirent = readdir(msgdir))) {
04137 if (sscanf(msgdirent->d_name, "msg%30d.%3s", &msgdirint, extension) == 2 && !strcmp(extension, "txt") && msgdirint < MAXMSGLIMIT) {
04138 map[msgdirint] = 1;
04139 stopcount++;
04140 ast_debug(4, "%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
04141 }
04142 }
04143 closedir(msgdir);
04144
04145 for (x = 0; x < vmu->maxmsg; x++) {
04146 if (map[x] == 1) {
04147 stopcount--;
04148 } else if (map[x] == 0 && !stopcount) {
04149 break;
04150 }
04151 }
04152
04153 return x - 1;
04154 }
04155
04156 #endif
04157 #endif
04158 #ifndef IMAP_STORAGE
04159
04160
04161
04162
04163
04164
04165
04166
04167
04168
04169 static int copy(char *infile, char *outfile)
04170 {
04171 int ifd;
04172 int ofd;
04173 int res;
04174 int len;
04175 char buf[4096];
04176
04177 #ifdef HARDLINK_WHEN_POSSIBLE
04178
04179 if (link(infile, outfile)) {
04180 #endif
04181 if ((ifd = open(infile, O_RDONLY)) < 0) {
04182 ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
04183 return -1;
04184 }
04185 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
04186 ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
04187 close(ifd);
04188 return -1;
04189 }
04190 do {
04191 len = read(ifd, buf, sizeof(buf));
04192 if (len < 0) {
04193 ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
04194 close(ifd);
04195 close(ofd);
04196 unlink(outfile);
04197 }
04198 if (len) {
04199 res = write(ofd, buf, len);
04200 if (errno == ENOMEM || errno == ENOSPC || res != len) {
04201 ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
04202 close(ifd);
04203 close(ofd);
04204 unlink(outfile);
04205 }
04206 }
04207 } while (len);
04208 close(ifd);
04209 close(ofd);
04210 return 0;
04211 #ifdef HARDLINK_WHEN_POSSIBLE
04212 } else {
04213
04214 return 0;
04215 }
04216 #endif
04217 }
04218
04219
04220
04221
04222
04223
04224
04225
04226
04227
04228 static void copy_plain_file(char *frompath, char *topath)
04229 {
04230 char frompath2[PATH_MAX], topath2[PATH_MAX];
04231 struct ast_variable *tmp,*var = NULL;
04232 const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
04233 ast_filecopy(frompath, topath, NULL);
04234 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
04235 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
04236 if (ast_check_realtime("voicemail_data")) {
04237 var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
04238
04239 for (tmp = var; tmp; tmp = tmp->next) {
04240 if (!strcasecmp(tmp->name, "origmailbox")) {
04241 origmailbox = tmp->value;
04242 } else if (!strcasecmp(tmp->name, "context")) {
04243 context = tmp->value;
04244 } else if (!strcasecmp(tmp->name, "macrocontext")) {
04245 macrocontext = tmp->value;
04246 } else if (!strcasecmp(tmp->name, "exten")) {
04247 exten = tmp->value;
04248 } else if (!strcasecmp(tmp->name, "priority")) {
04249 priority = tmp->value;
04250 } else if (!strcasecmp(tmp->name, "callerchan")) {
04251 callerchan = tmp->value;
04252 } else if (!strcasecmp(tmp->name, "callerid")) {
04253 callerid = tmp->value;
04254 } else if (!strcasecmp(tmp->name, "origdate")) {
04255 origdate = tmp->value;
04256 } else if (!strcasecmp(tmp->name, "origtime")) {
04257 origtime = tmp->value;
04258 } else if (!strcasecmp(tmp->name, "category")) {
04259 category = tmp->value;
04260 } else if (!strcasecmp(tmp->name, "duration")) {
04261 duration = tmp->value;
04262 }
04263 }
04264 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);
04265 }
04266 copy(frompath2, topath2);
04267 ast_variables_destroy(var);
04268 }
04269 #endif
04270
04271
04272
04273
04274
04275
04276
04277
04278
04279 static int vm_delete(char *file)
04280 {
04281 char *txt;
04282 int txtsize = 0;
04283
04284 txtsize = (strlen(file) + 5)*sizeof(char);
04285 txt = alloca(txtsize);
04286
04287
04288
04289 if (ast_check_realtime("voicemail_data")) {
04290 ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
04291 }
04292 snprintf(txt, txtsize, "%s.txt", file);
04293 unlink(txt);
04294 return ast_filedelete(file, NULL);
04295 }
04296
04297
04298
04299
04300 static int inbuf(struct baseio *bio, FILE *fi)
04301 {
04302 int l;
04303
04304 if (bio->ateof)
04305 return 0;
04306
04307 if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) <= 0) {
04308 if (ferror(fi))
04309 return -1;
04310
04311 bio->ateof = 1;
04312 return 0;
04313 }
04314
04315 bio->iolen = l;
04316 bio->iocp = 0;
04317
04318 return 1;
04319 }
04320
04321
04322
04323
04324 static int inchar(struct baseio *bio, FILE *fi)
04325 {
04326 if (bio->iocp>=bio->iolen) {
04327 if (!inbuf(bio, fi))
04328 return EOF;
04329 }
04330
04331 return bio->iobuf[bio->iocp++];
04332 }
04333
04334
04335
04336
04337 static int ochar(struct baseio *bio, int c, FILE *so)
04338 {
04339 if (bio->linelength >= BASELINELEN) {
04340 if (fputs(ENDL, so) == EOF) {
04341 return -1;
04342 }
04343
04344 bio->linelength = 0;
04345 }
04346
04347 if (putc(((unsigned char) c), so) == EOF) {
04348 return -1;
04349 }
04350
04351 bio->linelength++;
04352
04353 return 1;
04354 }
04355
04356
04357
04358
04359
04360
04361
04362
04363
04364
04365 static int base_encode(char *filename, FILE *so)
04366 {
04367 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
04368 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
04369 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
04370 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
04371 int i, hiteof = 0;
04372 FILE *fi;
04373 struct baseio bio;
04374
04375 memset(&bio, 0, sizeof(bio));
04376 bio.iocp = BASEMAXINLINE;
04377
04378 if (!(fi = fopen(filename, "rb"))) {
04379 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
04380 return -1;
04381 }
04382
04383 while (!hiteof){
04384 unsigned char igroup[3], ogroup[4];
04385 int c, n;
04386
04387 memset(igroup, 0, sizeof(igroup));
04388
04389 for (n = 0; n < 3; n++) {
04390 if ((c = inchar(&bio, fi)) == EOF) {
04391 hiteof = 1;
04392 break;
04393 }
04394
04395 igroup[n] = (unsigned char) c;
04396 }
04397
04398 if (n > 0) {
04399 ogroup[0]= dtable[igroup[0] >> 2];
04400 ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
04401 ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
04402 ogroup[3]= dtable[igroup[2] & 0x3F];
04403
04404 if (n < 3) {
04405 ogroup[3] = '=';
04406
04407 if (n < 2)
04408 ogroup[2] = '=';
04409 }
04410
04411 for (i = 0; i < 4; i++)
04412 ochar(&bio, ogroup[i], so);
04413 }
04414 }
04415
04416 fclose(fi);
04417
04418 if (fputs(ENDL, so) == EOF) {
04419 return 0;
04420 }
04421
04422 return 1;
04423 }
04424
04425 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)
04426 {
04427 char callerid[256];
04428 char num[12];
04429 char fromdir[256], fromfile[256];
04430 struct ast_config *msg_cfg;
04431 const char *origcallerid, *origtime;
04432 char origcidname[80], origcidnum[80], origdate[80];
04433 int inttime;
04434 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04435
04436
04437 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
04438 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
04439 snprintf(num, sizeof(num), "%d", msgnum);
04440 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", num);
04441 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
04442 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
04443 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
04444 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
04445 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
04446 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
04447 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
04448 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
04449 pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
04450
04451
04452 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04453 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
04454 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04455 strcat(fromfile, ".txt");
04456 }
04457 if (!(msg_cfg = ast_config_load(fromfile, config_flags))) {
04458 ast_debug(1, "Config load for message text file '%s' failed\n", fromfile);
04459 return;
04460 }
04461
04462 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04463 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
04464 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
04465 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
04466 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
04467 }
04468
04469 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
04470 struct timeval tv = { inttime, };
04471 struct ast_tm tm;
04472 ast_localtime(&tv, &tm, NULL);
04473 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04474 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
04475 }
04476 ast_config_destroy(msg_cfg);
04477 }
04478
04479
04480
04481
04482
04483
04484
04485
04486
04487 static const char *ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
04488 {
04489 const char *ptr;
04490
04491
04492 ast_str_set(buf, maxlen, "\"");
04493 for (ptr = from; *ptr; ptr++) {
04494 if (*ptr == '"' || *ptr == '\\') {
04495 ast_str_append(buf, maxlen, "\\%c", *ptr);
04496 } else {
04497 ast_str_append(buf, maxlen, "%c", *ptr);
04498 }
04499 }
04500 ast_str_append(buf, maxlen, "\"");
04501
04502 return ast_str_buffer(*buf);
04503 }
04504
04505
04506
04507
04508
04509 static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
04510 {
04511 const struct vm_zone *z = NULL;
04512 struct timeval t = ast_tvnow();
04513
04514
04515 if (!ast_strlen_zero(vmu->zonetag)) {
04516
04517 AST_LIST_LOCK(&zones);
04518 AST_LIST_TRAVERSE(&zones, z, list) {
04519 if (!strcmp(z->name, vmu->zonetag))
04520 break;
04521 }
04522 AST_LIST_UNLOCK(&zones);
04523 }
04524 ast_localtime(&t, tm, z ? z->timezone : NULL);
04525 return tm;
04526 }
04527
04528
04529
04530
04531
04532 static int check_mime(const char *str)
04533 {
04534 for (; *str; str++) {
04535 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
04536 return 1;
04537 }
04538 }
04539 return 0;
04540 }
04541
04542
04543
04544
04545
04546
04547
04548
04549
04550
04551
04552
04553
04554
04555
04556
04557
04558
04559 static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
04560 {
04561 struct ast_str *tmp = ast_str_alloca(80);
04562 int first_section = 1;
04563
04564 ast_str_reset(*end);
04565 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04566 for (; *start; start++) {
04567 int need_encoding = 0;
04568 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
04569 need_encoding = 1;
04570 }
04571 if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
04572 (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
04573 (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
04574 (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
04575
04576 ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
04577 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04578 first_section = 0;
04579 }
04580 if (need_encoding && *start == ' ') {
04581 ast_str_append(&tmp, -1, "_");
04582 } else if (need_encoding) {
04583 ast_str_append(&tmp, -1, "=%hhX", *start);
04584 } else {
04585 ast_str_append(&tmp, -1, "%c", *start);
04586 }
04587 }
04588 ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
04589 return ast_str_buffer(*end);
04590 }
04591
04592
04593
04594
04595
04596
04597
04598
04599
04600
04601
04602
04603
04604
04605
04606
04607
04608
04609
04610
04611
04612
04613
04614
04615 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)
04616 {
04617 char date[256];
04618 char host[MAXHOSTNAMELEN] = "";
04619 char who[256];
04620 char bound[256];
04621 char dur[256];
04622 struct ast_tm tm;
04623 char enc_cidnum[256] = "", enc_cidname[256] = "";
04624 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04625 char *greeting_attachment;
04626 char filename[256];
04627
04628 if (!str1 || !str2) {
04629 ast_free(str1);
04630 ast_free(str2);
04631 return;
04632 }
04633
04634 if (cidnum) {
04635 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04636 }
04637 if (cidname) {
04638 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04639 }
04640 gethostname(host, sizeof(host) - 1);
04641
04642 if (strchr(srcemail, '@')) {
04643 ast_copy_string(who, srcemail, sizeof(who));
04644 } else {
04645 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04646 }
04647
04648 greeting_attachment = strrchr(ast_strdupa(attach), '/');
04649 if (greeting_attachment) {
04650 *greeting_attachment++ = '\0';
04651 }
04652
04653 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04654 ast_strftime_locale(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04655 fprintf(p, "Date: %s" ENDL, date);
04656
04657
04658 ast_strftime_locale(date, sizeof(date), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04659
04660 if (!ast_strlen_zero(fromstring)) {
04661 struct ast_channel *ast;
04662 if ((ast = ast_dummy_channel_alloc())) {
04663 char *ptr;
04664 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04665 ast_str_substitute_variables(&str1, 0, ast, fromstring);
04666
04667 if (check_mime(ast_str_buffer(str1))) {
04668 int first_line = 1;
04669 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04670 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04671 *ptr = '\0';
04672 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04673 first_line = 0;
04674
04675 ast_str_set(&str2, 0, "%s", ptr + 1);
04676 }
04677 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04678 } else {
04679 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04680 }
04681 ast = ast_channel_unref(ast);
04682 } else {
04683 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04684 }
04685 } else {
04686 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04687 }
04688
04689 if (check_mime(vmu->fullname)) {
04690 int first_line = 1;
04691 char *ptr;
04692 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(vmu->email) + 3);
04693 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04694 *ptr = '\0';
04695 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04696 first_line = 0;
04697
04698 ast_str_set(&str2, 0, "%s", ptr + 1);
04699 }
04700 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), vmu->email);
04701 } else {
04702 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), vmu->email);
04703 }
04704
04705 if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) {
04706 char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject;
04707 struct ast_channel *ast;
04708 if ((ast = ast_dummy_channel_alloc())) {
04709 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04710 ast_str_substitute_variables(&str1, 0, ast, e_subj);
04711 if (check_mime(ast_str_buffer(str1))) {
04712 int first_line = 1;
04713 char *ptr;
04714 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04715 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04716 *ptr = '\0';
04717 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04718 first_line = 0;
04719
04720 ast_str_set(&str2, 0, "%s", ptr + 1);
04721 }
04722 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04723 } else {
04724 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04725 }
04726 ast = ast_channel_unref(ast);
04727 } else {
04728 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04729 }
04730 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
04731 if (ast_strlen_zero(flag)) {
04732 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04733 } else {
04734 fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04735 }
04736 } else {
04737 if (ast_strlen_zero(flag)) {
04738 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04739 } else {
04740 fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04741 }
04742 }
04743
04744 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1,
04745 (unsigned int) ast_random(), mailbox, (int) getpid(), host);
04746 if (imap) {
04747
04748 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
04749
04750 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
04751 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
04752 #ifdef IMAP_STORAGE
04753 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
04754 #else
04755 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
04756 #endif
04757
04758 fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
04759 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
04760 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, ast_channel_name(chan));
04761 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
04762 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
04763 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
04764 if (!ast_strlen_zero(category)) {
04765 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
04766 } else {
04767 fprintf(p, "X-Asterisk-VM-Category: " ENDL);
04768 }
04769 fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
04770 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
04771 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long) time(NULL));
04772 }
04773 if (!ast_strlen_zero(cidnum)) {
04774 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
04775 }
04776 if (!ast_strlen_zero(cidname)) {
04777 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
04778 }
04779 fprintf(p, "MIME-Version: 1.0" ENDL);
04780 if (attach_user_voicemail) {
04781
04782 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox,
04783 (int) getpid(), (unsigned int) ast_random());
04784
04785 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
04786 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
04787 fprintf(p, "--%s" ENDL, bound);
04788 }
04789 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
04790 if (emailbody || vmu->emailbody) {
04791 char* e_body = vmu->emailbody ? vmu->emailbody : emailbody;
04792 struct ast_channel *ast;
04793 if ((ast = ast_dummy_channel_alloc())) {
04794 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04795 ast_str_substitute_variables(&str1, 0, ast, e_body);
04796 #ifdef IMAP_STORAGE
04797 {
04798
04799 char *line = ast_str_buffer(str1), *next;
04800 do {
04801
04802 if ((next = strchr(line, '\n'))) {
04803 *next++ = '\0';
04804 }
04805 fprintf(p, "%s" ENDL, line);
04806 line = next;
04807 } while (!ast_strlen_zero(line));
04808 }
04809 #else
04810 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04811 #endif
04812 ast = ast_channel_unref(ast);
04813 } else {
04814 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04815 }
04816 } else if (msgnum > -1) {
04817 if (strcmp(vmu->mailbox, mailbox)) {
04818
04819 struct ast_config *msg_cfg;
04820 const char *v;
04821 int inttime;
04822 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
04823 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04824
04825 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04826 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
04827 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04828 strcat(fromfile, ".txt");
04829 }
04830 if ((msg_cfg = ast_config_load(fromfile, config_flags))) {
04831 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04832 ast_copy_string(origcallerid, v, sizeof(origcallerid));
04833 }
04834
04835
04836
04837 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
04838 struct timeval tv = { inttime, };
04839 struct ast_tm tm;
04840 ast_localtime(&tv, &tm, NULL);
04841 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04842 }
04843 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
04844 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
04845 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
04846 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
04847 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
04848 date, origcallerid, origdate);
04849 ast_config_destroy(msg_cfg);
04850 } else {
04851 goto plain_message;
04852 }
04853 } else {
04854 plain_message:
04855 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
04856 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
04857 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
04858 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
04859 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
04860 }
04861 } else {
04862 fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
04863 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
04864 }
04865
04866 if (imap || attach_user_voicemail) {
04867 if (!ast_strlen_zero(attach2)) {
04868 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04869 ast_debug(5, "creating second attachment filename %s\n", filename);
04870 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
04871 snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
04872 ast_debug(5, "creating attachment filename %s\n", filename);
04873 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04874 } else {
04875 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04876 ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
04877 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04878 }
04879 }
04880 ast_free(str1);
04881 ast_free(str2);
04882 }
04883
04884 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)
04885 {
04886 char tmpdir[256], newtmp[256];
04887 char fname[256];
04888 char tmpcmd[256];
04889 int tmpfd = -1;
04890 int soxstatus = 0;
04891
04892
04893 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
04894
04895 if (vmu->volgain < -.001 || vmu->volgain > .001) {
04896 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
04897 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
04898 tmpfd = mkstemp(newtmp);
04899 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
04900 ast_debug(3, "newtmp: %s\n", newtmp);
04901 if (tmpfd > -1) {
04902 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
04903 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
04904 attach = newtmp;
04905 ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
04906 } else {
04907 ast_log(LOG_WARNING, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
04908 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
04909 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
04910 }
04911 }
04912 }
04913 fprintf(p, "--%s" ENDL, bound);
04914 if (msgnum > -1)
04915 fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
04916 else
04917 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
04918 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
04919 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
04920 if (msgnum > -1)
04921 fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
04922 else
04923 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
04924 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
04925 base_encode(fname, p);
04926 if (last)
04927 fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
04928 if (tmpfd > -1) {
04929 if (soxstatus == 0) {
04930 unlink(fname);
04931 }
04932 close(tmpfd);
04933 unlink(newtmp);
04934 }
04935 return 0;
04936 }
04937
04938 static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, const char *flag)
04939 {
04940 FILE *p = NULL;
04941 char tmp[80] = "/tmp/astmail-XXXXXX";
04942 char tmp2[256];
04943 char *stringp;
04944
04945 if (vmu && ast_strlen_zero(vmu->email)) {
04946 ast_log(AST_LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
04947 return(0);
04948 }
04949
04950
04951 format = ast_strdupa(format);
04952 stringp = format;
04953 strsep(&stringp, "|");
04954
04955 if (!strcmp(format, "wav49"))
04956 format = "WAV";
04957 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));
04958
04959
04960 if ((p = vm_mkftemp(tmp)) == NULL) {
04961 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04962 return -1;
04963 } else {
04964 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag);
04965 fclose(p);
04966 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04967 ast_safe_system(tmp2);
04968 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
04969 }
04970 return 0;
04971 }
04972
04973 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)
04974 {
04975 char enc_cidnum[256], enc_cidname[256];
04976 char date[256];
04977 char host[MAXHOSTNAMELEN] = "";
04978 char who[256];
04979 char dur[PATH_MAX];
04980 char tmp[80] = "/tmp/astmail-XXXXXX";
04981 char tmp2[PATH_MAX];
04982 struct ast_tm tm;
04983 FILE *p;
04984 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04985
04986 if (!str1 || !str2) {
04987 ast_free(str1);
04988 ast_free(str2);
04989 return -1;
04990 }
04991
04992 if (cidnum) {
04993 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04994 }
04995 if (cidname) {
04996 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04997 }
04998
04999 if ((p = vm_mkftemp(tmp)) == NULL) {
05000 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
05001 ast_free(str1);
05002 ast_free(str2);
05003 return -1;
05004 }
05005 gethostname(host, sizeof(host)-1);
05006 if (strchr(srcemail, '@')) {
05007 ast_copy_string(who, srcemail, sizeof(who));
05008 } else {
05009 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
05010 }
05011 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
05012 ast_strftime_locale(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
05013 fprintf(p, "Date: %s\n", date);
05014
05015
05016 ast_strftime_locale(date, sizeof(date), pagerdateformat, vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
05017
05018 if (!ast_strlen_zero(pagerfromstring)) {
05019 struct ast_channel *ast;
05020 if ((ast = ast_dummy_channel_alloc())) {
05021 char *ptr;
05022 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
05023 ast_str_substitute_variables(&str1, 0, ast, pagerfromstring);
05024
05025 if (check_mime(ast_str_buffer(str1))) {
05026 int first_line = 1;
05027 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
05028 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
05029 *ptr = '\0';
05030 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
05031 first_line = 0;
05032
05033 ast_str_set(&str2, 0, "%s", ptr + 1);
05034 }
05035 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
05036 } else {
05037 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
05038 }
05039 ast = ast_channel_unref(ast);
05040 } else {
05041 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05042 }
05043 } else {
05044 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
05045 }
05046
05047 if (check_mime(vmu->fullname)) {
05048 int first_line = 1;
05049 char *ptr;
05050 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(pager) + 3);
05051 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
05052 *ptr = '\0';
05053 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
05054 first_line = 0;
05055
05056 ast_str_set(&str2, 0, "%s", ptr + 1);
05057 }
05058 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), pager);
05059 } else {
05060 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), pager);
05061 }
05062
05063 if (!ast_strlen_zero(pagersubject)) {
05064 struct ast_channel *ast;
05065 if ((ast = ast_dummy_channel_alloc())) {
05066 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
05067 ast_str_substitute_variables(&str1, 0, ast, pagersubject);
05068 if (check_mime(ast_str_buffer(str1))) {
05069 int first_line = 1;
05070 char *ptr;
05071 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
05072 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
05073 *ptr = '\0';
05074 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
05075 first_line = 0;
05076
05077 ast_str_set(&str2, 0, "%s", ptr + 1);
05078 }
05079 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
05080 } else {
05081 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
05082 }
05083 ast = ast_channel_unref(ast);
05084 } else {
05085 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05086 }
05087 } else {
05088 if (ast_strlen_zero(flag)) {
05089 fprintf(p, "Subject: New VM\n\n");
05090 } else {
05091 fprintf(p, "Subject: New %s VM\n\n", flag);
05092 }
05093 }
05094
05095 if (pagerbody) {
05096 struct ast_channel *ast;
05097 if ((ast = ast_dummy_channel_alloc())) {
05098 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
05099 ast_str_substitute_variables(&str1, 0, ast, pagerbody);
05100 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
05101 ast = ast_channel_unref(ast);
05102 } else {
05103 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05104 }
05105 } else {
05106 fprintf(p, "New %s long %s msg in box %s\n"
05107 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
05108 }
05109
05110 fclose(p);
05111 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
05112 ast_safe_system(tmp2);
05113 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
05114 ast_free(str1);
05115 ast_free(str2);
05116 return 0;
05117 }
05118
05119
05120
05121
05122
05123
05124
05125
05126
05127
05128 static int get_date(char *s, int len)
05129 {
05130 struct ast_tm tm;
05131 struct timeval t = ast_tvnow();
05132
05133 ast_localtime(&t, &tm, "UTC");
05134
05135 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
05136 }
05137
05138 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
05139 {
05140 int res;
05141 char fn[PATH_MAX];
05142 char dest[PATH_MAX];
05143
05144 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
05145
05146 if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
05147 ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
05148 return -1;
05149 }
05150
05151 RETRIEVE(fn, -1, ext, context);
05152 if (ast_fileexists(fn, NULL, NULL) > 0) {
05153 res = ast_stream_and_wait(chan, fn, ecodes);
05154 if (res) {
05155 DISPOSE(fn, -1);
05156 return res;
05157 }
05158 } else {
05159
05160 DISPOSE(fn, -1);
05161 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
05162 if (res)
05163 return res;
05164 res = ast_say_digit_str(chan, ext, ecodes, ast_channel_language(chan));
05165 if (res)
05166 return res;
05167 }
05168 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
05169 return res;
05170 }
05171
05172 static void free_zone(struct vm_zone *z)
05173 {
05174 ast_free(z);
05175 }
05176
05177 #ifdef ODBC_STORAGE
05178 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05179 {
05180 int x = -1;
05181 int res;
05182 SQLHSTMT stmt = NULL;
05183 char sql[PATH_MAX];
05184 char rowdata[20];
05185 char tmp[PATH_MAX] = "";
05186 struct odbc_obj *obj = NULL;
05187 char *context;
05188 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05189
05190 if (newmsgs)
05191 *newmsgs = 0;
05192 if (oldmsgs)
05193 *oldmsgs = 0;
05194 if (urgentmsgs)
05195 *urgentmsgs = 0;
05196
05197
05198 if (ast_strlen_zero(mailbox))
05199 return 0;
05200
05201 ast_copy_string(tmp, mailbox, sizeof(tmp));
05202
05203 if (strchr(mailbox, ' ') || strchr(mailbox, ',')) {
05204 int u, n, o;
05205 char *next, *remaining = tmp;
05206 while ((next = strsep(&remaining, " ,"))) {
05207 if (inboxcount2(next, urgentmsgs ? &u : NULL, &n, &o)) {
05208 return -1;
05209 }
05210 if (urgentmsgs) {
05211 *urgentmsgs += u;
05212 }
05213 if (newmsgs) {
05214 *newmsgs += n;
05215 }
05216 if (oldmsgs) {
05217 *oldmsgs += o;
05218 }
05219 }
05220 return 0;
05221 }
05222
05223 context = strchr(tmp, '@');
05224 if (context) {
05225 *context = '\0';
05226 context++;
05227 } else
05228 context = "default";
05229
05230 if ((obj = ast_odbc_request_obj(odbc_database, 0))) {
05231 do {
05232 if (newmsgs) {
05233 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
05234 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05235 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05236 break;
05237 }
05238 res = SQLFetch(stmt);
05239 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05240 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05241 break;
05242 }
05243 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05244 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05245 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05246 break;
05247 }
05248 *newmsgs = atoi(rowdata);
05249 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05250 }
05251
05252 if (oldmsgs) {
05253 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
05254 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05255 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05256 break;
05257 }
05258 res = SQLFetch(stmt);
05259 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05260 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05261 break;
05262 }
05263 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05264 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05265 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05266 break;
05267 }
05268 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
05269 *oldmsgs = atoi(rowdata);
05270 }
05271
05272 if (urgentmsgs) {
05273 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent");
05274 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05275 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05276 break;
05277 }
05278 res = SQLFetch(stmt);
05279 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05280 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05281 break;
05282 }
05283 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05284 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05285 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05286 break;
05287 }
05288 *urgentmsgs = atoi(rowdata);
05289 }
05290
05291 x = 0;
05292 } while (0);
05293 } else {
05294 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05295 }
05296
05297 if (stmt) {
05298 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05299 }
05300 if (obj) {
05301 ast_odbc_release_obj(obj);
05302 }
05303 return x;
05304 }
05305
05306
05307
05308
05309
05310
05311
05312
05313
05314
05315 static int messagecount(const char *context, const char *mailbox, const char *folder)
05316 {
05317 struct odbc_obj *obj = NULL;
05318 int nummsgs = 0;
05319 int res;
05320 SQLHSTMT stmt = NULL;
05321 char sql[PATH_MAX];
05322 char rowdata[20];
05323 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05324
05325
05326 if (ast_strlen_zero(mailbox)) {
05327 return 0;
05328 }
05329
05330 if (ast_strlen_zero(folder)) {
05331 folder = "INBOX";
05332 }
05333
05334 obj = ast_odbc_request_obj(odbc_database, 0);
05335 if (obj) {
05336 if (!strcmp(folder, "INBOX")) {
05337 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);
05338 } else {
05339 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
05340 }
05341 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
05342 if (!stmt) {
05343 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05344 goto yuck;
05345 }
05346 res = SQLFetch(stmt);
05347 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05348 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05349 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05350 goto yuck;
05351 }
05352 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05353 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05354 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05355 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05356 goto yuck;
05357 }
05358 nummsgs = atoi(rowdata);
05359 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05360 } else
05361 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05362
05363 yuck:
05364 if (obj)
05365 ast_odbc_release_obj(obj);
05366 return nummsgs;
05367 }
05368
05369
05370
05371
05372
05373
05374
05375
05376
05377 static int has_voicemail(const char *mailbox, const char *folder)
05378 {
05379 char tmp[256], *tmp2 = tmp, *box, *context;
05380 ast_copy_string(tmp, mailbox, sizeof(tmp));
05381 while ((context = box = strsep(&tmp2, ",&"))) {
05382 strsep(&context, "@");
05383 if (ast_strlen_zero(context))
05384 context = "default";
05385 if (messagecount(context, box, folder))
05386 return 1;
05387 }
05388 return 0;
05389 }
05390 #endif
05391 #ifndef IMAP_STORAGE
05392
05393
05394
05395
05396
05397
05398
05399
05400
05401
05402
05403
05404
05405
05406
05407
05408 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)
05409 {
05410 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
05411 const char *frombox = mbox(vmu, imbox);
05412 const char *userfolder;
05413 int recipmsgnum;
05414 int res = 0;
05415
05416 ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
05417
05418 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05419 userfolder = "Urgent";
05420 } else {
05421 userfolder = "INBOX";
05422 }
05423
05424 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05425
05426 if (!dir)
05427 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
05428 else
05429 ast_copy_string(fromdir, dir, sizeof(fromdir));
05430
05431 make_file(frompath, sizeof(frompath), fromdir, msgnum);
05432 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05433
05434 if (vm_lock_path(todir))
05435 return ERROR_LOCK_PATH;
05436
05437 recipmsgnum = last_message_index(recip, todir) + 1;
05438 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
05439 make_file(topath, sizeof(topath), todir, recipmsgnum);
05440 #ifndef ODBC_STORAGE
05441 if (EXISTS(fromdir, msgnum, frompath, ast_channel_language(chan))) {
05442 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
05443 } else {
05444 #endif
05445
05446
05447
05448 copy_plain_file(frompath, topath);
05449 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL);
05450 vm_delete(topath);
05451 #ifndef ODBC_STORAGE
05452 }
05453 #endif
05454 } else {
05455 ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
05456 res = -1;
05457 }
05458 ast_unlock_path(todir);
05459 notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt,
05460 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05461 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05462 flag);
05463
05464 return res;
05465 }
05466 #endif
05467 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
05468
05469 static int messagecount(const char *context, const char *mailbox, const char *folder)
05470 {
05471 return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
05472 }
05473
05474 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
05475 {
05476 DIR *dir;
05477 struct dirent *de;
05478 char fn[256];
05479 int ret = 0;
05480
05481
05482 if (ast_strlen_zero(mailbox))
05483 return 0;
05484
05485 if (ast_strlen_zero(folder))
05486 folder = "INBOX";
05487 if (ast_strlen_zero(context))
05488 context = "default";
05489
05490 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
05491
05492 if (!(dir = opendir(fn)))
05493 return 0;
05494
05495 while ((de = readdir(dir))) {
05496 if (!strncasecmp(de->d_name, "msg", 3)) {
05497 if (shortcircuit) {
05498 ret = 1;
05499 break;
05500 } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
05501 ret++;
05502 }
05503 }
05504 }
05505
05506 closedir(dir);
05507
05508 return ret;
05509 }
05510
05511
05512
05513
05514
05515
05516
05517
05518
05519
05520 static int has_voicemail(const char *mailbox, const char *folder)
05521 {
05522 char tmp[256], *tmp2 = tmp, *box, *context;
05523 ast_copy_string(tmp, mailbox, sizeof(tmp));
05524 if (ast_strlen_zero(folder)) {
05525 folder = "INBOX";
05526 }
05527 while ((box = strsep(&tmp2, ",&"))) {
05528 if ((context = strchr(box, '@')))
05529 *context++ = '\0';
05530 else
05531 context = "default";
05532 if (__has_voicemail(context, box, folder, 1))
05533 return 1;
05534
05535 if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
05536 return 1;
05537 }
05538 }
05539 return 0;
05540 }
05541
05542
05543 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05544 {
05545 char tmp[256];
05546 char *context;
05547
05548
05549 if (ast_strlen_zero(mailbox))
05550 return 0;
05551
05552 if (newmsgs)
05553 *newmsgs = 0;
05554 if (oldmsgs)
05555 *oldmsgs = 0;
05556 if (urgentmsgs)
05557 *urgentmsgs = 0;
05558
05559 if (strchr(mailbox, ',')) {
05560 int tmpnew, tmpold, tmpurgent;
05561 char *mb, *cur;
05562
05563 ast_copy_string(tmp, mailbox, sizeof(tmp));
05564 mb = tmp;
05565 while ((cur = strsep(&mb, ", "))) {
05566 if (!ast_strlen_zero(cur)) {
05567 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
05568 return -1;
05569 else {
05570 if (newmsgs)
05571 *newmsgs += tmpnew;
05572 if (oldmsgs)
05573 *oldmsgs += tmpold;
05574 if (urgentmsgs)
05575 *urgentmsgs += tmpurgent;
05576 }
05577 }
05578 }
05579 return 0;
05580 }
05581
05582 ast_copy_string(tmp, mailbox, sizeof(tmp));
05583
05584 if ((context = strchr(tmp, '@')))
05585 *context++ = '\0';
05586 else
05587 context = "default";
05588
05589 if (newmsgs)
05590 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
05591 if (oldmsgs)
05592 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
05593 if (urgentmsgs)
05594 *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
05595
05596 return 0;
05597 }
05598
05599 #endif
05600
05601
05602 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
05603 {
05604 int urgentmsgs = 0;
05605 int res = inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
05606 if (newmsgs) {
05607 *newmsgs += urgentmsgs;
05608 }
05609 return res;
05610 }
05611
05612 static void run_externnotify(char *context, char *extension, const char *flag)
05613 {
05614 char arguments[255];
05615 char ext_context[256] = "";
05616 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
05617 struct ast_smdi_mwi_message *mwi_msg;
05618
05619 if (!ast_strlen_zero(context))
05620 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
05621 else
05622 ast_copy_string(ext_context, extension, sizeof(ext_context));
05623
05624 if (smdi_iface) {
05625 if (ast_app_has_voicemail(ext_context, NULL))
05626 ast_smdi_mwi_set(smdi_iface, extension);
05627 else
05628 ast_smdi_mwi_unset(smdi_iface, extension);
05629
05630 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
05631 ast_log(AST_LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
05632 if (!strncmp(mwi_msg->cause, "INV", 3))
05633 ast_log(AST_LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
05634 else if (!strncmp(mwi_msg->cause, "BLK", 3))
05635 ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
05636 ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
05637 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
05638 } else {
05639 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
05640 }
05641 }
05642
05643 if (!ast_strlen_zero(externnotify)) {
05644 if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
05645 ast_log(AST_LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
05646 } else {
05647 snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &", externnotify, context, extension, newvoicemails, oldvoicemails, urgentvoicemails);
05648 ast_debug(1, "Executing %s\n", arguments);
05649 ast_safe_system(arguments);
05650 }
05651 }
05652 }
05653
05654
05655
05656
05657
05658
05659 struct leave_vm_options {
05660 unsigned int flags;
05661 signed char record_gain;
05662 char *exitcontext;
05663 };
05664
05665
05666
05667
05668
05669
05670
05671
05672
05673
05674
05675 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
05676 {
05677 #ifdef IMAP_STORAGE
05678 int newmsgs, oldmsgs;
05679 #else
05680 char urgdir[PATH_MAX];
05681 #endif
05682 char txtfile[PATH_MAX];
05683 char tmptxtfile[PATH_MAX];
05684 struct vm_state *vms = NULL;
05685 char callerid[256];
05686 FILE *txt;
05687 char date[256];
05688 int txtdes;
05689 int res = 0;
05690 int msgnum;
05691 int duration = 0;
05692 int sound_duration = 0;
05693 int ausemacro = 0;
05694 int ousemacro = 0;
05695 int ouseexten = 0;
05696 char tmpdur[16];
05697 char priority[16];
05698 char origtime[16];
05699 char dir[PATH_MAX];
05700 char tmpdir[PATH_MAX];
05701 char fn[PATH_MAX];
05702 char prefile[PATH_MAX] = "";
05703 char tempfile[PATH_MAX] = "";
05704 char ext_context[256] = "";
05705 char fmt[80];
05706 char *context;
05707 char ecodes[17] = "#";
05708 struct ast_str *tmp = ast_str_create(16);
05709 char *tmpptr;
05710 struct ast_vm_user *vmu;
05711 struct ast_vm_user svm;
05712 const char *category = NULL;
05713 const char *code;
05714 const char *alldtmf = "0123456789ABCD*#";
05715 char flag[80];
05716
05717 if (!tmp) {
05718 return -1;
05719 }
05720
05721 ast_str_set(&tmp, 0, "%s", ext);
05722 ext = ast_str_buffer(tmp);
05723 if ((context = strchr(ext, '@'))) {
05724 *context++ = '\0';
05725 tmpptr = strchr(context, '&');
05726 } else {
05727 tmpptr = strchr(ext, '&');
05728 }
05729
05730 if (tmpptr)
05731 *tmpptr++ = '\0';
05732
05733 ast_channel_lock(chan);
05734 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
05735 category = ast_strdupa(category);
05736 }
05737 ast_channel_unlock(chan);
05738
05739 if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
05740 ast_copy_string(flag, "Urgent", sizeof(flag));
05741 } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
05742 ast_copy_string(flag, "PRIORITY", sizeof(flag));
05743 } else {
05744 flag[0] = '\0';
05745 }
05746
05747 ast_debug(3, "Before find_user\n");
05748 if (!(vmu = find_user(&svm, context, ext))) {
05749 ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
05750 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05751 ast_free(tmp);
05752 return res;
05753 }
05754
05755 if (strcmp(vmu->context, "default"))
05756 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
05757 else
05758 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
05759
05760
05761
05762
05763
05764
05765 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
05766 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
05767 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
05768 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
05769 }
05770
05771
05772
05773
05774 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
05775 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
05776 ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
05777 ast_free(tmp);
05778 return -1;
05779 }
05780 RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
05781 if (ast_fileexists(tempfile, NULL, NULL) > 0)
05782 ast_copy_string(prefile, tempfile, sizeof(prefile));
05783
05784 DISPOSE(tempfile, -1);
05785
05786 #ifndef IMAP_STORAGE
05787 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
05788 #else
05789 snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
05790 if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
05791 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
05792 }
05793 #endif
05794
05795
05796 if (ast_test_flag(vmu, VM_OPERATOR)) {
05797 if (!ast_strlen_zero(vmu->exit)) {
05798 if (ast_exists_extension(chan, vmu->exit, "o", 1,
05799 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05800 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05801 ouseexten = 1;
05802 }
05803 } else if (ast_exists_extension(chan, chan->context, "o", 1,
05804 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05805 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05806 ouseexten = 1;
05807 } else if (!ast_strlen_zero(chan->macrocontext)
05808 && ast_exists_extension(chan, chan->macrocontext, "o", 1,
05809 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05810 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05811 ousemacro = 1;
05812 }
05813 }
05814
05815 if (!ast_strlen_zero(vmu->exit)) {
05816 if (ast_exists_extension(chan, vmu->exit, "a", 1,
05817 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05818 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05819 }
05820 } else if (ast_exists_extension(chan, chan->context, "a", 1,
05821 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05822 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05823 } else if (!ast_strlen_zero(chan->macrocontext)
05824 && ast_exists_extension(chan, chan->macrocontext, "a", 1,
05825 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05826 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05827 ausemacro = 1;
05828 }
05829
05830 if (ast_test_flag(options, OPT_DTMFEXIT)) {
05831 for (code = alldtmf; *code; code++) {
05832 char e[2] = "";
05833 e[0] = *code;
05834 if (strchr(ecodes, e[0]) == NULL
05835 && ast_canmatch_extension(chan, chan->context, e, 1,
05836 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05837 strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
05838 }
05839 }
05840 }
05841
05842
05843 if (!ast_strlen_zero(prefile)) {
05844 #ifdef ODBC_STORAGE
05845 int success =
05846 #endif
05847 RETRIEVE(prefile, -1, ext, context);
05848 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05849 if (ast_streamfile(chan, prefile, ast_channel_language(chan)) > -1)
05850 res = ast_waitstream(chan, ecodes);
05851 #ifdef ODBC_STORAGE
05852 if (success == -1) {
05853
05854 ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
05855 store_file(prefile, vmu->mailbox, vmu->context, -1);
05856 }
05857 #endif
05858 } else {
05859 ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
05860 res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
05861 }
05862 DISPOSE(prefile, -1);
05863 if (res < 0) {
05864 ast_debug(1, "Hang up during prefile playback\n");
05865 free_user(vmu);
05866 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05867 ast_free(tmp);
05868 return -1;
05869 }
05870 }
05871 if (res == '#') {
05872
05873 ast_set_flag(options, OPT_SILENT);
05874 res = 0;
05875 }
05876
05877 if (vmu->maxmsg == 0) {
05878 ast_debug(3, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
05879 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05880 goto leave_vm_out;
05881 }
05882 if (!res && !ast_test_flag(options, OPT_SILENT)) {
05883 res = ast_stream_and_wait(chan, INTRO, ecodes);
05884 if (res == '#') {
05885 ast_set_flag(options, OPT_SILENT);
05886 res = 0;
05887 }
05888 }
05889 if (res > 0)
05890 ast_stopstream(chan);
05891
05892
05893 if (res == '*') {
05894 chan->exten[0] = 'a';
05895 chan->exten[1] = '\0';
05896 if (!ast_strlen_zero(vmu->exit)) {
05897 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05898 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
05899 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05900 }
05901 chan->priority = 0;
05902 free_user(vmu);
05903 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05904 ast_free(tmp);
05905 return 0;
05906 }
05907
05908
05909 if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
05910 transfer:
05911 if (ouseexten || ousemacro) {
05912 chan->exten[0] = 'o';
05913 chan->exten[1] = '\0';
05914 if (!ast_strlen_zero(vmu->exit)) {
05915 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05916 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
05917 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05918 }
05919 ast_play_and_wait(chan, "transfer");
05920 chan->priority = 0;
05921 free_user(vmu);
05922 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05923 }
05924 ast_free(tmp);
05925 return OPERATOR_EXIT;
05926 }
05927
05928
05929 if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
05930 if (!ast_strlen_zero(options->exitcontext))
05931 ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context));
05932 free_user(vmu);
05933 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05934 ast_free(tmp);
05935 return res;
05936 }
05937
05938 if (res < 0) {
05939 free_user(vmu);
05940 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05941 ast_free(tmp);
05942 return -1;
05943 }
05944
05945 ast_copy_string(fmt, vmfmts, sizeof(fmt));
05946 if (!ast_strlen_zero(fmt)) {
05947 msgnum = 0;
05948
05949 #ifdef IMAP_STORAGE
05950
05951
05952 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
05953 if (res < 0) {
05954 ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
05955 ast_free(tmp);
05956 return -1;
05957 }
05958 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
05959
05960
05961
05962
05963 if (!(vms = create_vm_state_from_user(vmu))) {
05964 ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
05965 ast_free(tmp);
05966 return -1;
05967 }
05968 }
05969 vms->newmessages++;
05970
05971
05972 msgnum = newmsgs + oldmsgs;
05973 ast_debug(3, "Messagecount set to %d\n", msgnum);
05974 snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
05975
05976 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05977
05978 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
05979 goto leave_vm_out;
05980 }
05981 #else
05982 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
05983 res = ast_streamfile(chan, "vm-mailboxfull", ast_channel_language(chan));
05984 if (!res)
05985 res = ast_waitstream(chan, "");
05986 ast_log(AST_LOG_WARNING, "No more messages possible\n");
05987 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05988 inprocess_count(vmu->mailbox, vmu->context, -1);
05989 goto leave_vm_out;
05990 }
05991
05992 #endif
05993 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
05994 txtdes = mkstemp(tmptxtfile);
05995 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
05996 if (txtdes < 0) {
05997 res = ast_streamfile(chan, "vm-mailboxfull", ast_channel_language(chan));
05998 if (!res)
05999 res = ast_waitstream(chan, "");
06000 ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
06001 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
06002 inprocess_count(vmu->mailbox, vmu->context, -1);
06003 goto leave_vm_out;
06004 }
06005
06006
06007 if (res >= 0) {
06008
06009 res = ast_stream_and_wait(chan, "beep", "");
06010 }
06011
06012
06013 if (ast_check_realtime("voicemail_data")) {
06014 snprintf(priority, sizeof(priority), "%d", chan->priority);
06015 snprintf(origtime, sizeof(origtime), "%ld", (long) time(NULL));
06016 get_date(date, sizeof(date));
06017 ast_callerid_merge(callerid, sizeof(callerid),
06018 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06019 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06020 "Unknown");
06021 ast_store_realtime("voicemail_data",
06022 "origmailbox", ext,
06023 "context", chan->context,
06024 "macrocontext", chan->macrocontext,
06025 "exten", chan->exten,
06026 "priority", priority,
06027 "callerchan", ast_channel_name(chan),
06028 "callerid", callerid,
06029 "origdate", date,
06030 "origtime", origtime,
06031 "category", S_OR(category, ""),
06032 "filename", tmptxtfile,
06033 SENTINEL);
06034 }
06035
06036
06037 txt = fdopen(txtdes, "w+");
06038 if (txt) {
06039 get_date(date, sizeof(date));
06040 ast_callerid_merge(callerid, sizeof(callerid),
06041 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06042 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06043 "Unknown");
06044 fprintf(txt,
06045 ";\n"
06046 "; Message Information file\n"
06047 ";\n"
06048 "[message]\n"
06049 "origmailbox=%s\n"
06050 "context=%s\n"
06051 "macrocontext=%s\n"
06052 "exten=%s\n"
06053 "rdnis=%s\n"
06054 "priority=%d\n"
06055 "callerchan=%s\n"
06056 "callerid=%s\n"
06057 "origdate=%s\n"
06058 "origtime=%ld\n"
06059 "category=%s\n",
06060 ext,
06061 chan->context,
06062 chan->macrocontext,
06063 chan->exten,
06064 S_COR(chan->redirecting.from.number.valid,
06065 chan->redirecting.from.number.str, "unknown"),
06066 chan->priority,
06067 ast_channel_name(chan),
06068 callerid,
06069 date, (long) time(NULL),
06070 category ? category : "");
06071 } else {
06072 ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
06073 inprocess_count(vmu->mailbox, vmu->context, -1);
06074 if (ast_check_realtime("voicemail_data")) {
06075 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06076 }
06077 res = ast_streamfile(chan, "vm-mailboxfull", ast_channel_language(chan));
06078 goto leave_vm_out;
06079 }
06080 res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, &sound_duration, NULL, options->record_gain, vms, flag);
06081
06082 if (txt) {
06083 fprintf(txt, "flag=%s\n", flag);
06084 if (sound_duration < vmu->minsecs) {
06085 fclose(txt);
06086 ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", sound_duration, vmu->minsecs);
06087 ast_filedelete(tmptxtfile, NULL);
06088 unlink(tmptxtfile);
06089 if (ast_check_realtime("voicemail_data")) {
06090 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06091 }
06092 inprocess_count(vmu->mailbox, vmu->context, -1);
06093 } else {
06094 fprintf(txt, "duration=%d\n", duration);
06095 fclose(txt);
06096 if (vm_lock_path(dir)) {
06097 ast_log(AST_LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
06098
06099 ast_filedelete(tmptxtfile, NULL);
06100 unlink(tmptxtfile);
06101 inprocess_count(vmu->mailbox, vmu->context, -1);
06102 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
06103 ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
06104 unlink(tmptxtfile);
06105 ast_unlock_path(dir);
06106 inprocess_count(vmu->mailbox, vmu->context, -1);
06107 if (ast_check_realtime("voicemail_data")) {
06108 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06109 }
06110 } else {
06111 #ifndef IMAP_STORAGE
06112 msgnum = last_message_index(vmu, dir) + 1;
06113 #endif
06114 make_file(fn, sizeof(fn), dir, msgnum);
06115
06116
06117 #ifndef IMAP_STORAGE
06118 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
06119 #else
06120 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
06121 #endif
06122
06123 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
06124 ast_filerename(tmptxtfile, fn, NULL);
06125 rename(tmptxtfile, txtfile);
06126 inprocess_count(vmu->mailbox, vmu->context, -1);
06127
06128
06129
06130 if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
06131 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
06132
06133 ast_unlock_path(dir);
06134 if (ast_check_realtime("voicemail_data")) {
06135 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
06136 ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL);
06137 }
06138
06139
06140
06141 if (ast_fileexists(fn, NULL, NULL) > 0) {
06142 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag);
06143 }
06144
06145
06146 while (tmpptr) {
06147 struct ast_vm_user recipu, *recip;
06148 char *exten, *cntx;
06149
06150 exten = strsep(&tmpptr, "&");
06151 cntx = strchr(exten, '@');
06152 if (cntx) {
06153 *cntx = '\0';
06154 cntx++;
06155 }
06156 if ((recip = find_user(&recipu, cntx, exten))) {
06157 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag);
06158 free_user(recip);
06159 }
06160 }
06161 #ifndef IMAP_STORAGE
06162 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
06163
06164 char sfn[PATH_MAX];
06165 char dfn[PATH_MAX];
06166 int x;
06167
06168 create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
06169 x = last_message_index(vmu, urgdir) + 1;
06170 make_file(sfn, sizeof(sfn), dir, msgnum);
06171 make_file(dfn, sizeof(dfn), urgdir, x);
06172 ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n", sfn, dfn);
06173 RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
06174
06175 ast_copy_string(fn, dfn, sizeof(fn));
06176 msgnum = x;
06177 }
06178 #endif
06179
06180 if (ast_fileexists(fn, NULL, NULL)) {
06181 #ifdef IMAP_STORAGE
06182 notify_new_message(chan, vmu, vms, msgnum, duration, fmt,
06183 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06184 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06185 flag);
06186 #else
06187 notify_new_message(chan, vmu, NULL, msgnum, duration, fmt,
06188 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06189 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06190 flag);
06191 #endif
06192 }
06193
06194
06195 if (ast_fileexists(fn, NULL, NULL)) {
06196 DISPOSE(dir, msgnum);
06197 }
06198 }
06199 }
06200 } else {
06201 inprocess_count(vmu->mailbox, vmu->context, -1);
06202 }
06203 if (res == '0') {
06204 goto transfer;
06205 } else if (res > 0 && res != 't')
06206 res = 0;
06207
06208 if (sound_duration < vmu->minsecs)
06209
06210 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
06211 else
06212 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
06213 } else
06214 ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
06215 leave_vm_out:
06216 free_user(vmu);
06217
06218 #ifdef IMAP_STORAGE
06219
06220 ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
06221 if (expungeonhangup == 1) {
06222 ast_mutex_lock(&vms->lock);
06223 #ifdef HAVE_IMAP_TK2006
06224 if (LEVELUIDPLUS (vms->mailstream)) {
06225 mail_expunge_full(vms->mailstream, NIL, EX_UID);
06226 } else
06227 #endif
06228 mail_expunge(vms->mailstream);
06229 ast_mutex_unlock(&vms->lock);
06230 }
06231 #endif
06232
06233 ast_free(tmp);
06234 return res;
06235 }
06236
06237 #if !defined(IMAP_STORAGE)
06238 static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount)
06239 {
06240
06241
06242 int x, dest;
06243 char sfn[PATH_MAX];
06244 char dfn[PATH_MAX];
06245
06246 if (vm_lock_path(dir)) {
06247 return ERROR_LOCK_PATH;
06248 }
06249
06250 for (x = 0, dest = 0; dest != stopcount && x < vmu->maxmsg + 10; x++) {
06251 make_file(sfn, sizeof(sfn), dir, x);
06252 if (EXISTS(dir, x, sfn, NULL)) {
06253
06254 if (x != dest) {
06255 make_file(dfn, sizeof(dfn), dir, dest);
06256 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
06257 }
06258
06259 dest++;
06260 }
06261 }
06262 ast_unlock_path(dir);
06263
06264 return dest;
06265 }
06266 #endif
06267
06268 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
06269 {
06270 int d;
06271 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL);
06272 return d;
06273 }
06274
06275 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
06276 {
06277 #ifdef IMAP_STORAGE
06278
06279
06280 char sequence[10];
06281 char mailbox[256];
06282 int res;
06283
06284
06285 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
06286
06287 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(vmu, box));
06288 ast_mutex_lock(&vms->lock);
06289
06290 if (box == OLD_FOLDER) {
06291 mail_setflag(vms->mailstream, sequence, "\\Seen");
06292 mail_clearflag(vms->mailstream, sequence, "\\Unseen");
06293 } else if (box == NEW_FOLDER) {
06294 mail_setflag(vms->mailstream, sequence, "\\Unseen");
06295 mail_clearflag(vms->mailstream, sequence, "\\Seen");
06296 }
06297 if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
06298 ast_mutex_unlock(&vms->lock);
06299 return 0;
06300 }
06301
06302 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
06303 ast_debug(5, "Checking if folder exists: %s\n", mailbox);
06304 if (mail_create(vms->mailstream, mailbox) == NIL)
06305 ast_debug(5, "Folder exists.\n");
06306 else
06307 ast_log(AST_LOG_NOTICE, "Folder %s created!\n", mbox(vmu, box));
06308 res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box));
06309 ast_mutex_unlock(&vms->lock);
06310 return res;
06311 #else
06312 char *dir = vms->curdir;
06313 char *username = vms->username;
06314 char *context = vmu->context;
06315 char sfn[PATH_MAX];
06316 char dfn[PATH_MAX];
06317 char ddir[PATH_MAX];
06318 const char *dbox = mbox(vmu, box);
06319 int x, i;
06320 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
06321
06322 if (vm_lock_path(ddir))
06323 return ERROR_LOCK_PATH;
06324
06325 x = last_message_index(vmu, ddir) + 1;
06326
06327 if (box == 10 && x >= vmu->maxdeletedmsg) {
06328 x--;
06329 for (i = 1; i <= x; i++) {
06330
06331 make_file(sfn, sizeof(sfn), ddir, i);
06332 make_file(dfn, sizeof(dfn), ddir, i - 1);
06333 if (EXISTS(ddir, i, sfn, NULL)) {
06334 RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
06335 } else
06336 break;
06337 }
06338 } else {
06339 if (x >= vmu->maxmsg) {
06340 ast_unlock_path(ddir);
06341 return -1;
06342 }
06343 }
06344 make_file(sfn, sizeof(sfn), dir, msg);
06345 make_file(dfn, sizeof(dfn), ddir, x);
06346 if (strcmp(sfn, dfn)) {
06347 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
06348 }
06349 ast_unlock_path(ddir);
06350 return 0;
06351 #endif
06352 }
06353
06354 static int adsi_logo(unsigned char *buf)
06355 {
06356 int bytes = 0;
06357 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
06358 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
06359 return bytes;
06360 }
06361
06362 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
06363 {
06364 unsigned char buf[256];
06365 int bytes = 0;
06366 int x;
06367 char num[5];
06368
06369 *useadsi = 0;
06370 bytes += ast_adsi_data_mode(buf + bytes);
06371 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06372
06373 bytes = 0;
06374 bytes += adsi_logo(buf);
06375 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06376 #ifdef DISPLAY
06377 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
06378 #endif
06379 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06380 bytes += ast_adsi_data_mode(buf + bytes);
06381 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06382
06383 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
06384 bytes = 0;
06385 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
06386 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06387 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06388 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06389 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06390 return 0;
06391 }
06392
06393 #ifdef DISPLAY
06394
06395 bytes = 0;
06396 bytes += ast_adsi_logo(buf);
06397 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06398 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
06399 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06400 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06401 #endif
06402 bytes = 0;
06403 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
06404 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
06405 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
06406 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
06407 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
06408 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
06409 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06410
06411 #ifdef DISPLAY
06412
06413 bytes = 0;
06414 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
06415 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06416
06417 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06418 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06419 #endif
06420
06421 bytes = 0;
06422
06423 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
06424 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
06425 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
06426 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
06427 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
06428 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
06429 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06430
06431 #ifdef DISPLAY
06432
06433 bytes = 0;
06434 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
06435 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06436 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06437 #endif
06438
06439 bytes = 0;
06440 for (x = 0; x < 5; x++) {
06441 snprintf(num, sizeof(num), "%d", x);
06442 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(NULL, x), mbox(NULL, x), num, 1);
06443 }
06444 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
06445 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06446
06447 #ifdef DISPLAY
06448
06449 bytes = 0;
06450 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
06451 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06452 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06453 #endif
06454
06455 if (ast_adsi_end_download(chan)) {
06456 bytes = 0;
06457 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
06458 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06459 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06460 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06461 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06462 return 0;
06463 }
06464 bytes = 0;
06465 bytes += ast_adsi_download_disconnect(buf + bytes);
06466 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06467 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06468
06469 ast_debug(1, "Done downloading scripts...\n");
06470
06471 #ifdef DISPLAY
06472
06473 bytes = 0;
06474 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
06475 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06476 #endif
06477 ast_debug(1, "Restarting session...\n");
06478
06479 bytes = 0;
06480
06481 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
06482 *useadsi = 1;
06483 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
06484 } else
06485 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
06486
06487 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06488 return 0;
06489 }
06490
06491 static void adsi_begin(struct ast_channel *chan, int *useadsi)
06492 {
06493 int x;
06494 if (!ast_adsi_available(chan))
06495 return;
06496 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
06497 if (x < 0)
06498 return;
06499 if (!x) {
06500 if (adsi_load_vmail(chan, useadsi)) {
06501 ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
06502 return;
06503 }
06504 } else
06505 *useadsi = 1;
06506 }
06507
06508 static void adsi_login(struct ast_channel *chan)
06509 {
06510 unsigned char buf[256];
06511 int bytes = 0;
06512 unsigned char keys[8];
06513 int x;
06514 if (!ast_adsi_available(chan))
06515 return;
06516
06517 for (x = 0; x < 8; x++)
06518 keys[x] = 0;
06519
06520 keys[3] = ADSI_KEY_APPS + 3;
06521
06522 bytes += adsi_logo(buf + bytes);
06523 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
06524 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
06525 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06526 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
06527 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
06528 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
06529 bytes += ast_adsi_set_keys(buf + bytes, keys);
06530 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06531 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06532 }
06533
06534 static void adsi_password(struct ast_channel *chan)
06535 {
06536 unsigned char buf[256];
06537 int bytes = 0;
06538 unsigned char keys[8];
06539 int x;
06540 if (!ast_adsi_available(chan))
06541 return;
06542
06543 for (x = 0; x < 8; x++)
06544 keys[x] = 0;
06545
06546 keys[3] = ADSI_KEY_APPS + 3;
06547
06548 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06549 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
06550 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
06551 bytes += ast_adsi_set_keys(buf + bytes, keys);
06552 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06553 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06554 }
06555
06556 static void adsi_folders(struct ast_channel *chan, int start, char *label)
06557 {
06558 unsigned char buf[256];
06559 int bytes = 0;
06560 unsigned char keys[8];
06561 int x, y;
06562
06563 if (!ast_adsi_available(chan))
06564 return;
06565
06566 for (x = 0; x < 5; x++) {
06567 y = ADSI_KEY_APPS + 12 + start + x;
06568 if (y > ADSI_KEY_APPS + 12 + 4)
06569 y = 0;
06570 keys[x] = ADSI_KEY_SKT | y;
06571 }
06572 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
06573 keys[6] = 0;
06574 keys[7] = 0;
06575
06576 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
06577 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
06578 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06579 bytes += ast_adsi_set_keys(buf + bytes, keys);
06580 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06581
06582 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06583 }
06584
06585 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
06586 {
06587 int bytes = 0;
06588 unsigned char buf[256];
06589 char buf1[256], buf2[256];
06590 char fn2[PATH_MAX];
06591
06592 char cid[256] = "";
06593 char *val;
06594 char *name, *num;
06595 char datetime[21] = "";
06596 FILE *f;
06597
06598 unsigned char keys[8];
06599
06600 int x;
06601
06602 if (!ast_adsi_available(chan))
06603 return;
06604
06605
06606 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
06607 f = fopen(fn2, "r");
06608 if (f) {
06609 while (!feof(f)) {
06610 if (!fgets((char *) buf, sizeof(buf), f)) {
06611 continue;
06612 }
06613 if (!feof(f)) {
06614 char *stringp = NULL;
06615 stringp = (char *) buf;
06616 strsep(&stringp, "=");
06617 val = strsep(&stringp, "=");
06618 if (!ast_strlen_zero(val)) {
06619 if (!strcmp((char *) buf, "callerid"))
06620 ast_copy_string(cid, val, sizeof(cid));
06621 if (!strcmp((char *) buf, "origdate"))
06622 ast_copy_string(datetime, val, sizeof(datetime));
06623 }
06624 }
06625 }
06626 fclose(f);
06627 }
06628
06629 for (x = 0; x < 5; x++)
06630 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06631 keys[6] = 0x0;
06632 keys[7] = 0x0;
06633
06634 if (!vms->curmsg) {
06635
06636 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06637 }
06638 if (vms->curmsg >= vms->lastmsg) {
06639
06640 if (vms->curmsg) {
06641
06642 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06643 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06644
06645 } else {
06646
06647 keys[3] = 1;
06648 }
06649 }
06650
06651 if (!ast_strlen_zero(cid)) {
06652 ast_callerid_parse(cid, &name, &num);
06653 if (!name)
06654 name = num;
06655 } else
06656 name = "Unknown Caller";
06657
06658
06659
06660 if (vms->deleted[vms->curmsg])
06661 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06662
06663
06664 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06665 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
06666 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
06667 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
06668
06669 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06670 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06671 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
06672 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
06673 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06674 bytes += ast_adsi_set_keys(buf + bytes, keys);
06675 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06676
06677 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06678 }
06679
06680 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
06681 {
06682 int bytes = 0;
06683 unsigned char buf[256];
06684 unsigned char keys[8];
06685
06686 int x;
06687
06688 if (!ast_adsi_available(chan))
06689 return;
06690
06691
06692 for (x = 0; x < 5; x++)
06693 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06694
06695 keys[6] = 0x0;
06696 keys[7] = 0x0;
06697
06698 if (!vms->curmsg) {
06699
06700 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06701 }
06702 if (vms->curmsg >= vms->lastmsg) {
06703
06704 if (vms->curmsg) {
06705
06706 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06707 } else {
06708
06709 keys[3] = 1;
06710 }
06711 }
06712
06713
06714 if (vms->deleted[vms->curmsg])
06715 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06716
06717
06718 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06719 bytes += ast_adsi_set_keys(buf + bytes, keys);
06720 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06721
06722 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06723 }
06724
06725 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
06726 {
06727 unsigned char buf[256] = "";
06728 char buf1[256] = "", buf2[256] = "";
06729 int bytes = 0;
06730 unsigned char keys[8];
06731 int x;
06732
06733 char *newm = (vms->newmessages == 1) ? "message" : "messages";
06734 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
06735 if (!ast_adsi_available(chan))
06736 return;
06737 if (vms->newmessages) {
06738 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
06739 if (vms->oldmessages) {
06740 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
06741 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
06742 } else {
06743 snprintf(buf2, sizeof(buf2), "%s.", newm);
06744 }
06745 } else if (vms->oldmessages) {
06746 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
06747 snprintf(buf2, sizeof(buf2), "%s.", oldm);
06748 } else {
06749 strcpy(buf1, "You have no messages.");
06750 buf2[0] = ' ';
06751 buf2[1] = '\0';
06752 }
06753 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06754 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06755 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06756
06757 for (x = 0; x < 6; x++)
06758 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06759 keys[6] = 0;
06760 keys[7] = 0;
06761
06762
06763 if (vms->lastmsg < 0)
06764 keys[0] = 1;
06765 bytes += ast_adsi_set_keys(buf + bytes, keys);
06766
06767 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06768
06769 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06770 }
06771
06772 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
06773 {
06774 unsigned char buf[256] = "";
06775 char buf1[256] = "", buf2[256] = "";
06776 int bytes = 0;
06777 unsigned char keys[8];
06778 int x;
06779
06780 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
06781
06782 if (!ast_adsi_available(chan))
06783 return;
06784
06785
06786 for (x = 0; x < 6; x++)
06787 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06788
06789 keys[6] = 0;
06790 keys[7] = 0;
06791
06792 if ((vms->lastmsg + 1) < 1)
06793 keys[0] = 0;
06794
06795 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
06796 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
06797
06798 if (vms->lastmsg + 1)
06799 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
06800 else
06801 strcpy(buf2, "no messages.");
06802 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06803 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06804 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
06805 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06806 bytes += ast_adsi_set_keys(buf + bytes, keys);
06807
06808 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06809
06810 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06811
06812 }
06813
06814
06815
06816
06817
06818
06819
06820
06821
06822
06823
06824
06825
06826
06827
06828 static void adsi_goodbye(struct ast_channel *chan)
06829 {
06830 unsigned char buf[256];
06831 int bytes = 0;
06832
06833 if (!ast_adsi_available(chan))
06834 return;
06835 bytes += adsi_logo(buf + bytes);
06836 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
06837 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
06838 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06839 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06840
06841 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06842 }
06843
06844
06845
06846
06847
06848 static int get_folder(struct ast_channel *chan, int start)
06849 {
06850 int x;
06851 int d;
06852 char fn[PATH_MAX];
06853 d = ast_play_and_wait(chan, "vm-press");
06854 if (d)
06855 return d;
06856 for (x = start; x < 5; x++) {
06857 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, ast_channel_language(chan), NULL)))
06858 return d;
06859 d = ast_play_and_wait(chan, "vm-for");
06860 if (d)
06861 return d;
06862 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x));
06863
06864
06865
06866
06867 if (x == 0) {
06868 if (ast_fileexists(fn, NULL, NULL)) {
06869 d = vm_play_folder_name(chan, fn);
06870 } else {
06871 ast_verb(1, "failed to find %s\n", fn);
06872 d = vm_play_folder_name(chan, "vm-INBOX");
06873 }
06874 } else {
06875 ast_test_suite_event_notify("PLAYBACK", "Message: folder name %s", fn);
06876 d = vm_play_folder_name(chan, fn);
06877 }
06878
06879 if (d)
06880 return d;
06881 d = ast_waitfordigit(chan, 500);
06882 if (d)
06883 return d;
06884 }
06885
06886 d = ast_play_and_wait(chan, "vm-tocancel");
06887 if (d)
06888 return d;
06889 d = ast_waitfordigit(chan, 4000);
06890 return d;
06891 }
06892
06893
06894
06895
06896
06897
06898
06899
06900
06901
06902
06903
06904
06905 static int get_folder2(struct ast_channel *chan, char *fn, int start)
06906 {
06907 int res = 0;
06908 int loops = 0;
06909
06910 res = ast_play_and_wait(chan, fn);
06911 while (((res < '0') || (res > '9')) &&
06912 (res != '#') && (res >= 0) &&
06913 loops < 4) {
06914 res = get_folder(chan, 0);
06915 loops++;
06916 }
06917 if (loops == 4) {
06918 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", '#', '#');
06919 return '#';
06920 }
06921 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
06922 return res;
06923 }
06924
06925
06926
06927
06928
06929
06930
06931
06932
06933
06934
06935
06936
06937
06938
06939
06940
06941
06942
06943 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts,
06944 char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
06945 {
06946 int cmd = 0;
06947 int retries = 0, prepend_duration = 0, already_recorded = 0;
06948 char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06949 char textfile[PATH_MAX];
06950 struct ast_config *msg_cfg;
06951 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06952 #ifndef IMAP_STORAGE
06953 signed char zero_gain = 0;
06954 #endif
06955 const char *duration_str;
06956
06957
06958 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06959 strcpy(textfile, msgfile);
06960 strcpy(backup, msgfile);
06961 strcpy(backup_textfile, msgfile);
06962 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
06963 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
06964 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
06965
06966 if ((msg_cfg = ast_config_load(textfile, config_flags)) && msg_cfg != CONFIG_STATUS_FILEINVALID && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
06967 *duration = atoi(duration_str);
06968 } else {
06969 *duration = 0;
06970 }
06971
06972 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
06973 if (cmd)
06974 retries = 0;
06975 switch (cmd) {
06976 case '1':
06977
06978 #ifdef IMAP_STORAGE
06979
06980 make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
06981 strncat(vms->introfn, "intro", sizeof(vms->introfn));
06982 ast_play_and_wait(chan, INTRO);
06983 ast_play_and_wait(chan, "beep");
06984 play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, NULL, record_gain, vms, flag);
06985 cmd = 't';
06986 #else
06987
06988
06989
06990 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06991 strcpy(textfile, msgfile);
06992 strncat(textfile, ".txt", sizeof(textfile) - 1);
06993 *duration = 0;
06994
06995
06996 if (!msg_cfg) {
06997 cmd = 0;
06998 break;
06999 }
07000
07001
07002 #ifndef IMAP_STORAGE
07003 if (already_recorded) {
07004 ast_filecopy(backup, msgfile, NULL);
07005 copy(backup_textfile, textfile);
07006 }
07007 else {
07008 ast_filecopy(msgfile, backup, NULL);
07009 copy(textfile, backup_textfile);
07010 }
07011 #endif
07012 already_recorded = 1;
07013
07014 if (record_gain)
07015 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
07016
07017 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, NULL, 1, silencethreshold, maxsilence);
07018
07019 if (cmd == 'S') {
07020 ast_stream_and_wait(chan, vm_pls_try_again, "");
07021 ast_stream_and_wait(chan, vm_prepend_timeout, "");
07022 ast_filerename(backup, msgfile, NULL);
07023 }
07024
07025 if (record_gain)
07026 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
07027
07028
07029 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
07030 *duration = atoi(duration_str);
07031
07032 if (prepend_duration) {
07033 struct ast_category *msg_cat;
07034
07035 char duration_buf[12];
07036
07037 *duration += prepend_duration;
07038 msg_cat = ast_category_get(msg_cfg, "message");
07039 snprintf(duration_buf, 11, "%ld", *duration);
07040 if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
07041 ast_config_text_file_save(textfile, msg_cfg, "app_voicemail");
07042 }
07043 }
07044
07045 #endif
07046 break;
07047 case '2':
07048
07049 #ifdef IMAP_STORAGE
07050 *vms->introfn = '\0';
07051 #endif
07052 cmd = 't';
07053 break;
07054 case '*':
07055 cmd = '*';
07056 break;
07057 default:
07058
07059 already_recorded = 0;
07060
07061 cmd = ast_play_and_wait(chan, "vm-forwardoptions");
07062
07063 if (!cmd) {
07064 cmd = ast_play_and_wait(chan, "vm-starmain");
07065
07066 }
07067 if (!cmd) {
07068 cmd = ast_waitfordigit(chan, 6000);
07069 }
07070 if (!cmd) {
07071 retries++;
07072 }
07073 if (retries > 3) {
07074 cmd = '*';
07075 }
07076 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07077 }
07078 }
07079
07080 if (msg_cfg)
07081 ast_config_destroy(msg_cfg);
07082 if (prepend_duration)
07083 *duration = prepend_duration;
07084
07085 if (already_recorded && cmd == -1) {
07086
07087 ast_filerename(backup, msgfile, NULL);
07088 rename(backup_textfile, textfile);
07089 }
07090
07091 if (cmd == 't' || cmd == 'S')
07092 cmd = 0;
07093 return cmd;
07094 }
07095
07096 static void queue_mwi_event(const char *box, int urgent, int new, int old)
07097 {
07098 struct ast_event *event;
07099 char *mailbox, *context;
07100
07101
07102 context = mailbox = ast_strdupa(box);
07103 strsep(&context, "@");
07104 if (ast_strlen_zero(context))
07105 context = "default";
07106
07107 if (!(event = ast_event_new(AST_EVENT_MWI,
07108 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
07109 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
07110 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
07111 AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
07112 AST_EVENT_IE_END))) {
07113 return;
07114 }
07115
07116 ast_event_queue_and_cache(event);
07117 }
07118
07119
07120
07121
07122
07123
07124
07125
07126
07127
07128
07129
07130
07131
07132
07133 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)
07134 {
07135 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
07136 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
07137 const char *category;
07138 char *myserveremail = serveremail;
07139
07140 ast_channel_lock(chan);
07141 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
07142 category = ast_strdupa(category);
07143 }
07144 ast_channel_unlock(chan);
07145
07146 #ifndef IMAP_STORAGE
07147 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag) && !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
07148 #else
07149 snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
07150 #endif
07151 make_file(fn, sizeof(fn), todir, msgnum);
07152 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
07153
07154 if (!ast_strlen_zero(vmu->attachfmt)) {
07155 if (strstr(fmt, vmu->attachfmt))
07156 fmt = vmu->attachfmt;
07157 else
07158 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);
07159 }
07160
07161
07162 fmt = ast_strdupa(fmt);
07163 stringp = fmt;
07164 strsep(&stringp, "|");
07165
07166 if (!ast_strlen_zero(vmu->serveremail))
07167 myserveremail = vmu->serveremail;
07168
07169 if (!ast_strlen_zero(vmu->email)) {
07170 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
07171
07172 if (attach_user_voicemail)
07173 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
07174
07175
07176 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag);
07177
07178 if (attach_user_voicemail)
07179 DISPOSE(todir, msgnum);
07180 }
07181
07182 if (!ast_strlen_zero(vmu->pager)) {
07183 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
07184 }
07185
07186 if (ast_test_flag(vmu, VM_DELETE))
07187 DELETE(todir, msgnum, fn, vmu);
07188
07189
07190 if (ast_app_has_voicemail(ext_context, NULL))
07191 ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
07192
07193 queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);
07194
07195 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s@%s\r\nWaiting: %d\r\nNew: %d\r\nOld: %d\r\n", vmu->mailbox, vmu->context, ast_app_has_voicemail(ext_context, NULL), newmsgs, oldmsgs);
07196 run_externnotify(vmu->context, vmu->mailbox, flag);
07197
07198 #ifdef IMAP_STORAGE
07199 vm_delete(fn);
07200 if (ast_test_flag(vmu, VM_DELETE)) {
07201 vm_imap_delete(NULL, vms->curmsg, vmu);
07202 vms->newmessages--;
07203 }
07204 #endif
07205
07206 return 0;
07207 }
07208
07209
07210
07211
07212
07213
07214
07215
07216
07217
07218
07219
07220
07221
07222
07223
07224
07225
07226
07227
07228
07229
07230
07231
07232
07233
07234
07235
07236 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)
07237 {
07238 #ifdef IMAP_STORAGE
07239 int todircount = 0;
07240 struct vm_state *dstvms;
07241 #endif
07242 char username[70]="";
07243 char fn[PATH_MAX];
07244 char ecodes[16] = "#";
07245 int res = 0, cmd = 0;
07246 struct ast_vm_user *receiver = NULL, *vmtmp;
07247 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
07248 char *stringp;
07249 const char *s;
07250 int saved_messages = 0;
07251 int valid_extensions = 0;
07252 char *dir;
07253 int curmsg;
07254 char urgent_str[7] = "";
07255 int prompt_played = 0;
07256 #ifndef IMAP_STORAGE
07257 char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
07258 #endif
07259 if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
07260 ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
07261 }
07262
07263 if (vms == NULL) return -1;
07264 dir = vms->curdir;
07265 curmsg = vms->curmsg;
07266
07267 ast_test_suite_event_notify("FORWARD", "Message: entering forward message menu");
07268 while (!res && !valid_extensions) {
07269 int use_directory = 0;
07270 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
07271 int done = 0;
07272 int retries = 0;
07273 cmd = 0;
07274 while ((cmd >= 0) && !done ){
07275 if (cmd)
07276 retries = 0;
07277 switch (cmd) {
07278 case '1':
07279 use_directory = 0;
07280 done = 1;
07281 break;
07282 case '2':
07283 use_directory = 1;
07284 done = 1;
07285 break;
07286 case '*':
07287 cmd = 't';
07288 done = 1;
07289 break;
07290 default:
07291
07292 cmd = ast_play_and_wait(chan, "vm-forward");
07293 if (!cmd) {
07294 cmd = ast_waitfordigit(chan, 3000);
07295 }
07296 if (!cmd) {
07297 retries++;
07298 }
07299 if (retries > 3) {
07300 cmd = 't';
07301 done = 1;
07302 }
07303 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07304 }
07305 }
07306 if (cmd < 0 || cmd == 't')
07307 break;
07308 }
07309
07310 if (use_directory) {
07311
07312
07313 char old_context[sizeof(chan->context)];
07314 char old_exten[sizeof(chan->exten)];
07315 int old_priority;
07316 struct ast_app* directory_app;
07317
07318 directory_app = pbx_findapp("Directory");
07319 if (directory_app) {
07320 char vmcontext[256];
07321
07322 memcpy(old_context, chan->context, sizeof(chan->context));
07323 memcpy(old_exten, chan->exten, sizeof(chan->exten));
07324 old_priority = chan->priority;
07325
07326
07327 snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
07328 res = pbx_exec(chan, directory_app, vmcontext);
07329
07330 ast_copy_string(username, chan->exten, sizeof(username));
07331
07332
07333 memcpy(chan->context, old_context, sizeof(chan->context));
07334 memcpy(chan->exten, old_exten, sizeof(chan->exten));
07335 chan->priority = old_priority;
07336 } else {
07337 ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
07338 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
07339 }
07340 } else {
07341
07342 ast_test_suite_event_notify("PLAYBACK", "Message: vm-extension");
07343 res = ast_streamfile(chan, "vm-extension", ast_channel_language(chan));
07344 prompt_played++;
07345 if (res || prompt_played > 4)
07346 break;
07347 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#")) < 0)
07348 break;
07349 }
07350
07351
07352 if (ast_strlen_zero(username))
07353 continue;
07354 stringp = username;
07355 s = strsep(&stringp, "*");
07356
07357 valid_extensions = 1;
07358 while (s) {
07359 if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
07360 int oldmsgs;
07361 int newmsgs;
07362 int capacity;
07363 if (inboxcount(s, &newmsgs, &oldmsgs)) {
07364 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", s);
07365
07366 res = ast_play_and_wait(chan, "pbx-invalid");
07367 valid_extensions = 0;
07368 break;
07369 }
07370 capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
07371 if ((newmsgs + oldmsgs) >= capacity) {
07372 ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity);
07373 res = ast_play_and_wait(chan, "vm-mailboxfull");
07374 valid_extensions = 0;
07375 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07376 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07377 free_user(vmtmp);
07378 }
07379 inprocess_count(receiver->mailbox, receiver->context, -1);
07380 break;
07381 }
07382 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
07383 } else {
07384
07385
07386
07387
07388
07389 while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07390 free_user(receiver);
07391 }
07392 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
07393
07394 res = ast_play_and_wait(chan, "pbx-invalid");
07395 valid_extensions = 0;
07396 break;
07397 }
07398
07399
07400 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
07401 RETRIEVE(fn, -1, s, receiver->context);
07402 if (ast_fileexists(fn, NULL, NULL) > 0) {
07403 res = ast_stream_and_wait(chan, fn, ecodes);
07404 if (res) {
07405 DISPOSE(fn, -1);
07406 return res;
07407 }
07408 } else {
07409 res = ast_say_digit_str(chan, s, ecodes, ast_channel_language(chan));
07410 }
07411 DISPOSE(fn, -1);
07412
07413 s = strsep(&stringp, "*");
07414 }
07415
07416 if (valid_extensions)
07417 break;
07418 }
07419
07420 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
07421 return res;
07422 if (is_new_message == 1) {
07423 struct leave_vm_options leave_options;
07424 char mailbox[AST_MAX_EXTENSION * 2 + 2];
07425 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
07426
07427
07428 memset(&leave_options, 0, sizeof(leave_options));
07429 leave_options.record_gain = record_gain;
07430 cmd = leave_voicemail(chan, mailbox, &leave_options);
07431 } else {
07432
07433 long duration = 0;
07434 struct vm_state vmstmp;
07435 int copy_msg_result = 0;
07436 memcpy(&vmstmp, vms, sizeof(vmstmp));
07437
07438 RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
07439
07440 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
07441 if (!cmd) {
07442 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
07443 #ifdef IMAP_STORAGE
07444 int attach_user_voicemail;
07445 char *myserveremail = serveremail;
07446
07447
07448 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
07449 if (!dstvms) {
07450 dstvms = create_vm_state_from_user(vmtmp);
07451 }
07452 if (dstvms) {
07453 init_mailstream(dstvms, 0);
07454 if (!dstvms->mailstream) {
07455 ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
07456 } else {
07457 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str);
07458 run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str);
07459 }
07460 } else {
07461 ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
07462 }
07463 if (!ast_strlen_zero(vmtmp->serveremail))
07464 myserveremail = vmtmp->serveremail;
07465 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
07466
07467 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
07468 dstvms->curbox,
07469 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
07470 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
07471 vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
07472 NULL, urgent_str);
07473 #else
07474 copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
07475 #endif
07476 saved_messages++;
07477 AST_LIST_REMOVE_CURRENT(list);
07478 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07479 free_user(vmtmp);
07480 if (res)
07481 break;
07482 }
07483 AST_LIST_TRAVERSE_SAFE_END;
07484 if (saved_messages > 0 && !copy_msg_result) {
07485
07486
07487
07488
07489
07490
07491
07492
07493 #ifdef IMAP_STORAGE
07494
07495 if (ast_strlen_zero(vmstmp.introfn))
07496 #endif
07497 res = ast_play_and_wait(chan, "vm-msgsaved");
07498 }
07499 #ifndef IMAP_STORAGE
07500 else {
07501
07502 res = ast_play_and_wait(chan, "vm-mailboxfull");
07503 }
07504
07505 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07506 strcpy(textfile, msgfile);
07507 strcpy(backup, msgfile);
07508 strcpy(backup_textfile, msgfile);
07509 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07510 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
07511 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07512 if (ast_fileexists(backup, NULL, NULL) > 0) {
07513 ast_filerename(backup, msgfile, NULL);
07514 rename(backup_textfile, textfile);
07515 }
07516 #endif
07517 }
07518 DISPOSE(dir, curmsg);
07519 #ifndef IMAP_STORAGE
07520 if (cmd) {
07521 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07522 strcpy(textfile, msgfile);
07523 strcpy(backup_textfile, msgfile);
07524 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07525 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07526 rename(backup_textfile, textfile);
07527 }
07528 #endif
07529 }
07530
07531
07532 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07533 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07534 free_user(vmtmp);
07535 }
07536 return res ? res : cmd;
07537 }
07538
07539 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
07540 {
07541 int res;
07542 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
07543 ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file);
07544 return res;
07545 }
07546
07547 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
07548 {
07549 ast_test_suite_event_notify("PLAYVOICE", "Message: Playing %s", file);
07550 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);
07551 }
07552
07553 static int play_message_category(struct ast_channel *chan, const char *category)
07554 {
07555 int res = 0;
07556
07557 if (!ast_strlen_zero(category))
07558 res = ast_play_and_wait(chan, category);
07559
07560 if (res) {
07561 ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
07562 res = 0;
07563 }
07564
07565 return res;
07566 }
07567
07568 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
07569 {
07570 int res = 0;
07571 struct vm_zone *the_zone = NULL;
07572 time_t t;
07573
07574 if (ast_get_time_t(origtime, &t, 0, NULL)) {
07575 ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
07576 return 0;
07577 }
07578
07579
07580 if (!ast_strlen_zero(vmu->zonetag)) {
07581
07582 struct vm_zone *z;
07583 AST_LIST_LOCK(&zones);
07584 AST_LIST_TRAVERSE(&zones, z, list) {
07585 if (!strcmp(z->name, vmu->zonetag)) {
07586 the_zone = z;
07587 break;
07588 }
07589 }
07590 AST_LIST_UNLOCK(&zones);
07591 }
07592
07593
07594 #if 0
07595
07596 ast_localtime(&t, &time_now, NULL);
07597 tv_now = ast_tvnow();
07598 ast_localtime(&tv_now, &time_then, NULL);
07599
07600
07601 if (time_now.tm_year == time_then.tm_year)
07602 snprintf(temp, sizeof(temp), "%d", time_now.tm_yday);
07603 else
07604 snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
07605 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
07606
07607
07608 #endif
07609 if (the_zone) {
07610 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), the_zone->msg_format, the_zone->timezone);
07611 } else if (!strncasecmp(ast_channel_language(chan), "de", 2)) {
07612 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' Q 'digits/at' HM", NULL);
07613 } else if (!strncasecmp(ast_channel_language(chan), "gr", 2)) {
07614 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' q H 'digits/kai' M ", NULL);
07615 } else if (!strncasecmp(ast_channel_language(chan), "it", 2)) {
07616 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);
07617 } else if (!strncasecmp(ast_channel_language(chan), "nl", 2)) {
07618 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' q 'digits/nl-om' HM", NULL);
07619 } else if (!strncasecmp(ast_channel_language(chan), "no", 2)) {
07620 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' Q 'digits/at' HM", NULL);
07621 } else if (!strncasecmp(ast_channel_language(chan), "pl", 2)) {
07622 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' Q HM", NULL);
07623 } else if (!strncasecmp(ast_channel_language(chan), "pt_BR", 5)) {
07624 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);
07625 } else if (!strncasecmp(ast_channel_language(chan), "se", 2)) {
07626 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' dB 'digits/at' k 'and' M", NULL);
07627 } else if (!strncasecmp(ast_channel_language(chan), "zh", 2)) {
07628 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "qR 'vm-received'", NULL);
07629 } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) {
07630 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);
07631 } else {
07632 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' q 'digits/at' IMp", NULL);
07633 }
07634 #if 0
07635 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
07636 #endif
07637 return res;
07638 }
07639
07640
07641
07642 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback, int saycidnumber)
07643 {
07644 int res = 0;
07645 int i;
07646 char *callerid, *name;
07647 char prefile[PATH_MAX] = "";
07648
07649
07650
07651
07652
07653
07654
07655
07656 if ((cid == NULL)||(context == NULL))
07657 return res;
07658
07659
07660 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
07661 ast_callerid_parse(cid, &name, &callerid);
07662 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
07663
07664
07665 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
07666 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
07667 if ((strcmp(cidinternalcontexts[i], context) == 0))
07668 break;
07669 }
07670 if (i != MAX_NUM_CID_CONTEXTS){
07671 if (!res) {
07672 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
07673 if (!ast_strlen_zero(prefile)) {
07674
07675
07676 if (ast_fileexists(prefile, NULL, NULL) > 0) {
07677 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
07678 if (!callback)
07679 res = wait_file2(chan, vms, "vm-from");
07680 res = ast_stream_and_wait(chan, prefile, "");
07681 } else {
07682 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
07683
07684 if (!callback)
07685 res = wait_file2(chan, vms, "vm-from-extension");
07686 res = ast_say_digit_str(chan, callerid, "", ast_channel_language(chan));
07687 }
07688 }
07689 }
07690 } else if (!res) {
07691 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
07692
07693 if (!callback) {
07694
07695 snprintf(prefile, sizeof(prefile), "%s/recordings/callerids/%s", ast_config_AST_SPOOL_DIR, callerid);
07696 if (!saycidnumber && ast_fileexists(prefile, NULL, NULL) > 0) {
07697 ast_verb(3, "Playing recorded name for CID number '%s' - '%s'\n", callerid,prefile);
07698 wait_file2(chan, vms, "vm-from");
07699 res = ast_stream_and_wait(chan, prefile, "");
07700 ast_verb(3, "Played recorded name result '%d'\n", res);
07701 } else {
07702
07703 wait_file2(chan, vms, "vm-from-phonenumber");
07704 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, ast_channel_language(chan));
07705 }
07706 } else {
07707 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, ast_channel_language(chan));
07708 }
07709 }
07710 } else {
07711
07712 ast_debug(1, "VM-CID: From an unknown number\n");
07713
07714 res = wait_file2(chan, vms, "vm-unknown-caller");
07715 }
07716 return res;
07717 }
07718
07719 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
07720 {
07721 int res = 0;
07722 int durationm;
07723 int durations;
07724
07725 if (duration == NULL)
07726 return res;
07727
07728
07729 durations = atoi(duration);
07730 durationm = (durations / 60);
07731
07732 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
07733
07734 if ((!res) && (durationm >= minduration)) {
07735 res = wait_file2(chan, vms, "vm-duration");
07736
07737
07738 if (!strncasecmp(ast_channel_language(chan), "pl", 2)) {
07739 div_t num = div(durationm, 10);
07740
07741 if (durationm == 1) {
07742 res = ast_play_and_wait(chan, "digits/1z");
07743 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
07744 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
07745 if (num.rem == 2) {
07746 if (!num.quot) {
07747 res = ast_play_and_wait(chan, "digits/2-ie");
07748 } else {
07749 res = say_and_wait(chan, durationm - 2 , ast_channel_language(chan));
07750 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
07751 }
07752 } else {
07753 res = say_and_wait(chan, durationm, ast_channel_language(chan));
07754 }
07755 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
07756 } else {
07757 res = say_and_wait(chan, durationm, ast_channel_language(chan));
07758 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
07759 }
07760
07761 } else {
07762 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, ast_channel_language(chan), NULL);
07763 res = wait_file2(chan, vms, "vm-minutes");
07764 }
07765 }
07766 return res;
07767 }
07768
07769 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
07770 {
07771 int res = 0;
07772 char filename[256], *cid;
07773 const char *origtime, *context, *category, *duration, *flag;
07774 struct ast_config *msg_cfg;
07775 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
07776
07777 vms->starting = 0;
07778 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07779 adsi_message(chan, vms);
07780 if (!vms->curmsg) {
07781 res = wait_file2(chan, vms, "vm-first");
07782 } else if (vms->curmsg == vms->lastmsg) {
07783 res = wait_file2(chan, vms, "vm-last");
07784 }
07785
07786 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
07787 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
07788 msg_cfg = ast_config_load(filename, config_flags);
07789 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
07790 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07791 return 0;
07792 }
07793 flag = ast_variable_retrieve(msg_cfg, "message", "flag");
07794
07795
07796 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
07797 res = wait_file2(chan, vms, "vm-Urgent");
07798 }
07799
07800 if (!res) {
07801
07802
07803 if (!strncasecmp(ast_channel_language(chan), "pl", 2)) {
07804 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07805 int ten, one;
07806 char nextmsg[256];
07807 ten = (vms->curmsg + 1) / 10;
07808 one = (vms->curmsg + 1) % 10;
07809
07810 if (vms->curmsg < 20) {
07811 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
07812 res = wait_file2(chan, vms, nextmsg);
07813 } else {
07814 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
07815 res = wait_file2(chan, vms, nextmsg);
07816 if (one > 0) {
07817 if (!res) {
07818 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
07819 res = wait_file2(chan, vms, nextmsg);
07820 }
07821 }
07822 }
07823 }
07824 if (!res)
07825 res = wait_file2(chan, vms, "vm-message");
07826
07827 } else if (!strncasecmp(ast_channel_language(chan), "he", 2)) {
07828 if (!vms->curmsg) {
07829 res = wait_file2(chan, vms, "vm-message");
07830 res = wait_file2(chan, vms, "vm-first");
07831 } else if (vms->curmsg == vms->lastmsg) {
07832 res = wait_file2(chan, vms, "vm-message");
07833 res = wait_file2(chan, vms, "vm-last");
07834 } else {
07835 res = wait_file2(chan, vms, "vm-message");
07836 res = wait_file2(chan, vms, "vm-number");
07837 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, ast_channel_language(chan), "f");
07838 }
07839
07840 } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) {
07841 if (!vms->curmsg) {
07842 res = wait_file2(chan, vms, "vm-message");
07843 res = wait_file2(chan, vms, "vm-first");
07844 } else if (vms->curmsg == vms->lastmsg) {
07845 res = wait_file2(chan, vms, "vm-message");
07846 res = wait_file2(chan, vms, "vm-last");
07847 } else {
07848 res = wait_file2(chan, vms, "vm-message");
07849 res = wait_file2(chan, vms, "vm-number");
07850 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, ast_channel_language(chan), "f");
07851 }
07852 } else {
07853 if (!strncasecmp(ast_channel_language(chan), "se", 2)) {
07854 res = wait_file2(chan, vms, "vm-meddelandet");
07855 } else {
07856 res = wait_file2(chan, vms, "vm-message");
07857 }
07858 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07859 if (!res) {
07860 ast_test_suite_event_notify("PLAYBACK", "Message: message number");
07861 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, ast_channel_language(chan), NULL);
07862 }
07863 }
07864 }
07865 }
07866
07867 if (!msg_cfg) {
07868 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07869 return 0;
07870 }
07871
07872 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
07873 ast_log(AST_LOG_WARNING, "No origtime?!\n");
07874 DISPOSE(vms->curdir, vms->curmsg);
07875 ast_config_destroy(msg_cfg);
07876 return 0;
07877 }
07878
07879 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
07880 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
07881 category = ast_variable_retrieve(msg_cfg, "message", "category");
07882
07883 context = ast_variable_retrieve(msg_cfg, "message", "context");
07884 if (!strncasecmp("macro", context, 5))
07885 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
07886 if (!res) {
07887 res = play_message_category(chan, category);
07888 }
07889 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE))) {
07890 res = play_message_datetime(chan, vmu, origtime, filename);
07891 }
07892 if ((!res) && (ast_test_flag(vmu, VM_SAYCID))) {
07893 res = play_message_callerid(chan, vms, cid, context, 0, 0);
07894 }
07895 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION))) {
07896 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
07897 }
07898
07899 if (res == '1') {
07900 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07901 res = 0;
07902 }
07903 ast_config_destroy(msg_cfg);
07904
07905 if (!res) {
07906 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07907 vms->heard[vms->curmsg] = 1;
07908 #ifdef IMAP_STORAGE
07909
07910
07911
07912 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
07913 wait_file(chan, vms, vms->introfn);
07914 }
07915 #endif
07916 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
07917 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
07918 res = 0;
07919 }
07920 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07921 }
07922 DISPOSE(vms->curdir, vms->curmsg);
07923 return res;
07924 }
07925
07926 #ifdef IMAP_STORAGE
07927 static int imap_remove_file(char *dir, int msgnum)
07928 {
07929 char fn[PATH_MAX];
07930 char full_fn[PATH_MAX];
07931 char intro[PATH_MAX] = {0,};
07932
07933 if (msgnum > -1) {
07934 make_file(fn, sizeof(fn), dir, msgnum);
07935 snprintf(intro, sizeof(intro), "%sintro", fn);
07936 } else
07937 ast_copy_string(fn, dir, sizeof(fn));
07938
07939 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
07940 ast_filedelete(fn, NULL);
07941 if (!ast_strlen_zero(intro)) {
07942 ast_filedelete(intro, NULL);
07943 }
07944 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
07945 unlink(full_fn);
07946 }
07947 return 0;
07948 }
07949
07950
07951
07952 static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
07953 {
07954 char *file, *filename;
07955 char *attachment;
07956 char arg[10];
07957 int i;
07958 BODY* body;
07959
07960 file = strrchr(ast_strdupa(dir), '/');
07961 if (file) {
07962 *file++ = '\0';
07963 } else {
07964 ast_log(AST_LOG_ERROR, "Failed to procure file name from directory passed. You should never see this.\n");
07965 return -1;
07966 }
07967
07968 ast_mutex_lock(&vms->lock);
07969 for (i = 0; i < vms->mailstream->nmsgs; i++) {
07970 mail_fetchstructure(vms->mailstream, i + 1, &body);
07971
07972 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
07973 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
07974 } else {
07975 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
07976 ast_mutex_unlock(&vms->lock);
07977 return -1;
07978 }
07979 filename = strsep(&attachment, ".");
07980 if (!strcmp(filename, file)) {
07981 sprintf(arg, "%d", i + 1);
07982 mail_setflag(vms->mailstream, arg, "\\DELETED");
07983 }
07984 }
07985 mail_expunge(vms->mailstream);
07986 ast_mutex_unlock(&vms->lock);
07987 return 0;
07988 }
07989
07990 #elif !defined(IMAP_STORAGE)
07991 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
07992 {
07993 int count_msg, last_msg;
07994
07995 ast_copy_string(vms->curbox, mbox(vmu, box), sizeof(vms->curbox));
07996
07997
07998
07999
08000 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
08001
08002
08003 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
08004
08005
08006 count_msg = count_messages(vmu, vms->curdir);
08007 if (count_msg < 0) {
08008 return count_msg;
08009 } else {
08010 vms->lastmsg = count_msg - 1;
08011 }
08012
08013 if (vm_allocate_dh(vms, vmu, count_msg)) {
08014 return -1;
08015 }
08016
08017
08018
08019
08020
08021
08022
08023
08024 if (vm_lock_path(vms->curdir)) {
08025 ast_log(AST_LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
08026 return ERROR_LOCK_PATH;
08027 }
08028
08029
08030 last_msg = last_message_index(vmu, vms->curdir);
08031 ast_unlock_path(vms->curdir);
08032
08033 if (last_msg < -1) {
08034 return last_msg;
08035 } else if (vms->lastmsg != last_msg) {
08036 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);
08037 resequence_mailbox(vmu, vms->curdir, count_msg);
08038 }
08039
08040 return 0;
08041 }
08042 #endif
08043
08044 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
08045 {
08046 int x = 0;
08047
08048 #ifndef IMAP_STORAGE
08049 int last_msg_idx;
08050 int res = 0, nummsg;
08051 char fn2[PATH_MAX];
08052 #endif
08053
08054 if (vms->lastmsg <= -1) {
08055 goto done;
08056 }
08057
08058 vms->curmsg = -1;
08059 #ifndef IMAP_STORAGE
08060
08061 if (vm_lock_path(vms->curdir)) {
08062 return ERROR_LOCK_PATH;
08063 }
08064
08065
08066 last_msg_idx = last_message_index(vmu, vms->curdir);
08067 if (last_msg_idx != vms->lastmsg) {
08068 ast_log(AST_LOG_NOTICE, "%d messages received after mailbox opened.\n", last_msg_idx - vms->lastmsg);
08069 }
08070
08071
08072 for (x = 0; x < last_msg_idx + 1; x++) {
08073 if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
08074
08075 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08076 if (!EXISTS(vms->curdir, x, vms->fn, NULL)) {
08077 break;
08078 }
08079 vms->curmsg++;
08080 make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
08081 if (strcmp(vms->fn, fn2)) {
08082 RENAME(vms->curdir, x, vmu->mailbox, vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
08083 }
08084 } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
08085
08086 res = save_to_folder(vmu, vms, x, 1);
08087 if (res == ERROR_LOCK_PATH) {
08088
08089 ast_log(AST_LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
08090 vms->deleted[x] = 0;
08091 vms->heard[x] = 0;
08092 --x;
08093 }
08094 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
08095
08096 res = save_to_folder(vmu, vms, x, 10);
08097 if (res == ERROR_LOCK_PATH) {
08098
08099 vms->deleted[x] = 0;
08100 vms->heard[x] = 0;
08101 --x;
08102 }
08103 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
08104
08105
08106 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08107 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08108 DELETE(vms->curdir, x, vms->fn, vmu);
08109 }
08110 }
08111 }
08112
08113
08114 nummsg = x - 1;
08115 for (x = vms->curmsg + 1; x <= nummsg; x++) {
08116 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08117 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08118 DELETE(vms->curdir, x, vms->fn, vmu);
08119 }
08120 }
08121 ast_unlock_path(vms->curdir);
08122 #else
08123 if (vms->deleted) {
08124
08125
08126 for (x = vms->dh_arraysize - 1; x >= 0; x--) {
08127 if (vms->deleted[x]) {
08128 ast_debug(3, "IMAP delete of %d\n", x);
08129 DELETE(vms->curdir, x, vms->fn, vmu);
08130 }
08131 }
08132 }
08133 #endif
08134
08135 done:
08136 if (vms->deleted) {
08137 ast_free(vms->deleted);
08138 }
08139 if (vms->heard) {
08140 ast_free(vms->heard);
08141 }
08142
08143 return 0;
08144 }
08145
08146
08147
08148
08149
08150
08151
08152 static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
08153 {
08154 int cmd;
08155 char *buf;
08156
08157 buf = alloca(strlen(box) + 2);
08158 strcpy(buf, box);
08159 strcat(buf, "s");
08160
08161 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
08162 cmd = ast_play_and_wait(chan, buf);
08163 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08164 } else {
08165 cmd = ast_play_and_wait(chan, "vm-messages");
08166 return cmd ? cmd : ast_play_and_wait(chan, box);
08167 }
08168 }
08169
08170 static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
08171 {
08172 int cmd;
08173
08174 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
08175 if (!strcasecmp(box, "vm-INBOX"))
08176 cmd = ast_play_and_wait(chan, "vm-new-e");
08177 else
08178 cmd = ast_play_and_wait(chan, "vm-old-e");
08179 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08180 } else {
08181 cmd = ast_play_and_wait(chan, "vm-messages");
08182 return cmd ? cmd : ast_play_and_wait(chan, box);
08183 }
08184 }
08185
08186 static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
08187 {
08188 int cmd;
08189
08190 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
08191 cmd = ast_play_and_wait(chan, "vm-messages");
08192 return cmd ? cmd : ast_play_and_wait(chan, box);
08193 } else {
08194 cmd = ast_play_and_wait(chan, box);
08195 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08196 }
08197 }
08198
08199 static int vm_play_folder_name(struct ast_channel *chan, char *box)
08200 {
08201 int cmd;
08202
08203 if ( !strncasecmp(ast_channel_language(chan), "it", 2) ||
08204 !strncasecmp(ast_channel_language(chan), "es", 2) ||
08205 !strncasecmp(ast_channel_language(chan), "pt", 2)) {
08206 cmd = ast_play_and_wait(chan, "vm-messages");
08207 return cmd ? cmd : ast_play_and_wait(chan, box);
08208 } else if (!strncasecmp(ast_channel_language(chan), "gr", 2)) {
08209 return vm_play_folder_name_gr(chan, box);
08210 } else if (!strncasecmp(ast_channel_language(chan), "he", 2)) {
08211 return ast_play_and_wait(chan, box);
08212 } else if (!strncasecmp(ast_channel_language(chan), "pl", 2)) {
08213 return vm_play_folder_name_pl(chan, box);
08214 } else if (!strncasecmp(ast_channel_language(chan), "ua", 2)) {
08215 return vm_play_folder_name_ua(chan, box);
08216 } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) {
08217 return ast_play_and_wait(chan, box);
08218 } else {
08219 cmd = ast_play_and_wait(chan, box);
08220 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08221 }
08222 }
08223
08224
08225
08226
08227
08228
08229
08230
08231
08232
08233
08234
08235
08236 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
08237 {
08238 int res = 0;
08239
08240 if (vms->newmessages) {
08241 res = ast_play_and_wait(chan, "vm-youhave");
08242 if (!res)
08243 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, ast_channel_language(chan), NULL);
08244 if (!res) {
08245 if ((vms->newmessages == 1)) {
08246 res = ast_play_and_wait(chan, "vm-INBOX");
08247 if (!res)
08248 res = ast_play_and_wait(chan, "vm-message");
08249 } else {
08250 res = ast_play_and_wait(chan, "vm-INBOXs");
08251 if (!res)
08252 res = ast_play_and_wait(chan, "vm-messages");
08253 }
08254 }
08255 } else if (vms->oldmessages){
08256 res = ast_play_and_wait(chan, "vm-youhave");
08257 if (!res)
08258 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan), NULL);
08259 if ((vms->oldmessages == 1)){
08260 res = ast_play_and_wait(chan, "vm-Old");
08261 if (!res)
08262 res = ast_play_and_wait(chan, "vm-message");
08263 } else {
08264 res = ast_play_and_wait(chan, "vm-Olds");
08265 if (!res)
08266 res = ast_play_and_wait(chan, "vm-messages");
08267 }
08268 } else if (!vms->oldmessages && !vms->newmessages)
08269 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
08270 return res;
08271 }
08272
08273
08274
08275
08276
08277
08278
08279
08280
08281
08282
08283
08284
08285
08286
08287
08288
08289
08290
08291
08292
08293
08294
08295
08296
08297
08298
08299
08300
08301
08302
08303
08304
08305
08306
08307
08308
08309
08310
08311
08312
08313
08314
08315
08316
08317
08318
08319
08320
08321
08322
08323
08324
08325
08326
08327
08328
08329
08330 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
08331 {
08332 int res;
08333 int lastnum = 0;
08334
08335 res = ast_play_and_wait(chan, "vm-youhave");
08336
08337 if (!res && vms->newmessages) {
08338 lastnum = vms->newmessages;
08339
08340 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, ast_channel_language(chan), message_gender))) {
08341 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
08342 }
08343
08344 if (!res && vms->oldmessages) {
08345 res = ast_play_and_wait(chan, "vm-and");
08346 }
08347 }
08348
08349 if (!res && vms->oldmessages) {
08350 lastnum = vms->oldmessages;
08351
08352 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, ast_channel_language(chan), message_gender))) {
08353 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
08354 }
08355 }
08356
08357 if (!res) {
08358 if (lastnum == 0) {
08359 res = ast_play_and_wait(chan, "vm-no");
08360 }
08361 if (!res) {
08362 res = ast_say_counted_noun(chan, lastnum, "vm-message");
08363 }
08364 }
08365
08366 return res;
08367 }
08368
08369
08370 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
08371 {
08372 int res = 0;
08373
08374
08375 if (!res) {
08376 if ((vms->newmessages) || (vms->oldmessages)) {
08377 res = ast_play_and_wait(chan, "vm-youhave");
08378 }
08379
08380
08381
08382
08383
08384 if (vms->newmessages) {
08385 if (!res) {
08386 if (vms->newmessages == 1) {
08387 res = ast_play_and_wait(chan, "vm-INBOX1");
08388 } else {
08389 if (vms->newmessages == 2) {
08390 res = ast_play_and_wait(chan, "vm-shtei");
08391 } else {
08392 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
08393 }
08394 res = ast_play_and_wait(chan, "vm-INBOX");
08395 }
08396 }
08397 if (vms->oldmessages && !res) {
08398 res = ast_play_and_wait(chan, "vm-and");
08399 if (vms->oldmessages == 1) {
08400 res = ast_play_and_wait(chan, "vm-Old1");
08401 } else {
08402 if (vms->oldmessages == 2) {
08403 res = ast_play_and_wait(chan, "vm-shtei");
08404 } else {
08405 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
08406 }
08407 res = ast_play_and_wait(chan, "vm-Old");
08408 }
08409 }
08410 }
08411 if (!res && vms->oldmessages && !vms->newmessages) {
08412 if (!res) {
08413 if (vms->oldmessages == 1) {
08414 res = ast_play_and_wait(chan, "vm-Old1");
08415 } else {
08416 if (vms->oldmessages == 2) {
08417 res = ast_play_and_wait(chan, "vm-shtei");
08418 } else {
08419 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
08420 }
08421 res = ast_play_and_wait(chan, "vm-Old");
08422 }
08423 }
08424 }
08425 if (!res) {
08426 if (!vms->oldmessages && !vms->newmessages) {
08427 if (!res) {
08428 res = ast_play_and_wait(chan, "vm-nomessages");
08429 }
08430 }
08431 }
08432 }
08433 return res;
08434 }
08435
08436
08437 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
08438 {
08439 int res;
08440
08441
08442 res = ast_play_and_wait(chan, "vm-youhave");
08443 if (!res) {
08444 if (vms->urgentmessages) {
08445 res = say_and_wait(chan, vms->urgentmessages, ast_channel_language(chan));
08446 if (!res)
08447 res = ast_play_and_wait(chan, "vm-Urgent");
08448 if ((vms->oldmessages || vms->newmessages) && !res) {
08449 res = ast_play_and_wait(chan, "vm-and");
08450 } else if (!res) {
08451 if ((vms->urgentmessages == 1))
08452 res = ast_play_and_wait(chan, "vm-message");
08453 else
08454 res = ast_play_and_wait(chan, "vm-messages");
08455 }
08456 }
08457 if (vms->newmessages) {
08458 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
08459 if (!res)
08460 res = ast_play_and_wait(chan, "vm-INBOX");
08461 if (vms->oldmessages && !res)
08462 res = ast_play_and_wait(chan, "vm-and");
08463 else if (!res) {
08464 if ((vms->newmessages == 1))
08465 res = ast_play_and_wait(chan, "vm-message");
08466 else
08467 res = ast_play_and_wait(chan, "vm-messages");
08468 }
08469
08470 }
08471 if (!res && vms->oldmessages) {
08472 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
08473 if (!res)
08474 res = ast_play_and_wait(chan, "vm-Old");
08475 if (!res) {
08476 if (vms->oldmessages == 1)
08477 res = ast_play_and_wait(chan, "vm-message");
08478 else
08479 res = ast_play_and_wait(chan, "vm-messages");
08480 }
08481 }
08482 if (!res) {
08483 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
08484 res = ast_play_and_wait(chan, "vm-no");
08485 if (!res)
08486 res = ast_play_and_wait(chan, "vm-messages");
08487 }
08488 }
08489 }
08490 return res;
08491 }
08492
08493
08494 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
08495 {
08496
08497 int res;
08498 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
08499 res = ast_play_and_wait(chan, "vm-no") ||
08500 ast_play_and_wait(chan, "vm-message");
08501 else
08502 res = ast_play_and_wait(chan, "vm-youhave");
08503 if (!res && vms->newmessages) {
08504 res = (vms->newmessages == 1) ?
08505 ast_play_and_wait(chan, "digits/un") ||
08506 ast_play_and_wait(chan, "vm-nuovo") ||
08507 ast_play_and_wait(chan, "vm-message") :
08508
08509 say_and_wait(chan, vms->newmessages, ast_channel_language(chan)) ||
08510 ast_play_and_wait(chan, "vm-nuovi") ||
08511 ast_play_and_wait(chan, "vm-messages");
08512 if (!res && vms->oldmessages)
08513 res = ast_play_and_wait(chan, "vm-and");
08514 }
08515 if (!res && vms->oldmessages) {
08516 res = (vms->oldmessages == 1) ?
08517 ast_play_and_wait(chan, "digits/un") ||
08518 ast_play_and_wait(chan, "vm-vecchio") ||
08519 ast_play_and_wait(chan, "vm-message") :
08520
08521 say_and_wait(chan, vms->oldmessages, ast_channel_language(chan)) ||
08522 ast_play_and_wait(chan, "vm-vecchi") ||
08523 ast_play_and_wait(chan, "vm-messages");
08524 }
08525 return res;
08526 }
08527
08528
08529 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
08530 {
08531
08532 int res;
08533 div_t num;
08534
08535 if (!vms->oldmessages && !vms->newmessages) {
08536 res = ast_play_and_wait(chan, "vm-no");
08537 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08538 return res;
08539 } else {
08540 res = ast_play_and_wait(chan, "vm-youhave");
08541 }
08542
08543 if (vms->newmessages) {
08544 num = div(vms->newmessages, 10);
08545 if (vms->newmessages == 1) {
08546 res = ast_play_and_wait(chan, "digits/1-a");
08547 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
08548 res = res ? res : ast_play_and_wait(chan, "vm-message");
08549 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08550 if (num.rem == 2) {
08551 if (!num.quot) {
08552 res = ast_play_and_wait(chan, "digits/2-ie");
08553 } else {
08554 res = say_and_wait(chan, vms->newmessages - 2 , ast_channel_language(chan));
08555 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08556 }
08557 } else {
08558 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
08559 }
08560 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
08561 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08562 } else {
08563 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
08564 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
08565 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08566 }
08567 if (!res && vms->oldmessages)
08568 res = ast_play_and_wait(chan, "vm-and");
08569 }
08570 if (!res && vms->oldmessages) {
08571 num = div(vms->oldmessages, 10);
08572 if (vms->oldmessages == 1) {
08573 res = ast_play_and_wait(chan, "digits/1-a");
08574 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
08575 res = res ? res : ast_play_and_wait(chan, "vm-message");
08576 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08577 if (num.rem == 2) {
08578 if (!num.quot) {
08579 res = ast_play_and_wait(chan, "digits/2-ie");
08580 } else {
08581 res = say_and_wait(chan, vms->oldmessages - 2 , ast_channel_language(chan));
08582 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08583 }
08584 } else {
08585 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
08586 }
08587 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
08588 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08589 } else {
08590 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
08591 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
08592 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08593 }
08594 }
08595
08596 return res;
08597 }
08598
08599
08600 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
08601 {
08602
08603 int res;
08604
08605 res = ast_play_and_wait(chan, "vm-youhave");
08606 if (res)
08607 return res;
08608
08609 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08610 res = ast_play_and_wait(chan, "vm-no");
08611 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08612 return res;
08613 }
08614
08615 if (vms->newmessages) {
08616 if ((vms->newmessages == 1)) {
08617 res = ast_play_and_wait(chan, "digits/ett");
08618 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
08619 res = res ? res : ast_play_and_wait(chan, "vm-message");
08620 } else {
08621 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
08622 res = res ? res : ast_play_and_wait(chan, "vm-nya");
08623 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08624 }
08625 if (!res && vms->oldmessages)
08626 res = ast_play_and_wait(chan, "vm-and");
08627 }
08628 if (!res && vms->oldmessages) {
08629 if (vms->oldmessages == 1) {
08630 res = ast_play_and_wait(chan, "digits/ett");
08631 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
08632 res = res ? res : ast_play_and_wait(chan, "vm-message");
08633 } else {
08634 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
08635 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
08636 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08637 }
08638 }
08639
08640 return res;
08641 }
08642
08643
08644 static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
08645 {
08646
08647 int res;
08648
08649 res = ast_play_and_wait(chan, "vm-youhave");
08650 if (res)
08651 return res;
08652
08653 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08654 res = ast_play_and_wait(chan, "vm-no");
08655 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08656 return res;
08657 }
08658
08659 if (vms->newmessages) {
08660 if ((vms->newmessages == 1)) {
08661 res = ast_play_and_wait(chan, "digits/1");
08662 res = res ? res : ast_play_and_wait(chan, "vm-ny");
08663 res = res ? res : ast_play_and_wait(chan, "vm-message");
08664 } else {
08665 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
08666 res = res ? res : ast_play_and_wait(chan, "vm-nye");
08667 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08668 }
08669 if (!res && vms->oldmessages)
08670 res = ast_play_and_wait(chan, "vm-and");
08671 }
08672 if (!res && vms->oldmessages) {
08673 if (vms->oldmessages == 1) {
08674 res = ast_play_and_wait(chan, "digits/1");
08675 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
08676 res = res ? res : ast_play_and_wait(chan, "vm-message");
08677 } else {
08678 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
08679 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
08680 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08681 }
08682 }
08683
08684 return res;
08685 }
08686
08687
08688 static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
08689 {
08690
08691 int res;
08692 res = ast_play_and_wait(chan, "vm-youhave");
08693 if (!res) {
08694 if (vms->newmessages) {
08695 if ((vms->newmessages == 1))
08696 res = ast_play_and_wait(chan, "digits/1F");
08697 else
08698 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
08699 if (!res)
08700 res = ast_play_and_wait(chan, "vm-INBOX");
08701 if (vms->oldmessages && !res)
08702 res = ast_play_and_wait(chan, "vm-and");
08703 else if (!res) {
08704 if ((vms->newmessages == 1))
08705 res = ast_play_and_wait(chan, "vm-message");
08706 else
08707 res = ast_play_and_wait(chan, "vm-messages");
08708 }
08709
08710 }
08711 if (!res && vms->oldmessages) {
08712 if (vms->oldmessages == 1)
08713 res = ast_play_and_wait(chan, "digits/1F");
08714 else
08715 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
08716 if (!res)
08717 res = ast_play_and_wait(chan, "vm-Old");
08718 if (!res) {
08719 if (vms->oldmessages == 1)
08720 res = ast_play_and_wait(chan, "vm-message");
08721 else
08722 res = ast_play_and_wait(chan, "vm-messages");
08723 }
08724 }
08725 if (!res) {
08726 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08727 res = ast_play_and_wait(chan, "vm-no");
08728 if (!res)
08729 res = ast_play_and_wait(chan, "vm-messages");
08730 }
08731 }
08732 }
08733 return res;
08734 }
08735
08736
08737 static int vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
08738 {
08739
08740 int res;
08741 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08742 res = ast_play_and_wait(chan, "vm-youhaveno");
08743 if (!res)
08744 res = ast_play_and_wait(chan, "vm-messages");
08745 } else {
08746 res = ast_play_and_wait(chan, "vm-youhave");
08747 }
08748 if (!res) {
08749 if (vms->newmessages) {
08750 if (!res) {
08751 if ((vms->newmessages == 1)) {
08752 res = ast_play_and_wait(chan, "digits/1M");
08753 if (!res)
08754 res = ast_play_and_wait(chan, "vm-message");
08755 if (!res)
08756 res = ast_play_and_wait(chan, "vm-INBOXs");
08757 } else {
08758 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
08759 if (!res)
08760 res = ast_play_and_wait(chan, "vm-messages");
08761 if (!res)
08762 res = ast_play_and_wait(chan, "vm-INBOX");
08763 }
08764 }
08765 if (vms->oldmessages && !res)
08766 res = ast_play_and_wait(chan, "vm-and");
08767 }
08768 if (vms->oldmessages) {
08769 if (!res) {
08770 if (vms->oldmessages == 1) {
08771 res = ast_play_and_wait(chan, "digits/1M");
08772 if (!res)
08773 res = ast_play_and_wait(chan, "vm-message");
08774 if (!res)
08775 res = ast_play_and_wait(chan, "vm-Olds");
08776 } else {
08777 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
08778 if (!res)
08779 res = ast_play_and_wait(chan, "vm-messages");
08780 if (!res)
08781 res = ast_play_and_wait(chan, "vm-Old");
08782 }
08783 }
08784 }
08785 }
08786 return res;
08787 }
08788
08789
08790 static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms) {
08791
08792 int res;
08793 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08794 res = ast_play_and_wait(chan, "vm-nomessages");
08795 return res;
08796 } else {
08797 res = ast_play_and_wait(chan, "vm-youhave");
08798 }
08799 if (vms->newmessages) {
08800 if (!res)
08801 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
08802 if ((vms->newmessages == 1)) {
08803 if (!res)
08804 res = ast_play_and_wait(chan, "vm-message");
08805 if (!res)
08806 res = ast_play_and_wait(chan, "vm-INBOXs");
08807 } else {
08808 if (!res)
08809 res = ast_play_and_wait(chan, "vm-messages");
08810 if (!res)
08811 res = ast_play_and_wait(chan, "vm-INBOX");
08812 }
08813 if (vms->oldmessages && !res)
08814 res = ast_play_and_wait(chan, "vm-and");
08815 }
08816 if (vms->oldmessages) {
08817 if (!res)
08818 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
08819 if (vms->oldmessages == 1) {
08820 if (!res)
08821 res = ast_play_and_wait(chan, "vm-message");
08822 if (!res)
08823 res = ast_play_and_wait(chan, "vm-Olds");
08824 } else {
08825 if (!res)
08826 res = ast_play_and_wait(chan, "vm-messages");
08827 if (!res)
08828 res = ast_play_and_wait(chan, "vm-Old");
08829 }
08830 }
08831 return res;
08832 }
08833
08834
08835 static int vm_intro_fr(struct ast_channel *chan, struct vm_state *vms)
08836 {
08837
08838 int res;
08839 res = ast_play_and_wait(chan, "vm-youhave");
08840 if (!res) {
08841 if (vms->newmessages) {
08842 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
08843 if (!res)
08844 res = ast_play_and_wait(chan, "vm-INBOX");
08845 if (vms->oldmessages && !res)
08846 res = ast_play_and_wait(chan, "vm-and");
08847 else if (!res) {
08848 if ((vms->newmessages == 1))
08849 res = ast_play_and_wait(chan, "vm-message");
08850 else
08851 res = ast_play_and_wait(chan, "vm-messages");
08852 }
08853
08854 }
08855 if (!res && vms->oldmessages) {
08856 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
08857 if (!res)
08858 res = ast_play_and_wait(chan, "vm-Old");
08859 if (!res) {
08860 if (vms->oldmessages == 1)
08861 res = ast_play_and_wait(chan, "vm-message");
08862 else
08863 res = ast_play_and_wait(chan, "vm-messages");
08864 }
08865 }
08866 if (!res) {
08867 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08868 res = ast_play_and_wait(chan, "vm-no");
08869 if (!res)
08870 res = ast_play_and_wait(chan, "vm-messages");
08871 }
08872 }
08873 }
08874 return res;
08875 }
08876
08877
08878 static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
08879 {
08880
08881 int res;
08882 res = ast_play_and_wait(chan, "vm-youhave");
08883 if (!res) {
08884 if (vms->newmessages) {
08885 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
08886 if (!res) {
08887 if (vms->newmessages == 1)
08888 res = ast_play_and_wait(chan, "vm-INBOXs");
08889 else
08890 res = ast_play_and_wait(chan, "vm-INBOX");
08891 }
08892 if (vms->oldmessages && !res)
08893 res = ast_play_and_wait(chan, "vm-and");
08894 else if (!res) {
08895 if ((vms->newmessages == 1))
08896 res = ast_play_and_wait(chan, "vm-message");
08897 else
08898 res = ast_play_and_wait(chan, "vm-messages");
08899 }
08900
08901 }
08902 if (!res && vms->oldmessages) {
08903 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
08904 if (!res) {
08905 if (vms->oldmessages == 1)
08906 res = ast_play_and_wait(chan, "vm-Olds");
08907 else
08908 res = ast_play_and_wait(chan, "vm-Old");
08909 }
08910 if (!res) {
08911 if (vms->oldmessages == 1)
08912 res = ast_play_and_wait(chan, "vm-message");
08913 else
08914 res = ast_play_and_wait(chan, "vm-messages");
08915 }
08916 }
08917 if (!res) {
08918 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08919 res = ast_play_and_wait(chan, "vm-no");
08920 if (!res)
08921 res = ast_play_and_wait(chan, "vm-messages");
08922 }
08923 }
08924 }
08925 return res;
08926 }
08927
08928
08929 static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
08930 {
08931
08932 int res;
08933 res = ast_play_and_wait(chan, "vm-youhave");
08934 if (!res) {
08935 if (vms->newmessages) {
08936 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
08937 if (!res) {
08938 if ((vms->newmessages == 1)) {
08939 res = ast_play_and_wait(chan, "vm-message");
08940 if (!res)
08941 res = ast_play_and_wait(chan, "vm-INBOXs");
08942 } else {
08943 res = ast_play_and_wait(chan, "vm-messages");
08944 if (!res)
08945 res = ast_play_and_wait(chan, "vm-INBOX");
08946 }
08947 }
08948 if (vms->oldmessages && !res)
08949 res = ast_play_and_wait(chan, "vm-and");
08950 }
08951 if (!res && vms->oldmessages) {
08952 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
08953 if (!res) {
08954 if (vms->oldmessages == 1) {
08955 res = ast_play_and_wait(chan, "vm-message");
08956 if (!res)
08957 res = ast_play_and_wait(chan, "vm-Olds");
08958 } else {
08959 res = ast_play_and_wait(chan, "vm-messages");
08960 if (!res)
08961 res = ast_play_and_wait(chan, "vm-Old");
08962 }
08963 }
08964 }
08965 if (!res) {
08966 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08967 res = ast_play_and_wait(chan, "vm-no");
08968 if (!res)
08969 res = ast_play_and_wait(chan, "vm-messages");
08970 }
08971 }
08972 }
08973 return res;
08974 }
08975
08976
08977
08978
08979
08980
08981
08982
08983
08984
08985
08986
08987
08988
08989
08990
08991
08992 static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
08993 {
08994 int res;
08995 res = ast_play_and_wait(chan, "vm-youhave");
08996 if (!res) {
08997 if (vms->newmessages) {
08998 if (vms->newmessages == 1) {
08999 res = ast_play_and_wait(chan, "digits/jednu");
09000 } else {
09001 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
09002 }
09003 if (!res) {
09004 if ((vms->newmessages == 1))
09005 res = ast_play_and_wait(chan, "vm-novou");
09006 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
09007 res = ast_play_and_wait(chan, "vm-nove");
09008 if (vms->newmessages > 4)
09009 res = ast_play_and_wait(chan, "vm-novych");
09010 }
09011 if (vms->oldmessages && !res)
09012 res = ast_play_and_wait(chan, "vm-and");
09013 else if (!res) {
09014 if ((vms->newmessages == 1))
09015 res = ast_play_and_wait(chan, "vm-zpravu");
09016 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
09017 res = ast_play_and_wait(chan, "vm-zpravy");
09018 if (vms->newmessages > 4)
09019 res = ast_play_and_wait(chan, "vm-zprav");
09020 }
09021 }
09022 if (!res && vms->oldmessages) {
09023 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
09024 if (!res) {
09025 if ((vms->oldmessages == 1))
09026 res = ast_play_and_wait(chan, "vm-starou");
09027 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
09028 res = ast_play_and_wait(chan, "vm-stare");
09029 if (vms->oldmessages > 4)
09030 res = ast_play_and_wait(chan, "vm-starych");
09031 }
09032 if (!res) {
09033 if ((vms->oldmessages == 1))
09034 res = ast_play_and_wait(chan, "vm-zpravu");
09035 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
09036 res = ast_play_and_wait(chan, "vm-zpravy");
09037 if (vms->oldmessages > 4)
09038 res = ast_play_and_wait(chan, "vm-zprav");
09039 }
09040 }
09041 if (!res) {
09042 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
09043 res = ast_play_and_wait(chan, "vm-no");
09044 if (!res)
09045 res = ast_play_and_wait(chan, "vm-zpravy");
09046 }
09047 }
09048 }
09049 return res;
09050 }
09051
09052
09053 static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
09054 {
09055 int res;
09056
09057 res = ast_play_and_wait(chan, "vm-you");
09058
09059 if (!res && vms->newmessages) {
09060 res = ast_play_and_wait(chan, "vm-have");
09061 if (!res)
09062 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
09063 if (!res)
09064 res = ast_play_and_wait(chan, "vm-tong");
09065 if (!res)
09066 res = ast_play_and_wait(chan, "vm-INBOX");
09067 if (vms->oldmessages && !res)
09068 res = ast_play_and_wait(chan, "vm-and");
09069 else if (!res)
09070 res = ast_play_and_wait(chan, "vm-messages");
09071 }
09072 if (!res && vms->oldmessages) {
09073 res = ast_play_and_wait(chan, "vm-have");
09074 if (!res)
09075 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
09076 if (!res)
09077 res = ast_play_and_wait(chan, "vm-tong");
09078 if (!res)
09079 res = ast_play_and_wait(chan, "vm-Old");
09080 if (!res)
09081 res = ast_play_and_wait(chan, "vm-messages");
09082 }
09083 if (!res && !vms->oldmessages && !vms->newmessages) {
09084 res = ast_play_and_wait(chan, "vm-haveno");
09085 if (!res)
09086 res = ast_play_and_wait(chan, "vm-messages");
09087 }
09088 return res;
09089 }
09090
09091
09092 static int vm_intro_vi(struct ast_channel *chan, struct vm_state *vms)
09093 {
09094 int res;
09095
09096
09097 res = ast_play_and_wait(chan, "vm-youhave");
09098 if (!res) {
09099 if (vms->newmessages) {
09100 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
09101 if (!res)
09102 res = ast_play_and_wait(chan, "vm-INBOX");
09103 if (vms->oldmessages && !res)
09104 res = ast_play_and_wait(chan, "vm-and");
09105 }
09106 if (!res && vms->oldmessages) {
09107 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
09108 if (!res)
09109 res = ast_play_and_wait(chan, "vm-Old");
09110 }
09111 if (!res) {
09112 if (!vms->oldmessages && !vms->newmessages) {
09113 res = ast_play_and_wait(chan, "vm-no");
09114 if (!res)
09115 res = ast_play_and_wait(chan, "vm-message");
09116 }
09117 }
09118 }
09119 return res;
09120 }
09121
09122 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
09123 {
09124 char prefile[256];
09125
09126
09127 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09128 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
09129 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09130 if (ast_fileexists(prefile, NULL, NULL) > 0) {
09131 ast_play_and_wait(chan, "vm-tempgreetactive");
09132 }
09133 DISPOSE(prefile, -1);
09134 }
09135
09136
09137 if (0) {
09138 return 0;
09139 } else if (!strncasecmp(ast_channel_language(chan), "cs", 2)) {
09140 return vm_intro_cs(chan, vms);
09141 } else if (!strncasecmp(ast_channel_language(chan), "cz", 2)) {
09142 static int deprecation_warning = 0;
09143 if (deprecation_warning++ % 10 == 0) {
09144 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
09145 }
09146 return vm_intro_cs(chan, vms);
09147 } else if (!strncasecmp(ast_channel_language(chan), "de", 2)) {
09148 return vm_intro_de(chan, vms);
09149 } else if (!strncasecmp(ast_channel_language(chan), "es", 2)) {
09150 return vm_intro_es(chan, vms);
09151 } else if (!strncasecmp(ast_channel_language(chan), "fr", 2)) {
09152 return vm_intro_fr(chan, vms);
09153 } else if (!strncasecmp(ast_channel_language(chan), "gr", 2)) {
09154 return vm_intro_gr(chan, vms);
09155 } else if (!strncasecmp(ast_channel_language(chan), "he", 2)) {
09156 return vm_intro_he(chan, vms);
09157 } else if (!strncasecmp(ast_channel_language(chan), "it", 2)) {
09158 return vm_intro_it(chan, vms);
09159 } else if (!strncasecmp(ast_channel_language(chan), "nl", 2)) {
09160 return vm_intro_nl(chan, vms);
09161 } else if (!strncasecmp(ast_channel_language(chan), "no", 2)) {
09162 return vm_intro_no(chan, vms);
09163 } else if (!strncasecmp(ast_channel_language(chan), "pl", 2)) {
09164 return vm_intro_pl(chan, vms);
09165 } else if (!strncasecmp(ast_channel_language(chan), "pt_BR", 5)) {
09166 return vm_intro_pt_BR(chan, vms);
09167 } else if (!strncasecmp(ast_channel_language(chan), "pt", 2)) {
09168 return vm_intro_pt(chan, vms);
09169 } else if (!strncasecmp(ast_channel_language(chan), "ru", 2)) {
09170 return vm_intro_multilang(chan, vms, "n");
09171 } else if (!strncasecmp(ast_channel_language(chan), "se", 2)) {
09172 return vm_intro_se(chan, vms);
09173 } else if (!strncasecmp(ast_channel_language(chan), "ua", 2)) {
09174 return vm_intro_multilang(chan, vms, "n");
09175 } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) {
09176 return vm_intro_vi(chan, vms);
09177 } else if (!strncasecmp(ast_channel_language(chan), "zh", 2)) {
09178 return vm_intro_zh(chan, vms);
09179 } else {
09180 return vm_intro_en(chan, vms);
09181 }
09182 }
09183
09184 static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09185 {
09186 int res = 0;
09187
09188 while (!res) {
09189 if (vms->starting) {
09190 if (vms->lastmsg > -1) {
09191 if (skipadvanced)
09192 res = ast_play_and_wait(chan, "vm-onefor-full");
09193 else
09194 res = ast_play_and_wait(chan, "vm-onefor");
09195 if (!res)
09196 res = vm_play_folder_name(chan, vms->vmbox);
09197 }
09198 if (!res) {
09199 if (skipadvanced)
09200 res = ast_play_and_wait(chan, "vm-opts-full");
09201 else
09202 res = ast_play_and_wait(chan, "vm-opts");
09203 }
09204 } else {
09205
09206 if (skipadvanced) {
09207 res = ast_play_and_wait(chan, "vm-onefor-full");
09208 if (!res)
09209 res = vm_play_folder_name(chan, vms->vmbox);
09210 res = ast_play_and_wait(chan, "vm-opts-full");
09211 }
09212
09213
09214
09215
09216
09217
09218 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
09219 res = ast_play_and_wait(chan, "vm-prev");
09220 }
09221 if (!res && !skipadvanced)
09222 res = ast_play_and_wait(chan, "vm-advopts");
09223 if (!res)
09224 res = ast_play_and_wait(chan, "vm-repeat");
09225
09226
09227
09228
09229
09230
09231 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
09232 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
09233 res = ast_play_and_wait(chan, "vm-next");
09234 }
09235 if (!res) {
09236 if (!vms->deleted[vms->curmsg])
09237 res = ast_play_and_wait(chan, "vm-delete");
09238 else
09239 res = ast_play_and_wait(chan, "vm-undelete");
09240 if (!res)
09241 res = ast_play_and_wait(chan, "vm-toforward");
09242 if (!res)
09243 res = ast_play_and_wait(chan, "vm-savemessage");
09244 }
09245 }
09246 if (!res) {
09247 res = ast_play_and_wait(chan, "vm-helpexit");
09248 }
09249 if (!res)
09250 res = ast_waitfordigit(chan, 6000);
09251 if (!res) {
09252 vms->repeats++;
09253 if (vms->repeats > 2) {
09254 res = 't';
09255 }
09256 }
09257 }
09258 return res;
09259 }
09260
09261 static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09262 {
09263 int res = 0;
09264
09265 while (!res) {
09266 if (vms->lastmsg > -1) {
09267 res = ast_play_and_wait(chan, "vm-listen");
09268 if (!res)
09269 res = vm_play_folder_name(chan, vms->vmbox);
09270 if (!res)
09271 res = ast_play_and_wait(chan, "press");
09272 if (!res)
09273 res = ast_play_and_wait(chan, "digits/1");
09274 }
09275 if (!res)
09276 res = ast_play_and_wait(chan, "vm-opts");
09277 if (!res) {
09278 vms->starting = 0;
09279 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09280 }
09281 }
09282 return res;
09283 }
09284
09285 static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09286 {
09287 if (vms->starting && !strncasecmp(ast_channel_language(chan), "zh", 2)) {
09288 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
09289 } else {
09290 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09291 }
09292 }
09293
09294
09295 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09296 {
09297 int cmd = 0;
09298 int duration = 0;
09299 int tries = 0;
09300 char newpassword[80] = "";
09301 char newpassword2[80] = "";
09302 char prefile[PATH_MAX] = "";
09303 unsigned char buf[256];
09304 int bytes = 0;
09305
09306 ast_test_suite_event_notify("NEWUSER", "Message: entering new user state");
09307 if (ast_adsi_available(chan)) {
09308 bytes += adsi_logo(buf + bytes);
09309 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
09310 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09311 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09312 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09313 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09314 }
09315
09316
09317 if (ast_test_flag(vmu, VM_FORCENAME)) {
09318 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09319 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09320 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09321 if (cmd < 0 || cmd == 't' || cmd == '#')
09322 return cmd;
09323 }
09324 }
09325
09326
09327 if (ast_test_flag(vmu, VM_FORCEGREET)) {
09328 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09329 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09330 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09331 if (cmd < 0 || cmd == 't' || cmd == '#')
09332 return cmd;
09333 }
09334
09335 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09336 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09337 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09338 if (cmd < 0 || cmd == 't' || cmd == '#')
09339 return cmd;
09340 }
09341 }
09342
09343
09344
09345
09346
09347 for (;;) {
09348 newpassword[1] = '\0';
09349 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09350 if (cmd == '#')
09351 newpassword[0] = '\0';
09352 if (cmd < 0 || cmd == 't' || cmd == '#')
09353 return cmd;
09354 cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
09355 if (cmd < 0 || cmd == 't' || cmd == '#')
09356 return cmd;
09357 cmd = check_password(vmu, newpassword);
09358 if (cmd != 0) {
09359 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09360 cmd = ast_play_and_wait(chan, vm_invalid_password);
09361 } else {
09362 newpassword2[1] = '\0';
09363 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09364 if (cmd == '#')
09365 newpassword2[0] = '\0';
09366 if (cmd < 0 || cmd == 't' || cmd == '#')
09367 return cmd;
09368 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
09369 if (cmd < 0 || cmd == 't' || cmd == '#')
09370 return cmd;
09371 if (!strcmp(newpassword, newpassword2))
09372 break;
09373 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09374 cmd = ast_play_and_wait(chan, vm_mismatch);
09375 }
09376 if (++tries == 3)
09377 return -1;
09378 if (cmd != 0) {
09379 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09380 }
09381 }
09382 if (pwdchange & PWDCHANGE_INTERNAL)
09383 vm_change_password(vmu, newpassword);
09384 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
09385 vm_change_password_shell(vmu, newpassword);
09386
09387 ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int) strlen(newpassword));
09388 cmd = ast_play_and_wait(chan, vm_passchanged);
09389
09390 return cmd;
09391 }
09392
09393 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09394 {
09395 int cmd = 0;
09396 int retries = 0;
09397 int duration = 0;
09398 char newpassword[80] = "";
09399 char newpassword2[80] = "";
09400 char prefile[PATH_MAX] = "";
09401 unsigned char buf[256];
09402 int bytes = 0;
09403
09404 ast_test_suite_event_notify("VMOPTIONS", "Message: entering mailbox options");
09405 if (ast_adsi_available(chan)) {
09406 bytes += adsi_logo(buf + bytes);
09407 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
09408 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09409 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09410 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09411 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09412 }
09413 while ((cmd >= 0) && (cmd != 't')) {
09414 if (cmd)
09415 retries = 0;
09416 switch (cmd) {
09417 case '1':
09418 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09419 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09420 break;
09421 case '2':
09422 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09423 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09424 break;
09425 case '3':
09426 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09427 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09428 break;
09429 case '4':
09430 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
09431 break;
09432 case '5':
09433 if (vmu->password[0] == '-') {
09434 cmd = ast_play_and_wait(chan, "vm-no");
09435 break;
09436 }
09437 newpassword[1] = '\0';
09438 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09439 if (cmd == '#')
09440 newpassword[0] = '\0';
09441 else {
09442 if (cmd < 0)
09443 break;
09444 if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
09445 break;
09446 }
09447 }
09448 cmd = check_password(vmu, newpassword);
09449 if (cmd != 0) {
09450 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09451 cmd = ast_play_and_wait(chan, vm_invalid_password);
09452 if (!cmd) {
09453 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09454 }
09455 break;
09456 }
09457 newpassword2[1] = '\0';
09458 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09459 if (cmd == '#')
09460 newpassword2[0] = '\0';
09461 else {
09462 if (cmd < 0)
09463 break;
09464
09465 if ((cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#")) < 0) {
09466 break;
09467 }
09468 }
09469 if (strcmp(newpassword, newpassword2)) {
09470 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09471 cmd = ast_play_and_wait(chan, vm_mismatch);
09472 if (!cmd) {
09473 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09474 }
09475 break;
09476 }
09477
09478 if (pwdchange & PWDCHANGE_INTERNAL) {
09479 vm_change_password(vmu, newpassword);
09480 }
09481 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd)) {
09482 vm_change_password_shell(vmu, newpassword);
09483 }
09484
09485 ast_debug(1, "User %s set password to %s of length %d\n",
09486 vms->username, newpassword, (int) strlen(newpassword));
09487 cmd = ast_play_and_wait(chan, vm_passchanged);
09488 break;
09489 case '*':
09490 cmd = 't';
09491 break;
09492 default:
09493 cmd = 0;
09494 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09495 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09496 if (ast_fileexists(prefile, NULL, NULL)) {
09497 cmd = ast_play_and_wait(chan, "vm-tmpexists");
09498 }
09499 DISPOSE(prefile, -1);
09500 if (!cmd) {
09501 cmd = ast_play_and_wait(chan, "vm-options");
09502 }
09503 if (!cmd) {
09504 cmd = ast_waitfordigit(chan, 6000);
09505 }
09506 if (!cmd) {
09507 retries++;
09508 }
09509 if (retries > 3) {
09510 cmd = 't';
09511 }
09512 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09513 }
09514 }
09515 if (cmd == 't')
09516 cmd = 0;
09517 return cmd;
09518 }
09519
09520
09521
09522
09523
09524
09525
09526
09527
09528
09529
09530
09531
09532
09533
09534
09535
09536 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09537 {
09538 int cmd = 0;
09539 int retries = 0;
09540 int duration = 0;
09541 char prefile[PATH_MAX] = "";
09542 unsigned char buf[256];
09543 int bytes = 0;
09544
09545 if (ast_adsi_available(chan)) {
09546 bytes += adsi_logo(buf + bytes);
09547 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
09548 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09549 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09550 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09551 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09552 }
09553
09554 ast_test_suite_event_notify("TEMPGREETING", "Message: entering temp greeting options");
09555 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09556 while ((cmd >= 0) && (cmd != 't')) {
09557 if (cmd)
09558 retries = 0;
09559 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09560 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
09561 play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09562 cmd = 't';
09563 } else {
09564 switch (cmd) {
09565 case '1':
09566 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09567 break;
09568 case '2':
09569 DELETE(prefile, -1, prefile, vmu);
09570 ast_play_and_wait(chan, "vm-tempremoved");
09571 cmd = 't';
09572 break;
09573 case '*':
09574 cmd = 't';
09575 break;
09576 default:
09577 cmd = ast_play_and_wait(chan,
09578 ast_fileexists(prefile, NULL, NULL) > 0 ?
09579 "vm-tempgreeting2" : "vm-tempgreeting");
09580 if (!cmd) {
09581 cmd = ast_waitfordigit(chan, 6000);
09582 }
09583 if (!cmd) {
09584 retries++;
09585 }
09586 if (retries > 3) {
09587 cmd = 't';
09588 }
09589 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09590 }
09591 }
09592 DISPOSE(prefile, -1);
09593 }
09594 if (cmd == 't')
09595 cmd = 0;
09596 return cmd;
09597 }
09598
09599
09600
09601
09602
09603
09604
09605
09606
09607 static int vm_browse_messages_gr(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09608 {
09609 int cmd = 0;
09610
09611 if (vms->lastmsg > -1) {
09612 cmd = play_message(chan, vmu, vms);
09613 } else {
09614 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09615 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
09616 if (!cmd) {
09617 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
09618 cmd = ast_play_and_wait(chan, vms->fn);
09619 }
09620 if (!cmd)
09621 cmd = ast_play_and_wait(chan, "vm-messages");
09622 } else {
09623 if (!cmd)
09624 cmd = ast_play_and_wait(chan, "vm-messages");
09625 if (!cmd) {
09626 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09627 cmd = ast_play_and_wait(chan, vms->fn);
09628 }
09629 }
09630 }
09631 return cmd;
09632 }
09633
09634
09635 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09636 {
09637 int cmd = 0;
09638
09639 if (vms->lastmsg > -1) {
09640 cmd = play_message(chan, vmu, vms);
09641 } else {
09642 if (!strcasecmp(vms->fn, "INBOX")) {
09643 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
09644 } else {
09645 cmd = ast_play_and_wait(chan, "vm-nomessages");
09646 }
09647 }
09648 return cmd;
09649 }
09650
09651
09652
09653
09654
09655
09656
09657
09658
09659 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09660 {
09661 int cmd = 0;
09662
09663 if (vms->lastmsg > -1) {
09664 cmd = play_message(chan, vmu, vms);
09665 } else {
09666 cmd = ast_play_and_wait(chan, "vm-youhave");
09667 if (!cmd)
09668 cmd = ast_play_and_wait(chan, "vm-no");
09669 if (!cmd) {
09670 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09671 cmd = ast_play_and_wait(chan, vms->fn);
09672 }
09673 if (!cmd)
09674 cmd = ast_play_and_wait(chan, "vm-messages");
09675 }
09676 return cmd;
09677 }
09678
09679
09680
09681
09682
09683
09684
09685
09686
09687 static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09688 {
09689 int cmd;
09690
09691 if (vms->lastmsg > -1) {
09692 cmd = play_message(chan, vmu, vms);
09693 } else {
09694 cmd = ast_play_and_wait(chan, "vm-no");
09695 if (!cmd)
09696 cmd = ast_play_and_wait(chan, "vm-message");
09697 if (!cmd) {
09698 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09699 cmd = ast_play_and_wait(chan, vms->fn);
09700 }
09701 }
09702 return cmd;
09703 }
09704
09705
09706
09707
09708
09709
09710
09711
09712
09713 static int vm_browse_messages_es(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09714 {
09715 int cmd;
09716
09717 if (vms->lastmsg > -1) {
09718 cmd = play_message(chan, vmu, vms);
09719 } else {
09720 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09721 if (!cmd)
09722 cmd = ast_play_and_wait(chan, "vm-messages");
09723 if (!cmd) {
09724 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09725 cmd = ast_play_and_wait(chan, vms->fn);
09726 }
09727 }
09728 return cmd;
09729 }
09730
09731
09732
09733
09734
09735
09736
09737
09738
09739 static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09740 {
09741 int cmd;
09742
09743 if (vms->lastmsg > -1) {
09744 cmd = play_message(chan, vmu, vms);
09745 } else {
09746 cmd = ast_play_and_wait(chan, "vm-no");
09747 if (!cmd) {
09748 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09749 cmd = ast_play_and_wait(chan, vms->fn);
09750 }
09751 if (!cmd)
09752 cmd = ast_play_and_wait(chan, "vm-messages");
09753 }
09754 return cmd;
09755 }
09756
09757
09758
09759
09760
09761
09762
09763
09764
09765 static int vm_browse_messages_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09766 {
09767 int cmd;
09768
09769 if (vms->lastmsg > -1) {
09770 cmd = play_message(chan, vmu, vms);
09771 } else {
09772 cmd = ast_play_and_wait(chan, "vm-you");
09773 if (!cmd)
09774 cmd = ast_play_and_wait(chan, "vm-haveno");
09775 if (!cmd)
09776 cmd = ast_play_and_wait(chan, "vm-messages");
09777 if (!cmd) {
09778 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09779 cmd = ast_play_and_wait(chan, vms->fn);
09780 }
09781 }
09782 return cmd;
09783 }
09784
09785
09786
09787
09788
09789
09790
09791
09792
09793 static int vm_browse_messages_vi(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09794 {
09795 int cmd = 0;
09796
09797 if (vms->lastmsg > -1) {
09798 cmd = play_message(chan, vmu, vms);
09799 } else {
09800 cmd = ast_play_and_wait(chan, "vm-no");
09801 if (!cmd) {
09802 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09803 cmd = ast_play_and_wait(chan, vms->fn);
09804 }
09805 }
09806 return cmd;
09807 }
09808
09809
09810
09811
09812
09813
09814
09815
09816
09817
09818
09819
09820 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09821 {
09822 if (!strncasecmp(ast_channel_language(chan), "es", 2)) {
09823 return vm_browse_messages_es(chan, vms, vmu);
09824 } else if (!strncasecmp(ast_channel_language(chan), "gr", 2)) {
09825 return vm_browse_messages_gr(chan, vms, vmu);
09826 } else if (!strncasecmp(ast_channel_language(chan), "he", 2)) {
09827 return vm_browse_messages_he(chan, vms, vmu);
09828 } else if (!strncasecmp(ast_channel_language(chan), "it", 2)) {
09829 return vm_browse_messages_it(chan, vms, vmu);
09830 } else if (!strncasecmp(ast_channel_language(chan), "pt", 2)) {
09831 return vm_browse_messages_pt(chan, vms, vmu);
09832 } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) {
09833 return vm_browse_messages_vi(chan, vms, vmu);
09834 } else if (!strncasecmp(ast_channel_language(chan), "zh", 2)) {
09835 return vm_browse_messages_zh(chan, vms, vmu);
09836 } else {
09837 return vm_browse_messages_en(chan, vms, vmu);
09838 }
09839 }
09840
09841 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
09842 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
09843 int skipuser, int max_logins, int silent)
09844 {
09845 int useadsi = 0, valid = 0, logretries = 0;
09846 char password[AST_MAX_EXTENSION]="", *passptr;
09847 struct ast_vm_user vmus, *vmu = NULL;
09848
09849
09850 adsi_begin(chan, &useadsi);
09851 if (!skipuser && useadsi)
09852 adsi_login(chan);
09853 ast_test_suite_event_notify("PLAYBACK", "Message: vm-login");
09854 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", ast_channel_language(chan))) {
09855 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
09856 return -1;
09857 }
09858
09859
09860
09861 while (!valid && (logretries < max_logins)) {
09862
09863 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
09864 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
09865 return -1;
09866 }
09867 if (ast_strlen_zero(mailbox)) {
09868 if (chan->caller.id.number.valid && chan->caller.id.number.str) {
09869 ast_copy_string(mailbox, chan->caller.id.number.str, mailbox_size);
09870 } else {
09871 ast_verb(3, "Username not entered\n");
09872 return -1;
09873 }
09874 } else if (mailbox[0] == '*') {
09875
09876 ast_verb(4, "Mailbox begins with '*', attempting jump to extension 'a'\n");
09877 if (ast_exists_extension(chan, chan->context, "a", 1,
09878 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09879 return -1;
09880 }
09881 ast_verb(4, "Jump to extension 'a' failed; setting mailbox to NULL\n");
09882 mailbox[0] = '\0';
09883 }
09884
09885 if (useadsi)
09886 adsi_password(chan);
09887
09888 if (!ast_strlen_zero(prefix)) {
09889 char fullusername[80] = "";
09890 ast_copy_string(fullusername, prefix, sizeof(fullusername));
09891 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
09892 ast_copy_string(mailbox, fullusername, mailbox_size);
09893 }
09894
09895 ast_debug(1, "Before find user for mailbox %s\n", mailbox);
09896 vmu = find_user(&vmus, context, mailbox);
09897 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
09898
09899 password[0] = '\0';
09900 } else {
09901 ast_test_suite_event_notify("PLAYBACK", "Message: %s", vm_password);
09902 if (ast_streamfile(chan, vm_password, ast_channel_language(chan))) {
09903 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
09904 return -1;
09905 }
09906 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
09907 ast_log(AST_LOG_WARNING, "Unable to read password\n");
09908 return -1;
09909 } else if (password[0] == '*') {
09910
09911 ast_verb(4, "Password begins with '*', attempting jump to extension 'a'\n");
09912 if (ast_exists_extension(chan, chan->context, "a", 1,
09913 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09914 mailbox[0] = '*';
09915 return -1;
09916 }
09917 ast_verb(4, "Jump to extension 'a' failed; setting mailbox and user to NULL\n");
09918 mailbox[0] = '\0';
09919
09920 vmu = NULL;
09921 }
09922 }
09923
09924 if (vmu) {
09925 passptr = vmu->password;
09926 if (passptr[0] == '-') passptr++;
09927 }
09928 if (vmu && !strcmp(passptr, password))
09929 valid++;
09930 else {
09931 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
09932 if (!ast_strlen_zero(prefix))
09933 mailbox[0] = '\0';
09934 }
09935 logretries++;
09936 if (!valid) {
09937 if (skipuser || logretries >= max_logins) {
09938 ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect");
09939 if (ast_streamfile(chan, "vm-incorrect", ast_channel_language(chan))) {
09940 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
09941 return -1;
09942 }
09943 } else {
09944 ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect-mailbox");
09945 if (useadsi)
09946 adsi_login(chan);
09947 if (ast_streamfile(chan, "vm-incorrect-mailbox", ast_channel_language(chan))) {
09948 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
09949 return -1;
09950 }
09951 }
09952 if (ast_waitstream(chan, ""))
09953 return -1;
09954 }
09955 }
09956 if (!valid && (logretries >= max_logins)) {
09957 ast_stopstream(chan);
09958 ast_play_and_wait(chan, "vm-goodbye");
09959 return -1;
09960 }
09961 if (vmu && !skipuser) {
09962 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
09963 }
09964 return 0;
09965 }
09966
09967 static int vm_execmain(struct ast_channel *chan, const char *data)
09968 {
09969
09970
09971
09972 int res = -1;
09973 int cmd = 0;
09974 int valid = 0;
09975 char prefixstr[80] ="";
09976 char ext_context[256]="";
09977 int box;
09978 int useadsi = 0;
09979 int skipuser = 0;
09980 struct vm_state vms;
09981 struct ast_vm_user *vmu = NULL, vmus;
09982 char *context = NULL;
09983 int silentexit = 0;
09984 struct ast_flags flags = { 0 };
09985 signed char record_gain = 0;
09986 int play_auto = 0;
09987 int play_folder = 0;
09988 int in_urgent = 0;
09989 #ifdef IMAP_STORAGE
09990 int deleted = 0;
09991 #endif
09992
09993
09994 memset(&vms, 0, sizeof(vms));
09995
09996 vms.lastmsg = -1;
09997
09998 memset(&vmus, 0, sizeof(vmus));
09999
10000 ast_test_suite_event_notify("START", "Message: vm_execmain started");
10001 if (chan->_state != AST_STATE_UP) {
10002 ast_debug(1, "Before ast_answer\n");
10003 ast_answer(chan);
10004 }
10005
10006 if (!ast_strlen_zero(data)) {
10007 char *opts[OPT_ARG_ARRAY_SIZE];
10008 char *parse;
10009 AST_DECLARE_APP_ARGS(args,
10010 AST_APP_ARG(argv0);
10011 AST_APP_ARG(argv1);
10012 );
10013
10014 parse = ast_strdupa(data);
10015
10016 AST_STANDARD_APP_ARGS(args, parse);
10017
10018 if (args.argc == 2) {
10019 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
10020 return -1;
10021 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
10022 int gain;
10023 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
10024 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
10025 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10026 return -1;
10027 } else {
10028 record_gain = (signed char) gain;
10029 }
10030 } else {
10031 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
10032 }
10033 }
10034 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
10035 play_auto = 1;
10036 if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])) {
10037
10038 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
10039 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
10040 play_folder = -1;
10041 }
10042 } else {
10043 play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
10044 }
10045 } else {
10046 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
10047 }
10048 if (play_folder > 9 || play_folder < 0) {
10049 ast_log(AST_LOG_WARNING,
10050 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
10051 opts[OPT_ARG_PLAYFOLDER]);
10052 play_folder = 0;
10053 }
10054 }
10055 } else {
10056
10057 while (*(args.argv0)) {
10058 if (*(args.argv0) == 's')
10059 ast_set_flag(&flags, OPT_SILENT);
10060 else if (*(args.argv0) == 'p')
10061 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
10062 else
10063 break;
10064 (args.argv0)++;
10065 }
10066
10067 }
10068
10069 valid = ast_test_flag(&flags, OPT_SILENT);
10070
10071 if ((context = strchr(args.argv0, '@')))
10072 *context++ = '\0';
10073
10074 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
10075 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
10076 else
10077 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
10078
10079 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
10080 skipuser++;
10081 else
10082 valid = 0;
10083 }
10084
10085 if (!valid)
10086 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
10087
10088 ast_debug(1, "After vm_authenticate\n");
10089
10090 if (vms.username[0] == '*') {
10091 ast_debug(1, "user pressed * in context '%s'\n", chan->context);
10092
10093
10094 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
10095 ast_test_suite_event_notify("REDIRECT", "Message: redirecting user to 'a' extension");
10096 res = 0;
10097 goto out;
10098 }
10099 }
10100
10101 if (!res) {
10102 valid = 1;
10103 if (!skipuser)
10104 vmu = &vmus;
10105 } else {
10106 res = 0;
10107 }
10108
10109
10110 adsi_begin(chan, &useadsi);
10111
10112 ast_test_suite_assert(valid);
10113 if (!valid) {
10114 goto out;
10115 }
10116 ast_test_suite_event_notify("AUTHENTICATED", "Message: vm_user authenticated");
10117
10118 #ifdef IMAP_STORAGE
10119 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
10120 pthread_setspecific(ts_vmstate.key, &vms);
10121
10122 vms.interactive = 1;
10123 vms.updated = 1;
10124 if (vmu)
10125 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
10126 vmstate_insert(&vms);
10127 init_vm_state(&vms);
10128 #endif
10129
10130
10131 if (!ast_strlen_zero(vmu->language))
10132 ast_channel_language_set(chan, vmu->language);
10133
10134
10135 ast_debug(1, "Before open_mailbox\n");
10136 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10137 if (res < 0)
10138 goto out;
10139 vms.oldmessages = vms.lastmsg + 1;
10140 ast_debug(1, "Number of old messages: %d\n", vms.oldmessages);
10141
10142 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10143 if (res < 0)
10144 goto out;
10145 vms.newmessages = vms.lastmsg + 1;
10146 ast_debug(1, "Number of new messages: %d\n", vms.newmessages);
10147
10148 in_urgent = 1;
10149 res = open_mailbox(&vms, vmu, 11);
10150 if (res < 0)
10151 goto out;
10152 vms.urgentmessages = vms.lastmsg + 1;
10153 ast_debug(1, "Number of urgent messages: %d\n", vms.urgentmessages);
10154
10155
10156 if (play_auto) {
10157 ast_test_suite_event_notify("AUTOPLAY", "Message: auto-playing messages");
10158 if (vms.urgentmessages) {
10159 in_urgent = 1;
10160 res = open_mailbox(&vms, vmu, 11);
10161 } else {
10162 in_urgent = 0;
10163 res = open_mailbox(&vms, vmu, play_folder);
10164 }
10165 if (res < 0)
10166 goto out;
10167
10168
10169 if (vms.lastmsg == -1) {
10170 in_urgent = 0;
10171 cmd = vm_browse_messages(chan, &vms, vmu);
10172 res = 0;
10173 goto out;
10174 }
10175 } else {
10176 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
10177
10178 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10179 in_urgent = 0;
10180 play_folder = 1;
10181 if (res < 0)
10182 goto out;
10183 } else if (!vms.urgentmessages && vms.newmessages) {
10184
10185 in_urgent = 0;
10186 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10187 if (res < 0)
10188 goto out;
10189 }
10190 }
10191
10192 if (useadsi)
10193 adsi_status(chan, &vms);
10194 res = 0;
10195
10196
10197 if (!strcasecmp(vmu->mailbox, vmu->password) &&
10198 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
10199 if (ast_play_and_wait(chan, "vm-newuser") == -1)
10200 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
10201 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
10202 if ((cmd == 't') || (cmd == '#')) {
10203
10204 ast_test_suite_event_notify("TIMEOUT", "Message: response from user timed out");
10205 res = 0;
10206 goto out;
10207 } else if (cmd < 0) {
10208
10209 ast_test_suite_event_notify("HANGUP", "Message: hangup detected");
10210 res = -1;
10211 goto out;
10212 }
10213 }
10214 #ifdef IMAP_STORAGE
10215 ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
10216 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
10217 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
10218 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10219 }
10220 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10221 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
10222 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10223 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10224 }
10225 #endif
10226
10227 ast_test_suite_event_notify("INTRO", "Message: playing intro menu");
10228 if (play_auto) {
10229 cmd = '1';
10230 } else {
10231 cmd = vm_intro(chan, vmu, &vms);
10232 }
10233 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10234
10235 vms.repeats = 0;
10236 vms.starting = 1;
10237 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10238
10239 switch (cmd) {
10240 case '1':
10241 vms.curmsg = 0;
10242
10243 case '5':
10244 ast_test_suite_event_notify("BROWSE", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10245 cmd = vm_browse_messages(chan, &vms, vmu);
10246 break;
10247 case '2':
10248 ast_test_suite_event_notify("CHANGEFOLDER", "Message: browsing to a different folder");
10249 if (useadsi)
10250 adsi_folders(chan, 0, "Change to folder...");
10251
10252 cmd = get_folder2(chan, "vm-changeto", 0);
10253 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10254 if (cmd == '#') {
10255 cmd = 0;
10256 } else if (cmd > 0) {
10257 cmd = cmd - '0';
10258 res = close_mailbox(&vms, vmu);
10259 if (res == ERROR_LOCK_PATH)
10260 goto out;
10261
10262 if (cmd != 11) in_urgent = 0;
10263 res = open_mailbox(&vms, vmu, cmd);
10264 if (res < 0)
10265 goto out;
10266 play_folder = cmd;
10267 cmd = 0;
10268 }
10269 if (useadsi)
10270 adsi_status2(chan, &vms);
10271
10272 if (!cmd) {
10273 cmd = vm_play_folder_name(chan, vms.vmbox);
10274 }
10275
10276 vms.starting = 1;
10277 break;
10278 case '3':
10279 ast_test_suite_event_notify("ADVOPTIONS", "Message: entering advanced options menu");
10280 cmd = 0;
10281 vms.repeats = 0;
10282 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10283 switch (cmd) {
10284 case '1':
10285 if (vms.lastmsg > -1 && !vms.starting) {
10286 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
10287 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10288 res = cmd;
10289 goto out;
10290 }
10291 } else {
10292 cmd = ast_play_and_wait(chan, "vm-sorry");
10293 }
10294 cmd = 't';
10295 break;
10296 case '2':
10297 if (!vms.starting)
10298 ast_verb(3, "Callback Requested\n");
10299 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
10300 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
10301 if (cmd == 9) {
10302 silentexit = 1;
10303 goto out;
10304 } else if (cmd == ERROR_LOCK_PATH) {
10305 res = cmd;
10306 goto out;
10307 }
10308 } else {
10309 cmd = ast_play_and_wait(chan, "vm-sorry");
10310 }
10311 cmd = 't';
10312 break;
10313 case '3':
10314 if (vms.lastmsg > -1 && !vms.starting) {
10315 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
10316 if (cmd == ERROR_LOCK_PATH) {
10317 res = cmd;
10318 goto out;
10319 }
10320 } else {
10321 cmd = ast_play_and_wait(chan, "vm-sorry");
10322 }
10323 cmd = 't';
10324 break;
10325 case '4':
10326 if (!ast_strlen_zero(vmu->dialout)) {
10327 cmd = dialout(chan, vmu, NULL, vmu->dialout);
10328 if (cmd == 9) {
10329 silentexit = 1;
10330 goto out;
10331 }
10332 } else {
10333 cmd = ast_play_and_wait(chan, "vm-sorry");
10334 }
10335 cmd = 't';
10336 break;
10337
10338 case '5':
10339 if (ast_test_flag(vmu, VM_SVMAIL)) {
10340 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
10341 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10342 res = cmd;
10343 goto out;
10344 }
10345 } else {
10346 cmd = ast_play_and_wait(chan, "vm-sorry");
10347 }
10348 cmd = 't';
10349 break;
10350
10351 case '*':
10352 cmd = 't';
10353 break;
10354
10355 default:
10356 cmd = 0;
10357 if (!vms.starting) {
10358 cmd = ast_play_and_wait(chan, "vm-toreply");
10359 }
10360 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
10361 cmd = ast_play_and_wait(chan, "vm-tocallback");
10362 }
10363 if (!cmd && !vms.starting) {
10364 cmd = ast_play_and_wait(chan, "vm-tohearenv");
10365 }
10366 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
10367 cmd = ast_play_and_wait(chan, "vm-tomakecall");
10368 }
10369 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd) {
10370 cmd = ast_play_and_wait(chan, "vm-leavemsg");
10371 }
10372 if (!cmd) {
10373 cmd = ast_play_and_wait(chan, "vm-starmain");
10374 }
10375 if (!cmd) {
10376 cmd = ast_waitfordigit(chan, 6000);
10377 }
10378 if (!cmd) {
10379 vms.repeats++;
10380 }
10381 if (vms.repeats > 3) {
10382 cmd = 't';
10383 }
10384 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10385 }
10386 }
10387 if (cmd == 't') {
10388 cmd = 0;
10389 vms.repeats = 0;
10390 }
10391 break;
10392 case '4':
10393 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg - 1, vms.curmsg - 1);
10394 if (vms.curmsg > 0) {
10395 vms.curmsg--;
10396 cmd = play_message(chan, vmu, &vms);
10397 } else {
10398
10399
10400
10401
10402 if (in_urgent == 0 && vms.urgentmessages > 0) {
10403
10404 in_urgent = 1;
10405 res = close_mailbox(&vms, vmu);
10406 if (res == ERROR_LOCK_PATH)
10407 goto out;
10408 res = open_mailbox(&vms, vmu, 11);
10409 if (res < 0)
10410 goto out;
10411 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1);
10412 vms.curmsg = vms.lastmsg;
10413 if (vms.lastmsg < 0) {
10414 cmd = ast_play_and_wait(chan, "vm-nomore");
10415 }
10416 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10417 vms.curmsg = vms.lastmsg;
10418 cmd = play_message(chan, vmu, &vms);
10419 } else {
10420 cmd = ast_play_and_wait(chan, "vm-nomore");
10421 }
10422 }
10423 break;
10424 case '6':
10425 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg + 1, vms.curmsg + 1);
10426 if (vms.curmsg < vms.lastmsg) {
10427 vms.curmsg++;
10428 cmd = play_message(chan, vmu, &vms);
10429 } else {
10430 if (in_urgent && vms.newmessages > 0) {
10431
10432
10433
10434
10435 in_urgent = 0;
10436 res = close_mailbox(&vms, vmu);
10437 if (res == ERROR_LOCK_PATH)
10438 goto out;
10439 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10440 if (res < 0)
10441 goto out;
10442 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10443 vms.curmsg = -1;
10444 if (vms.lastmsg < 0) {
10445 cmd = ast_play_and_wait(chan, "vm-nomore");
10446 }
10447 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10448 vms.curmsg = 0;
10449 cmd = play_message(chan, vmu, &vms);
10450 } else {
10451 cmd = ast_play_and_wait(chan, "vm-nomore");
10452 }
10453 }
10454 break;
10455 case '7':
10456 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
10457 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
10458 if (useadsi)
10459 adsi_delete(chan, &vms);
10460 if (vms.deleted[vms.curmsg]) {
10461 if (play_folder == 0) {
10462 if (in_urgent) {
10463 vms.urgentmessages--;
10464 } else {
10465 vms.newmessages--;
10466 }
10467 }
10468 else if (play_folder == 1)
10469 vms.oldmessages--;
10470 cmd = ast_play_and_wait(chan, "vm-deleted");
10471 } else {
10472 if (play_folder == 0) {
10473 if (in_urgent) {
10474 vms.urgentmessages++;
10475 } else {
10476 vms.newmessages++;
10477 }
10478 }
10479 else if (play_folder == 1)
10480 vms.oldmessages++;
10481 cmd = ast_play_and_wait(chan, "vm-undeleted");
10482 }
10483 if (ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10484 if (vms.curmsg < vms.lastmsg) {
10485 vms.curmsg++;
10486 cmd = play_message(chan, vmu, &vms);
10487 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10488 vms.curmsg = 0;
10489 cmd = play_message(chan, vmu, &vms);
10490 } else {
10491
10492
10493
10494
10495 if (in_urgent == 1) {
10496
10497 in_urgent = 0;
10498 res = close_mailbox(&vms, vmu);
10499 if (res == ERROR_LOCK_PATH)
10500 goto out;
10501 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10502 if (res < 0)
10503 goto out;
10504 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10505 vms.curmsg = -1;
10506 if (vms.lastmsg < 0) {
10507 cmd = ast_play_and_wait(chan, "vm-nomore");
10508 }
10509 } else {
10510 cmd = ast_play_and_wait(chan, "vm-nomore");
10511 }
10512 }
10513 }
10514 } else
10515 cmd = 0;
10516 #ifdef IMAP_STORAGE
10517 deleted = 1;
10518 #endif
10519 break;
10520
10521 case '8':
10522 if (vms.lastmsg > -1) {
10523 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
10524 if (cmd == ERROR_LOCK_PATH) {
10525 res = cmd;
10526 goto out;
10527 }
10528 } else {
10529
10530
10531
10532
10533 if (in_urgent == 1 && vms.newmessages > 0) {
10534
10535 in_urgent = 0;
10536 res = close_mailbox(&vms, vmu);
10537 if (res == ERROR_LOCK_PATH)
10538 goto out;
10539 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10540 if (res < 0)
10541 goto out;
10542 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10543 vms.curmsg = -1;
10544 if (vms.lastmsg < 0) {
10545 cmd = ast_play_and_wait(chan, "vm-nomore");
10546 }
10547 } else {
10548 cmd = ast_play_and_wait(chan, "vm-nomore");
10549 }
10550 }
10551 break;
10552 case '9':
10553 ast_test_suite_event_notify("SAVEMSG", "Message: saving message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10554 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
10555
10556 cmd = 0;
10557 break;
10558 }
10559 if (useadsi)
10560 adsi_folders(chan, 1, "Save to folder...");
10561 cmd = get_folder2(chan, "vm-savefolder", 1);
10562 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10563 box = 0;
10564 if (cmd == '#') {
10565 cmd = 0;
10566 break;
10567 } else if (cmd > 0) {
10568 box = cmd = cmd - '0';
10569 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
10570 if (cmd == ERROR_LOCK_PATH) {
10571 res = cmd;
10572 goto out;
10573 #ifndef IMAP_STORAGE
10574 } else if (!cmd) {
10575 vms.deleted[vms.curmsg] = 1;
10576 #endif
10577 } else {
10578 vms.deleted[vms.curmsg] = 0;
10579 vms.heard[vms.curmsg] = 0;
10580 }
10581 }
10582 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
10583 if (useadsi)
10584 adsi_message(chan, &vms);
10585 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(vmu, box));
10586 if (!cmd) {
10587 cmd = ast_play_and_wait(chan, "vm-message");
10588 if (!cmd)
10589 cmd = say_and_wait(chan, vms.curmsg + 1, ast_channel_language(chan));
10590 if (!cmd)
10591 cmd = ast_play_and_wait(chan, "vm-savedto");
10592 if (!cmd)
10593 cmd = vm_play_folder_name(chan, vms.fn);
10594 } else {
10595 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10596 }
10597 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
10598 if (vms.curmsg < vms.lastmsg) {
10599 vms.curmsg++;
10600 cmd = play_message(chan, vmu, &vms);
10601 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10602 vms.curmsg = 0;
10603 cmd = play_message(chan, vmu, &vms);
10604 } else {
10605
10606
10607
10608
10609 if (in_urgent == 1 && vms.newmessages > 0) {
10610
10611 in_urgent = 0;
10612 res = close_mailbox(&vms, vmu);
10613 if (res == ERROR_LOCK_PATH)
10614 goto out;
10615 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10616 if (res < 0)
10617 goto out;
10618 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10619 vms.curmsg = -1;
10620 if (vms.lastmsg < 0) {
10621 cmd = ast_play_and_wait(chan, "vm-nomore");
10622 }
10623 } else {
10624 cmd = ast_play_and_wait(chan, "vm-nomore");
10625 }
10626 }
10627 }
10628 break;
10629 case '*':
10630 if (!vms.starting) {
10631 cmd = ast_play_and_wait(chan, "vm-onefor");
10632 if (!strncasecmp(ast_channel_language(chan), "he", 2)) {
10633 cmd = ast_play_and_wait(chan, "vm-for");
10634 }
10635 if (!cmd)
10636 cmd = vm_play_folder_name(chan, vms.vmbox);
10637 if (!cmd)
10638 cmd = ast_play_and_wait(chan, "vm-opts");
10639 if (!cmd)
10640 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
10641 } else
10642 cmd = 0;
10643 break;
10644 case '0':
10645 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
10646 if (useadsi)
10647 adsi_status(chan, &vms);
10648 break;
10649 default:
10650 ast_test_suite_event_notify("PLAYBACK", "Message: instructions");
10651 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
10652 break;
10653 }
10654 }
10655 if ((cmd == 't') || (cmd == '#')) {
10656
10657 res = 0;
10658 } else {
10659
10660 res = -1;
10661 }
10662
10663 out:
10664 if (res > -1) {
10665 ast_stopstream(chan);
10666 adsi_goodbye(chan);
10667 if (valid && res != OPERATOR_EXIT) {
10668 if (silentexit)
10669 res = ast_play_and_wait(chan, "vm-dialout");
10670 else
10671 res = ast_play_and_wait(chan, "vm-goodbye");
10672 }
10673 if ((valid && res > 0) || res == OPERATOR_EXIT) {
10674 res = 0;
10675 }
10676 if (useadsi)
10677 ast_adsi_unload_session(chan);
10678 }
10679 if (vmu)
10680 close_mailbox(&vms, vmu);
10681 if (valid) {
10682 int new = 0, old = 0, urgent = 0;
10683 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
10684 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
10685
10686 run_externnotify(vmu->context, vmu->mailbox, NULL);
10687 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
10688 queue_mwi_event(ext_context, urgent, new, old);
10689 }
10690 #ifdef IMAP_STORAGE
10691
10692 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
10693 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
10694 ast_mutex_lock(&vms.lock);
10695 #ifdef HAVE_IMAP_TK2006
10696 if (LEVELUIDPLUS (vms.mailstream)) {
10697 mail_expunge_full(vms.mailstream, NIL, EX_UID);
10698 } else
10699 #endif
10700 mail_expunge(vms.mailstream);
10701 ast_mutex_unlock(&vms.lock);
10702 }
10703
10704
10705 if (vmu) {
10706 vmstate_delete(&vms);
10707 }
10708 #endif
10709 if (vmu)
10710 free_user(vmu);
10711
10712 #ifdef IMAP_STORAGE
10713 pthread_setspecific(ts_vmstate.key, NULL);
10714 #endif
10715 return res;
10716 }
10717
10718 static int vm_exec(struct ast_channel *chan, const char *data)
10719 {
10720 int res = 0;
10721 char *tmp;
10722 struct leave_vm_options leave_options;
10723 struct ast_flags flags = { 0 };
10724 char *opts[OPT_ARG_ARRAY_SIZE];
10725 AST_DECLARE_APP_ARGS(args,
10726 AST_APP_ARG(argv0);
10727 AST_APP_ARG(argv1);
10728 );
10729
10730 memset(&leave_options, 0, sizeof(leave_options));
10731
10732 if (chan->_state != AST_STATE_UP)
10733 ast_answer(chan);
10734
10735 if (!ast_strlen_zero(data)) {
10736 tmp = ast_strdupa(data);
10737 AST_STANDARD_APP_ARGS(args, tmp);
10738 if (args.argc == 2) {
10739 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
10740 return -1;
10741 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
10742 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
10743 int gain;
10744
10745 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
10746 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10747 return -1;
10748 } else {
10749 leave_options.record_gain = (signed char) gain;
10750 }
10751 }
10752 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
10753 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
10754 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
10755 }
10756 }
10757 } else {
10758 char temp[256];
10759 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
10760 if (res < 0)
10761 return res;
10762 if (ast_strlen_zero(temp))
10763 return 0;
10764 args.argv0 = ast_strdupa(temp);
10765 }
10766
10767 res = leave_voicemail(chan, args.argv0, &leave_options);
10768 if (res == 't') {
10769 ast_play_and_wait(chan, "vm-goodbye");
10770 res = 0;
10771 }
10772
10773 if (res == OPERATOR_EXIT) {
10774 res = 0;
10775 }
10776
10777 if (res == ERROR_LOCK_PATH) {
10778 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
10779 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
10780 res = 0;
10781 }
10782
10783 return res;
10784 }
10785
10786 static struct ast_vm_user *find_or_create(const char *context, const char *box)
10787 {
10788 struct ast_vm_user *vmu;
10789
10790 if (!ast_strlen_zero(box) && box[0] == '*') {
10791 ast_log(LOG_WARNING, "Mailbox %s in context %s begins with '*' character. The '*' character,"
10792 "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
10793 "\n\tpredefined extension 'a'. A mailbox or password beginning with '*' is not valid"
10794 "\n\tand will be ignored.\n", box, context);
10795 return NULL;
10796 }
10797
10798 AST_LIST_TRAVERSE(&users, vmu, list) {
10799 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
10800 if (strcasecmp(vmu->context, context)) {
10801 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
10802 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
10803 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
10804 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
10805 }
10806 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
10807 return NULL;
10808 }
10809 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
10810 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
10811 return NULL;
10812 }
10813 }
10814
10815 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
10816 return NULL;
10817
10818 ast_copy_string(vmu->context, context, sizeof(vmu->context));
10819 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
10820
10821 AST_LIST_INSERT_TAIL(&users, vmu, list);
10822
10823 return vmu;
10824 }
10825
10826 static int append_mailbox(const char *context, const char *box, const char *data)
10827 {
10828
10829 char *tmp;
10830 char *stringp;
10831 char *s;
10832 struct ast_vm_user *vmu;
10833 char *mailbox_full;
10834 int new = 0, old = 0, urgent = 0;
10835 char secretfn[PATH_MAX] = "";
10836
10837 tmp = ast_strdupa(data);
10838
10839 if (!(vmu = find_or_create(context, box)))
10840 return -1;
10841
10842 populate_defaults(vmu);
10843
10844 stringp = tmp;
10845 if ((s = strsep(&stringp, ","))) {
10846 if (!ast_strlen_zero(s) && s[0] == '*') {
10847 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
10848 "\n\tmust be reset in voicemail.conf.\n", box);
10849 }
10850
10851 ast_copy_string(vmu->password, s, sizeof(vmu->password));
10852 }
10853 if (stringp && (s = strsep(&stringp, ","))) {
10854 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
10855 }
10856 if (stringp && (s = strsep(&stringp, ","))) {
10857 ast_copy_string(vmu->email, s, sizeof(vmu->email));
10858 }
10859 if (stringp && (s = strsep(&stringp, ","))) {
10860 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
10861 }
10862 if (stringp && (s = strsep(&stringp, ","))) {
10863 apply_options(vmu, s);
10864 }
10865
10866 switch (vmu->passwordlocation) {
10867 case OPT_PWLOC_SPOOLDIR:
10868 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
10869 read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
10870 }
10871
10872 mailbox_full = alloca(strlen(box) + strlen(context) + 1);
10873 strcpy(mailbox_full, box);
10874 strcat(mailbox_full, "@");
10875 strcat(mailbox_full, context);
10876
10877 inboxcount2(mailbox_full, &urgent, &new, &old);
10878 queue_mwi_event(mailbox_full, urgent, new, old);
10879
10880 return 0;
10881 }
10882
10883 AST_TEST_DEFINE(test_voicemail_vmuser)
10884 {
10885 int res = 0;
10886 struct ast_vm_user *vmu;
10887
10888 static const char options_string[] = "attach=yes|attachfmt=wav49|"
10889 "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|"
10890 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|"
10891 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
10892 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
10893 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
10894 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir|emailbody="
10895 "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message|emailsubject="
10896 "[PBX]: New message \\\\${VM_MSGNUM}\\\\ in mailbox ${VM_MAILBOX}";
10897 #ifdef IMAP_STORAGE
10898 static const char option_string2[] = "imapuser=imapuser|imappassword=imappasswd|"
10899 "imapfolder=INBOX|imapvmshareid=6000|imapserver=imapserver|imapport=1234|imapflags=flagged";
10900 #endif
10901
10902 switch (cmd) {
10903 case TEST_INIT:
10904 info->name = "vmuser";
10905 info->category = "/apps/app_voicemail/";
10906 info->summary = "Vmuser unit test";
10907 info->description =
10908 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
10909 return AST_TEST_NOT_RUN;
10910 case TEST_EXECUTE:
10911 break;
10912 }
10913
10914 if (!(vmu = ast_calloc(1, sizeof(*vmu)))) {
10915 return AST_TEST_NOT_RUN;
10916 }
10917 ast_set_flag(vmu, VM_ALLOCED);
10918 populate_defaults(vmu);
10919
10920 apply_options(vmu, options_string);
10921
10922 if (!ast_test_flag(vmu, VM_ATTACH)) {
10923 ast_test_status_update(test, "Parse failure for attach option\n");
10924 res = 1;
10925 }
10926 if (strcasecmp(vmu->attachfmt, "wav49")) {
10927 ast_test_status_update(test, "Parse failure for attachftm option\n");
10928 res = 1;
10929 }
10930 if (strcasecmp(vmu->serveremail, "someguy@digium.com")) {
10931 ast_test_status_update(test, "Parse failure for serveremail option\n");
10932 res = 1;
10933 }
10934 if (!vmu->emailsubject || strcasecmp(vmu->emailsubject, "[PBX]: New message \\${VM_MSGNUM}\\ in mailbox ${VM_MAILBOX}")) {
10935 ast_test_status_update(test, "Parse failure for emailsubject option\n");
10936 res = 1;
10937 }
10938 if (!vmu->emailbody || strcasecmp(vmu->emailbody, "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message")) {
10939 ast_test_status_update(test, "Parse failure for emailbody option\n");
10940 res = 1;
10941 }
10942 if (strcasecmp(vmu->zonetag, "central")) {
10943 ast_test_status_update(test, "Parse failure for tz option\n");
10944 res = 1;
10945 }
10946 if (!ast_test_flag(vmu, VM_DELETE)) {
10947 ast_test_status_update(test, "Parse failure for delete option\n");
10948 res = 1;
10949 }
10950 if (!ast_test_flag(vmu, VM_SAYCID)) {
10951 ast_test_status_update(test, "Parse failure for saycid option\n");
10952 res = 1;
10953 }
10954 if (!ast_test_flag(vmu, VM_SVMAIL)) {
10955 ast_test_status_update(test, "Parse failure for sendvoicemail option\n");
10956 res = 1;
10957 }
10958 if (!ast_test_flag(vmu, VM_REVIEW)) {
10959 ast_test_status_update(test, "Parse failure for review option\n");
10960 res = 1;
10961 }
10962 if (!ast_test_flag(vmu, VM_TEMPGREETWARN)) {
10963 ast_test_status_update(test, "Parse failure for tempgreetwarm option\n");
10964 res = 1;
10965 }
10966 if (!ast_test_flag(vmu, VM_MESSAGEWRAP)) {
10967 ast_test_status_update(test, "Parse failure for messagewrap option\n");
10968 res = 1;
10969 }
10970 if (!ast_test_flag(vmu, VM_OPERATOR)) {
10971 ast_test_status_update(test, "Parse failure for operator option\n");
10972 res = 1;
10973 }
10974 if (!ast_test_flag(vmu, VM_ENVELOPE)) {
10975 ast_test_status_update(test, "Parse failure for envelope option\n");
10976 res = 1;
10977 }
10978 if (!ast_test_flag(vmu, VM_MOVEHEARD)) {
10979 ast_test_status_update(test, "Parse failure for moveheard option\n");
10980 res = 1;
10981 }
10982 if (!ast_test_flag(vmu, VM_SAYDURATION)) {
10983 ast_test_status_update(test, "Parse failure for sayduration option\n");
10984 res = 1;
10985 }
10986 if (vmu->saydurationm != 5) {
10987 ast_test_status_update(test, "Parse failure for saydurationm option\n");
10988 res = 1;
10989 }
10990 if (!ast_test_flag(vmu, VM_FORCENAME)) {
10991 ast_test_status_update(test, "Parse failure for forcename option\n");
10992 res = 1;
10993 }
10994 if (!ast_test_flag(vmu, VM_FORCEGREET)) {
10995 ast_test_status_update(test, "Parse failure for forcegreetings option\n");
10996 res = 1;
10997 }
10998 if (strcasecmp(vmu->callback, "somecontext")) {
10999 ast_test_status_update(test, "Parse failure for callbacks option\n");
11000 res = 1;
11001 }
11002 if (strcasecmp(vmu->dialout, "somecontext2")) {
11003 ast_test_status_update(test, "Parse failure for dialout option\n");
11004 res = 1;
11005 }
11006 if (strcasecmp(vmu->exit, "somecontext3")) {
11007 ast_test_status_update(test, "Parse failure for exitcontext option\n");
11008 res = 1;
11009 }
11010 if (vmu->minsecs != 10) {
11011 ast_test_status_update(test, "Parse failure for minsecs option\n");
11012 res = 1;
11013 }
11014 if (vmu->maxsecs != 100) {
11015 ast_test_status_update(test, "Parse failure for maxsecs option\n");
11016 res = 1;
11017 }
11018 if (!ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
11019 ast_test_status_update(test, "Parse failure for nextaftercmd option\n");
11020 res = 1;
11021 }
11022 if (vmu->maxdeletedmsg != 50) {
11023 ast_test_status_update(test, "Parse failure for backupdeleted option\n");
11024 res = 1;
11025 }
11026 if (vmu->volgain != 1.3) {
11027 ast_test_status_update(test, "Parse failure for volgain option\n");
11028 res = 1;
11029 }
11030 if (vmu->passwordlocation != OPT_PWLOC_SPOOLDIR) {
11031 ast_test_status_update(test, "Parse failure for passwordlocation option\n");
11032 res = 1;
11033 }
11034 #ifdef IMAP_STORAGE
11035 apply_options(vmu, option_string2);
11036
11037 if (strcasecmp(vmu->imapuser, "imapuser")) {
11038 ast_test_status_update(test, "Parse failure for imapuser option\n");
11039 res = 1;
11040 }
11041 if (strcasecmp(vmu->imappassword, "imappasswd")) {
11042 ast_test_status_update(test, "Parse failure for imappasswd option\n");
11043 res = 1;
11044 }
11045 if (strcasecmp(vmu->imapfolder, "INBOX")) {
11046 ast_test_status_update(test, "Parse failure for imappasswd option\n");
11047 res = 1;
11048 }
11049 if (strcasecmp(vmu->imapvmshareid, "6000")) {
11050 ast_test_status_update(test, "Parse failure for imapvmshareid option\n");
11051 res = 1;
11052 }
11053 if (strcasecmp(vmu->imapserver, "imapserver")) {
11054 ast_test_status_update(test, "Parse failure for imapserver option\n");
11055 res = 1;
11056 }
11057 if (strcasecmp(vmu->imapport, "1234")) {
11058 ast_test_status_update(test, "Parse failure for imapport option\n");
11059 res = 1;
11060 }
11061 if (strcasecmp(vmu->imapflags, "flagged")) {
11062 ast_test_status_update(test, "Parse failure for imapflags option\n");
11063 res = 1;
11064 }
11065 #endif
11066
11067 free_user(vmu);
11068 return res ? AST_TEST_FAIL : AST_TEST_PASS;
11069 }
11070
11071 static int vm_box_exists(struct ast_channel *chan, const char *data)
11072 {
11073 struct ast_vm_user svm;
11074 char *context, *box;
11075 AST_DECLARE_APP_ARGS(args,
11076 AST_APP_ARG(mbox);
11077 AST_APP_ARG(options);
11078 );
11079 static int dep_warning = 0;
11080
11081 if (ast_strlen_zero(data)) {
11082 ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
11083 return -1;
11084 }
11085
11086 if (!dep_warning) {
11087 dep_warning = 1;
11088 ast_log(AST_LOG_WARNING, "MailboxExists is deprecated. Please use ${VM_INFO(%s,exists)} instead.\n", data);
11089 }
11090
11091 box = ast_strdupa(data);
11092
11093 AST_STANDARD_APP_ARGS(args, box);
11094
11095 if (args.options) {
11096 }
11097
11098 if ((context = strchr(args.mbox, '@'))) {
11099 *context = '\0';
11100 context++;
11101 }
11102
11103 if (find_user(&svm, context, args.mbox)) {
11104 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
11105 } else
11106 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
11107
11108 return 0;
11109 }
11110
11111 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
11112 {
11113 struct ast_vm_user svm;
11114 AST_DECLARE_APP_ARGS(arg,
11115 AST_APP_ARG(mbox);
11116 AST_APP_ARG(context);
11117 );
11118 static int dep_warning = 0;
11119
11120 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
11121
11122 if (ast_strlen_zero(arg.mbox)) {
11123 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
11124 return -1;
11125 }
11126
11127 if (!dep_warning) {
11128 dep_warning = 1;
11129 ast_log(AST_LOG_WARNING, "MAILBOX_EXISTS is deprecated. Please use ${VM_INFO(%s,exists)} instead.\n", args);
11130 }
11131
11132 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
11133 return 0;
11134 }
11135
11136 static int acf_vm_info(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
11137 {
11138 struct ast_vm_user *vmu = NULL;
11139 char *tmp, *mailbox, *context, *parse;
11140 int res = 0;
11141
11142 AST_DECLARE_APP_ARGS(arg,
11143 AST_APP_ARG(mailbox_context);
11144 AST_APP_ARG(attribute);
11145 AST_APP_ARG(folder);
11146 );
11147
11148 buf[0] = '\0';
11149
11150 if (ast_strlen_zero(args)) {
11151 ast_log(LOG_ERROR, "VM_INFO requires an argument (<mailbox>[@<context>],attribute[,folder])\n");
11152 return -1;
11153 }
11154
11155 parse = ast_strdupa(args);
11156 AST_STANDARD_APP_ARGS(arg, parse);
11157
11158 if (ast_strlen_zero(arg.mailbox_context) || ast_strlen_zero(arg.attribute)) {
11159 ast_log(LOG_ERROR, "VM_INFO requires an argument (<mailbox>[@<context>],attribute[,folder])\n");
11160 return -1;
11161 }
11162
11163 tmp = ast_strdupa(arg.mailbox_context);
11164 mailbox = strsep(&tmp, "@");
11165 context = strsep(&tmp, "");
11166
11167 if (ast_strlen_zero(context)) {
11168 context = "default";
11169 }
11170
11171 vmu = find_user(NULL, context, mailbox);
11172
11173 if (!strncasecmp(arg.attribute, "exists", 5)) {
11174 ast_copy_string(buf, vmu ? "1" : "0", len);
11175 return 0;
11176 }
11177
11178 if (vmu) {
11179 if (!strncasecmp(arg.attribute, "password", 8)) {
11180 ast_copy_string(buf, vmu->password, len);
11181 } else if (!strncasecmp(arg.attribute, "fullname", 8)) {
11182 ast_copy_string(buf, vmu->fullname, len);
11183 } else if (!strncasecmp(arg.attribute, "email", 5)) {
11184 ast_copy_string(buf, vmu->email, len);
11185 } else if (!strncasecmp(arg.attribute, "pager", 5)) {
11186 ast_copy_string(buf, vmu->pager, len);
11187 } else if (!strncasecmp(arg.attribute, "language", 8)) {
11188 ast_copy_string(buf, S_OR(vmu->language, ast_channel_language(chan)), len);
11189 } else if (!strncasecmp(arg.attribute, "locale", 6)) {
11190 ast_copy_string(buf, vmu->locale, len);
11191 } else if (!strncasecmp(arg.attribute, "tz", 2)) {
11192 ast_copy_string(buf, vmu->zonetag, len);
11193 } else if (!strncasecmp(arg.attribute, "count", 5)) {
11194
11195 res = messagecount(context, mailbox, arg.folder);
11196 if (res < 0) {
11197 ast_log(LOG_ERROR, "Unable to retrieve message count for mailbox %s\n", arg.mailbox_context);
11198 return -1;
11199 }
11200 snprintf(buf, len, "%d", res);
11201 } else {
11202 ast_log(LOG_ERROR, "Unknown attribute '%s' for VM_INFO\n", arg.attribute);
11203 return -1;
11204 }
11205 }
11206
11207 return 0;
11208 }
11209
11210 static struct ast_custom_function mailbox_exists_acf = {
11211 .name = "MAILBOX_EXISTS",
11212 .read = acf_mailbox_exists,
11213 };
11214
11215 static struct ast_custom_function vm_info_acf = {
11216 .name = "VM_INFO",
11217 .read = acf_vm_info,
11218 };
11219
11220 static int vmauthenticate(struct ast_channel *chan, const char *data)
11221 {
11222 char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
11223 struct ast_vm_user vmus;
11224 char *options = NULL;
11225 int silent = 0, skipuser = 0;
11226 int res = -1;
11227
11228 if (data) {
11229 s = ast_strdupa(data);
11230 user = strsep(&s, ",");
11231 options = strsep(&s, ",");
11232 if (user) {
11233 s = user;
11234 user = strsep(&s, "@");
11235 context = strsep(&s, "");
11236 if (!ast_strlen_zero(user))
11237 skipuser++;
11238 ast_copy_string(mailbox, user, sizeof(mailbox));
11239 }
11240 }
11241
11242 if (options) {
11243 silent = (strchr(options, 's')) != NULL;
11244 }
11245
11246 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
11247 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
11248 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
11249 ast_play_and_wait(chan, "auth-thankyou");
11250 res = 0;
11251 } else if (mailbox[0] == '*') {
11252
11253 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
11254 res = 0;
11255 }
11256 }
11257
11258 return res;
11259 }
11260
11261 static char *show_users_realtime(int fd, const char *context)
11262 {
11263 struct ast_config *cfg;
11264 const char *cat = NULL;
11265
11266 if (!(cfg = ast_load_realtime_multientry("voicemail",
11267 "context", context, SENTINEL))) {
11268 return CLI_FAILURE;
11269 }
11270
11271 ast_cli(fd,
11272 "\n"
11273 "=============================================================\n"
11274 "=== Configured Voicemail Users ==============================\n"
11275 "=============================================================\n"
11276 "===\n");
11277
11278 while ((cat = ast_category_browse(cfg, cat))) {
11279 struct ast_variable *var = NULL;
11280 ast_cli(fd,
11281 "=== Mailbox ...\n"
11282 "===\n");
11283 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
11284 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
11285 ast_cli(fd,
11286 "===\n"
11287 "=== ---------------------------------------------------------\n"
11288 "===\n");
11289 }
11290
11291 ast_cli(fd,
11292 "=============================================================\n"
11293 "\n");
11294
11295 ast_config_destroy(cfg);
11296
11297 return CLI_SUCCESS;
11298 }
11299
11300 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
11301 {
11302 int which = 0;
11303 int wordlen;
11304 struct ast_vm_user *vmu;
11305 const char *context = "";
11306
11307
11308 if (pos > 4)
11309 return NULL;
11310 if (pos == 3)
11311 return (state == 0) ? ast_strdup("for") : NULL;
11312 wordlen = strlen(word);
11313 AST_LIST_TRAVERSE(&users, vmu, list) {
11314 if (!strncasecmp(word, vmu->context, wordlen)) {
11315 if (context && strcmp(context, vmu->context) && ++which > state)
11316 return ast_strdup(vmu->context);
11317
11318 context = vmu->context;
11319 }
11320 }
11321 return NULL;
11322 }
11323
11324
11325 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11326 {
11327 struct ast_vm_user *vmu;
11328 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
11329 const char *context = NULL;
11330 int users_counter = 0;
11331
11332 switch (cmd) {
11333 case CLI_INIT:
11334 e->command = "voicemail show users";
11335 e->usage =
11336 "Usage: voicemail show users [for <context>]\n"
11337 " Lists all mailboxes currently set up\n";
11338 return NULL;
11339 case CLI_GENERATE:
11340 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
11341 }
11342
11343 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
11344 return CLI_SHOWUSAGE;
11345 if (a->argc == 5) {
11346 if (strcmp(a->argv[3],"for"))
11347 return CLI_SHOWUSAGE;
11348 context = a->argv[4];
11349 }
11350
11351 if (ast_check_realtime("voicemail")) {
11352 if (!context) {
11353 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
11354 return CLI_SHOWUSAGE;
11355 }
11356 return show_users_realtime(a->fd, context);
11357 }
11358
11359 AST_LIST_LOCK(&users);
11360 if (AST_LIST_EMPTY(&users)) {
11361 ast_cli(a->fd, "There are no voicemail users currently defined\n");
11362 AST_LIST_UNLOCK(&users);
11363 return CLI_FAILURE;
11364 }
11365 if (a->argc == 3)
11366 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11367 else {
11368 int count = 0;
11369 AST_LIST_TRAVERSE(&users, vmu, list) {
11370 if (!strcmp(context, vmu->context))
11371 count++;
11372 }
11373 if (count) {
11374 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11375 } else {
11376 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
11377 AST_LIST_UNLOCK(&users);
11378 return CLI_FAILURE;
11379 }
11380 }
11381 AST_LIST_TRAVERSE(&users, vmu, list) {
11382 int newmsgs = 0, oldmsgs = 0;
11383 char count[12], tmp[256] = "";
11384
11385 if ((a->argc == 3) || ((a->argc == 5) && !strcmp(context, vmu->context))) {
11386 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
11387 inboxcount(tmp, &newmsgs, &oldmsgs);
11388 snprintf(count, sizeof(count), "%d", newmsgs);
11389 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
11390 users_counter++;
11391 }
11392 }
11393 AST_LIST_UNLOCK(&users);
11394 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
11395 return CLI_SUCCESS;
11396 }
11397
11398
11399 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11400 {
11401 struct vm_zone *zone;
11402 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
11403 char *res = CLI_SUCCESS;
11404
11405 switch (cmd) {
11406 case CLI_INIT:
11407 e->command = "voicemail show zones";
11408 e->usage =
11409 "Usage: voicemail show zones\n"
11410 " Lists zone message formats\n";
11411 return NULL;
11412 case CLI_GENERATE:
11413 return NULL;
11414 }
11415
11416 if (a->argc != 3)
11417 return CLI_SHOWUSAGE;
11418
11419 AST_LIST_LOCK(&zones);
11420 if (!AST_LIST_EMPTY(&zones)) {
11421 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
11422 AST_LIST_TRAVERSE(&zones, zone, list) {
11423 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
11424 }
11425 } else {
11426 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
11427 res = CLI_FAILURE;
11428 }
11429 AST_LIST_UNLOCK(&zones);
11430
11431 return res;
11432 }
11433
11434
11435 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11436 {
11437 switch (cmd) {
11438 case CLI_INIT:
11439 e->command = "voicemail reload";
11440 e->usage =
11441 "Usage: voicemail reload\n"
11442 " Reload voicemail configuration\n";
11443 return NULL;
11444 case CLI_GENERATE:
11445 return NULL;
11446 }
11447
11448 if (a->argc != 2)
11449 return CLI_SHOWUSAGE;
11450
11451 ast_cli(a->fd, "Reloading voicemail configuration...\n");
11452 load_config(1);
11453
11454 return CLI_SUCCESS;
11455 }
11456
11457 static struct ast_cli_entry cli_voicemail[] = {
11458 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
11459 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
11460 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
11461 };
11462
11463 #ifdef IMAP_STORAGE
11464 #define DATA_EXPORT_VM_USERS(USER) \
11465 USER(ast_vm_user, context, AST_DATA_STRING) \
11466 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11467 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11468 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11469 USER(ast_vm_user, email, AST_DATA_STRING) \
11470 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11471 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11472 USER(ast_vm_user, pager, AST_DATA_STRING) \
11473 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11474 USER(ast_vm_user, mailcmd, AST_DATA_STRING) \
11475 USER(ast_vm_user, language, AST_DATA_STRING) \
11476 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11477 USER(ast_vm_user, callback, AST_DATA_STRING) \
11478 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11479 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11480 USER(ast_vm_user, exit, AST_DATA_STRING) \
11481 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11482 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11483 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11484 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11485 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11486 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11487 USER(ast_vm_user, imapuser, AST_DATA_STRING) \
11488 USER(ast_vm_user, imappassword, AST_DATA_STRING) \
11489 USER(ast_vm_user, imapvmshareid, AST_DATA_STRING) \
11490 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11491 #else
11492 #define DATA_EXPORT_VM_USERS(USER) \
11493 USER(ast_vm_user, context, AST_DATA_STRING) \
11494 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11495 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11496 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11497 USER(ast_vm_user, email, AST_DATA_STRING) \
11498 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11499 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11500 USER(ast_vm_user, pager, AST_DATA_STRING) \
11501 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11502 USER(ast_vm_user, mailcmd, AST_DATA_STRING) \
11503 USER(ast_vm_user, language, AST_DATA_STRING) \
11504 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11505 USER(ast_vm_user, callback, AST_DATA_STRING) \
11506 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11507 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11508 USER(ast_vm_user, exit, AST_DATA_STRING) \
11509 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11510 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11511 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11512 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11513 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11514 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11515 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11516 #endif
11517
11518 AST_DATA_STRUCTURE(ast_vm_user, DATA_EXPORT_VM_USERS);
11519
11520 #define DATA_EXPORT_VM_ZONES(ZONE) \
11521 ZONE(vm_zone, name, AST_DATA_STRING) \
11522 ZONE(vm_zone, timezone, AST_DATA_STRING) \
11523 ZONE(vm_zone, msg_format, AST_DATA_STRING)
11524
11525 AST_DATA_STRUCTURE(vm_zone, DATA_EXPORT_VM_ZONES);
11526
11527
11528
11529
11530
11531
11532
11533
11534 static int vm_users_data_provider_get_helper(const struct ast_data_search *search,
11535 struct ast_data *data_root, struct ast_vm_user *user)
11536 {
11537 struct ast_data *data_user, *data_zone;
11538 struct ast_data *data_state;
11539 struct vm_zone *zone = NULL;
11540 int urgentmsg = 0, newmsg = 0, oldmsg = 0;
11541 char ext_context[256] = "";
11542
11543 data_user = ast_data_add_node(data_root, "user");
11544 if (!data_user) {
11545 return -1;
11546 }
11547
11548 ast_data_add_structure(ast_vm_user, data_user, user);
11549
11550 AST_LIST_LOCK(&zones);
11551 AST_LIST_TRAVERSE(&zones, zone, list) {
11552 if (!strcmp(zone->name, user->zonetag)) {
11553 break;
11554 }
11555 }
11556 AST_LIST_UNLOCK(&zones);
11557
11558
11559 data_state = ast_data_add_node(data_user, "state");
11560 if (!data_state) {
11561 return -1;
11562 }
11563 snprintf(ext_context, sizeof(ext_context), "%s@%s", user->mailbox, user->context);
11564 inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg);
11565 ast_data_add_int(data_state, "urgentmsg", urgentmsg);
11566 ast_data_add_int(data_state, "newmsg", newmsg);
11567 ast_data_add_int(data_state, "oldmsg", oldmsg);
11568
11569 if (zone) {
11570 data_zone = ast_data_add_node(data_user, "zone");
11571 ast_data_add_structure(vm_zone, data_zone, zone);
11572 }
11573
11574 if (!ast_data_search_match(search, data_user)) {
11575 ast_data_remove_node(data_root, data_user);
11576 }
11577
11578 return 0;
11579 }
11580
11581 static int vm_users_data_provider_get(const struct ast_data_search *search,
11582 struct ast_data *data_root)
11583 {
11584 struct ast_vm_user *user;
11585
11586 AST_LIST_LOCK(&users);
11587 AST_LIST_TRAVERSE(&users, user, list) {
11588 vm_users_data_provider_get_helper(search, data_root, user);
11589 }
11590 AST_LIST_UNLOCK(&users);
11591
11592 return 0;
11593 }
11594
11595 static const struct ast_data_handler vm_users_data_provider = {
11596 .version = AST_DATA_HANDLER_VERSION,
11597 .get = vm_users_data_provider_get
11598 };
11599
11600 static const struct ast_data_entry vm_data_providers[] = {
11601 AST_DATA_ENTRY("asterisk/application/voicemail/list", &vm_users_data_provider)
11602 };
11603
11604 static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
11605 {
11606 int new = 0, old = 0, urgent = 0;
11607
11608 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
11609
11610 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
11611 mwi_sub->old_urgent = urgent;
11612 mwi_sub->old_new = new;
11613 mwi_sub->old_old = old;
11614 queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
11615 run_externnotify(NULL, mwi_sub->mailbox, NULL);
11616 }
11617 }
11618
11619 static void poll_subscribed_mailboxes(void)
11620 {
11621 struct mwi_sub *mwi_sub;
11622
11623 AST_RWLIST_RDLOCK(&mwi_subs);
11624 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
11625 if (!ast_strlen_zero(mwi_sub->mailbox)) {
11626 poll_subscribed_mailbox(mwi_sub);
11627 }
11628 }
11629 AST_RWLIST_UNLOCK(&mwi_subs);
11630 }
11631
11632 static void *mb_poll_thread(void *data)
11633 {
11634 while (poll_thread_run) {
11635 struct timespec ts = { 0, };
11636 struct timeval wait;
11637
11638 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
11639 ts.tv_sec = wait.tv_sec;
11640 ts.tv_nsec = wait.tv_usec * 1000;
11641
11642 ast_mutex_lock(&poll_lock);
11643 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
11644 ast_mutex_unlock(&poll_lock);
11645
11646 if (!poll_thread_run)
11647 break;
11648
11649 poll_subscribed_mailboxes();
11650 }
11651
11652 return NULL;
11653 }
11654
11655 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
11656 {
11657 ast_free(mwi_sub);
11658 }
11659
11660 static int handle_unsubscribe(void *datap)
11661 {
11662 struct mwi_sub *mwi_sub;
11663 uint32_t *uniqueid = datap;
11664
11665 AST_RWLIST_WRLOCK(&mwi_subs);
11666 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
11667 if (mwi_sub->uniqueid == *uniqueid) {
11668 AST_LIST_REMOVE_CURRENT(entry);
11669 break;
11670 }
11671 }
11672 AST_RWLIST_TRAVERSE_SAFE_END
11673 AST_RWLIST_UNLOCK(&mwi_subs);
11674
11675 if (mwi_sub)
11676 mwi_sub_destroy(mwi_sub);
11677
11678 ast_free(uniqueid);
11679 return 0;
11680 }
11681
11682 static int handle_subscribe(void *datap)
11683 {
11684 unsigned int len;
11685 struct mwi_sub *mwi_sub;
11686 struct mwi_sub_task *p = datap;
11687
11688 len = sizeof(*mwi_sub);
11689 if (!ast_strlen_zero(p->mailbox))
11690 len += strlen(p->mailbox);
11691
11692 if (!ast_strlen_zero(p->context))
11693 len += strlen(p->context) + 1;
11694
11695 if (!(mwi_sub = ast_calloc(1, len)))
11696 return -1;
11697
11698 mwi_sub->uniqueid = p->uniqueid;
11699 if (!ast_strlen_zero(p->mailbox))
11700 strcpy(mwi_sub->mailbox, p->mailbox);
11701
11702 if (!ast_strlen_zero(p->context)) {
11703 strcat(mwi_sub->mailbox, "@");
11704 strcat(mwi_sub->mailbox, p->context);
11705 }
11706
11707 AST_RWLIST_WRLOCK(&mwi_subs);
11708 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
11709 AST_RWLIST_UNLOCK(&mwi_subs);
11710 ast_free((void *) p->mailbox);
11711 ast_free((void *) p->context);
11712 ast_free(p);
11713 poll_subscribed_mailbox(mwi_sub);
11714 return 0;
11715 }
11716
11717 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
11718 {
11719 uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
11720 if (ast_event_get_type(event) != AST_EVENT_UNSUB)
11721 return;
11722
11723 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11724 return;
11725
11726 u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11727 *uniqueid = u;
11728 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
11729 ast_free(uniqueid);
11730 }
11731 }
11732
11733 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
11734 {
11735 struct mwi_sub_task *mwist;
11736
11737 if (ast_event_get_type(event) != AST_EVENT_SUB)
11738 return;
11739
11740 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11741 return;
11742
11743 if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
11744 ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
11745 return;
11746 }
11747 mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
11748 mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
11749 mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11750
11751 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
11752 ast_free(mwist);
11753 }
11754 }
11755
11756 static void start_poll_thread(void)
11757 {
11758 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, "Voicemail MWI subscription", NULL,
11759 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11760 AST_EVENT_IE_END);
11761
11762 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, "Voicemail MWI subscription", NULL,
11763 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11764 AST_EVENT_IE_END);
11765
11766 if (mwi_sub_sub)
11767 ast_event_report_subs(mwi_sub_sub);
11768
11769 poll_thread_run = 1;
11770
11771 ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL);
11772 }
11773
11774 static void stop_poll_thread(void)
11775 {
11776 poll_thread_run = 0;
11777
11778 if (mwi_sub_sub) {
11779 ast_event_unsubscribe(mwi_sub_sub);
11780 mwi_sub_sub = NULL;
11781 }
11782
11783 if (mwi_unsub_sub) {
11784 ast_event_unsubscribe(mwi_unsub_sub);
11785 mwi_unsub_sub = NULL;
11786 }
11787
11788 ast_mutex_lock(&poll_lock);
11789 ast_cond_signal(&poll_cond);
11790 ast_mutex_unlock(&poll_lock);
11791
11792 pthread_join(poll_thread, NULL);
11793
11794 poll_thread = AST_PTHREADT_NULL;
11795 }
11796
11797
11798 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
11799 {
11800 struct ast_vm_user *vmu = NULL;
11801 const char *id = astman_get_header(m, "ActionID");
11802 char actionid[128] = "";
11803
11804 if (!ast_strlen_zero(id))
11805 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
11806
11807 AST_LIST_LOCK(&users);
11808
11809 if (AST_LIST_EMPTY(&users)) {
11810 astman_send_ack(s, m, "There are no voicemail users currently defined.");
11811 AST_LIST_UNLOCK(&users);
11812 return RESULT_SUCCESS;
11813 }
11814
11815 astman_send_ack(s, m, "Voicemail user list will follow");
11816
11817 AST_LIST_TRAVERSE(&users, vmu, list) {
11818 char dirname[256];
11819
11820 #ifdef IMAP_STORAGE
11821 int new, old;
11822 inboxcount(vmu->mailbox, &new, &old);
11823 #endif
11824
11825 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
11826 astman_append(s,
11827 "%s"
11828 "Event: VoicemailUserEntry\r\n"
11829 "VMContext: %s\r\n"
11830 "VoiceMailbox: %s\r\n"
11831 "Fullname: %s\r\n"
11832 "Email: %s\r\n"
11833 "Pager: %s\r\n"
11834 "ServerEmail: %s\r\n"
11835 "MailCommand: %s\r\n"
11836 "Language: %s\r\n"
11837 "TimeZone: %s\r\n"
11838 "Callback: %s\r\n"
11839 "Dialout: %s\r\n"
11840 "UniqueID: %s\r\n"
11841 "ExitContext: %s\r\n"
11842 "SayDurationMinimum: %d\r\n"
11843 "SayEnvelope: %s\r\n"
11844 "SayCID: %s\r\n"
11845 "AttachMessage: %s\r\n"
11846 "AttachmentFormat: %s\r\n"
11847 "DeleteMessage: %s\r\n"
11848 "VolumeGain: %.2f\r\n"
11849 "CanReview: %s\r\n"
11850 "CallOperator: %s\r\n"
11851 "MaxMessageCount: %d\r\n"
11852 "MaxMessageLength: %d\r\n"
11853 "NewMessageCount: %d\r\n"
11854 #ifdef IMAP_STORAGE
11855 "OldMessageCount: %d\r\n"
11856 "IMAPUser: %s\r\n"
11857 "IMAPServer: %s\r\n"
11858 "IMAPPort: %s\r\n"
11859 "IMAPFlags: %s\r\n"
11860 #endif
11861 "\r\n",
11862 actionid,
11863 vmu->context,
11864 vmu->mailbox,
11865 vmu->fullname,
11866 vmu->email,
11867 vmu->pager,
11868 vmu->serveremail,
11869 vmu->mailcmd,
11870 vmu->language,
11871 vmu->zonetag,
11872 vmu->callback,
11873 vmu->dialout,
11874 vmu->uniqueid,
11875 vmu->exit,
11876 vmu->saydurationm,
11877 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
11878 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
11879 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
11880 vmu->attachfmt,
11881 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
11882 vmu->volgain,
11883 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
11884 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
11885 vmu->maxmsg,
11886 vmu->maxsecs,
11887 #ifdef IMAP_STORAGE
11888 new, old,
11889 vmu->imapuser,
11890 vmu->imapserver,
11891 vmu->imapport,
11892 vmu->imapflags
11893 #else
11894 count_messages(vmu, dirname)
11895 #endif
11896 );
11897 }
11898 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
11899
11900 AST_LIST_UNLOCK(&users);
11901
11902 return RESULT_SUCCESS;
11903 }
11904
11905
11906 static void free_vm_users(void)
11907 {
11908 struct ast_vm_user *current;
11909 AST_LIST_LOCK(&users);
11910 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
11911 ast_set_flag(current, VM_ALLOCED);
11912 free_user(current);
11913 }
11914 AST_LIST_UNLOCK(&users);
11915 }
11916
11917
11918 static void free_vm_zones(void)
11919 {
11920 struct vm_zone *zcur;
11921 AST_LIST_LOCK(&zones);
11922 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
11923 free_zone(zcur);
11924 AST_LIST_UNLOCK(&zones);
11925 }
11926
11927 static const char *substitute_escapes(const char *value)
11928 {
11929 char *current;
11930
11931
11932 struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
11933
11934 ast_str_reset(str);
11935
11936
11937 for (current = (char *) value; *current; current++) {
11938 if (*current == '\\') {
11939 current++;
11940 if (!*current) {
11941 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
11942 break;
11943 }
11944 switch (*current) {
11945 case '\\':
11946 ast_str_append(&str, 0, "\\");
11947 break;
11948 case 'r':
11949 ast_str_append(&str, 0, "\r");
11950 break;
11951 case 'n':
11952 #ifdef IMAP_STORAGE
11953 if (!str->used || str->str[str->used - 1] != '\r') {
11954 ast_str_append(&str, 0, "\r");
11955 }
11956 #endif
11957 ast_str_append(&str, 0, "\n");
11958 break;
11959 case 't':
11960 ast_str_append(&str, 0, "\t");
11961 break;
11962 default:
11963 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
11964 break;
11965 }
11966 } else {
11967 ast_str_append(&str, 0, "%c", *current);
11968 }
11969 }
11970
11971 return ast_str_buffer(str);
11972 }
11973
11974 static int load_config(int reload)
11975 {
11976 struct ast_config *cfg, *ucfg;
11977 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
11978 int res;
11979
11980 ast_unload_realtime("voicemail");
11981 ast_unload_realtime("voicemail_data");
11982
11983 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11984 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11985 return 0;
11986 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
11987 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11988 ucfg = NULL;
11989 }
11990 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11991 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
11992 ast_config_destroy(ucfg);
11993 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11994 return 0;
11995 }
11996 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
11997 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11998 return 0;
11999 } else {
12000 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
12001 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
12002 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
12003 ucfg = NULL;
12004 }
12005 }
12006
12007 res = actual_load_config(reload, cfg, ucfg);
12008
12009 ast_config_destroy(cfg);
12010 ast_config_destroy(ucfg);
12011
12012 return res;
12013 }
12014
12015 #ifdef TEST_FRAMEWORK
12016 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg)
12017 {
12018 ast_unload_realtime("voicemail");
12019 ast_unload_realtime("voicemail_data");
12020 return actual_load_config(reload, cfg, ucfg);
12021 }
12022 #endif
12023
12024 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg)
12025 {
12026 struct ast_vm_user *current;
12027 char *cat;
12028 struct ast_variable *var;
12029 const char *val;
12030 char *q, *stringp, *tmp;
12031 int x;
12032 int tmpadsi[4];
12033 char secretfn[PATH_MAX] = "";
12034
12035 #ifdef IMAP_STORAGE
12036 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
12037 #endif
12038
12039 strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
12040 strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
12041 strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
12042 strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
12043 strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);
12044
12045
12046 free_vm_users();
12047
12048
12049 free_vm_zones();
12050
12051 AST_LIST_LOCK(&users);
12052
12053 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
12054 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
12055
12056 if (cfg) {
12057
12058
12059 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
12060 val = "default";
12061 ast_copy_string(userscontext, val, sizeof(userscontext));
12062
12063 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
12064 val = "yes";
12065 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
12066
12067 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
12068 val = "no";
12069 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
12070
12071 volgain = 0.0;
12072 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
12073 sscanf(val, "%30lf", &volgain);
12074
12075 #ifdef ODBC_STORAGE
12076 strcpy(odbc_database, "asterisk");
12077 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
12078 ast_copy_string(odbc_database, val, sizeof(odbc_database));
12079 }
12080 strcpy(odbc_table, "voicemessages");
12081 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
12082 ast_copy_string(odbc_table, val, sizeof(odbc_table));
12083 }
12084 #endif
12085
12086 strcpy(mailcmd, SENDMAIL);
12087 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
12088 ast_copy_string(mailcmd, val, sizeof(mailcmd));
12089
12090 maxsilence = 0;
12091 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
12092 maxsilence = atoi(val);
12093 if (maxsilence > 0)
12094 maxsilence *= 1000;
12095 }
12096
12097 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
12098 maxmsg = MAXMSG;
12099 } else {
12100 maxmsg = atoi(val);
12101 if (maxmsg < 0) {
12102 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
12103 maxmsg = MAXMSG;
12104 } else if (maxmsg > MAXMSGLIMIT) {
12105 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
12106 maxmsg = MAXMSGLIMIT;
12107 }
12108 }
12109
12110 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
12111 maxdeletedmsg = 0;
12112 } else {
12113 if (sscanf(val, "%30d", &x) == 1)
12114 maxdeletedmsg = x;
12115 else if (ast_true(val))
12116 maxdeletedmsg = MAXMSG;
12117 else
12118 maxdeletedmsg = 0;
12119
12120 if (maxdeletedmsg < 0) {
12121 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
12122 maxdeletedmsg = MAXMSG;
12123 } else if (maxdeletedmsg > MAXMSGLIMIT) {
12124 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
12125 maxdeletedmsg = MAXMSGLIMIT;
12126 }
12127 }
12128
12129
12130 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
12131 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
12132 }
12133
12134
12135 if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
12136 ast_copy_string(pagerdateformat, val, sizeof(pagerdateformat));
12137 }
12138
12139
12140 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
12141 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
12142 pwdchange = PWDCHANGE_EXTERNAL;
12143 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
12144 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
12145 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
12146 }
12147
12148
12149 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
12150 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
12151 ast_debug(1, "found externpasscheck: %s\n", ext_pass_check_cmd);
12152 }
12153
12154 #ifdef IMAP_STORAGE
12155
12156 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
12157 ast_copy_string(imapserver, val, sizeof(imapserver));
12158 } else {
12159 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
12160 }
12161
12162 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
12163 ast_copy_string(imapport, val, sizeof(imapport));
12164 } else {
12165 ast_copy_string(imapport, "143", sizeof(imapport));
12166 }
12167
12168 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
12169 ast_copy_string(imapflags, val, sizeof(imapflags));
12170 }
12171
12172 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
12173 ast_copy_string(authuser, val, sizeof(authuser));
12174 }
12175
12176 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
12177 ast_copy_string(authpassword, val, sizeof(authpassword));
12178 }
12179
12180 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
12181 if (ast_false(val))
12182 expungeonhangup = 0;
12183 else
12184 expungeonhangup = 1;
12185 } else {
12186 expungeonhangup = 1;
12187 }
12188
12189 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
12190 ast_copy_string(imapfolder, val, sizeof(imapfolder));
12191 } else {
12192 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
12193 }
12194 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
12195 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
12196 }
12197 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
12198 imapgreetings = ast_true(val);
12199 } else {
12200 imapgreetings = 0;
12201 }
12202 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
12203 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12204 } else if ((val = ast_variable_retrieve(cfg, "general", "greetingsfolder"))) {
12205
12206 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12207 } else {
12208 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
12209 }
12210
12211
12212
12213
12214
12215 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
12216 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
12217 } else {
12218 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
12219 }
12220
12221 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
12222 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
12223 } else {
12224 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
12225 }
12226
12227 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
12228 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
12229 } else {
12230 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
12231 }
12232
12233 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
12234 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
12235 } else {
12236 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
12237 }
12238
12239
12240 imapversion++;
12241 #endif
12242
12243 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
12244 ast_copy_string(externnotify, val, sizeof(externnotify));
12245 ast_debug(1, "found externnotify: %s\n", externnotify);
12246 } else {
12247 externnotify[0] = '\0';
12248 }
12249
12250
12251 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
12252 ast_debug(1, "Enabled SMDI voicemail notification\n");
12253 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
12254 smdi_iface = ast_smdi_interface_find(val);
12255 } else {
12256 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
12257 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
12258 }
12259 if (!smdi_iface) {
12260 ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
12261 }
12262 }
12263
12264
12265 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
12266 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
12267 silencethreshold = atoi(val);
12268
12269 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
12270 val = ASTERISK_USERNAME;
12271 ast_copy_string(serveremail, val, sizeof(serveremail));
12272
12273 vmmaxsecs = 0;
12274 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
12275 if (sscanf(val, "%30d", &x) == 1) {
12276 vmmaxsecs = x;
12277 } else {
12278 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12279 }
12280 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
12281 static int maxmessage_deprecate = 0;
12282 if (maxmessage_deprecate == 0) {
12283 maxmessage_deprecate = 1;
12284 ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
12285 }
12286 if (sscanf(val, "%30d", &x) == 1) {
12287 vmmaxsecs = x;
12288 } else {
12289 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12290 }
12291 }
12292
12293 vmminsecs = 0;
12294 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
12295 if (sscanf(val, "%30d", &x) == 1) {
12296 vmminsecs = x;
12297 if (maxsilence / 1000 >= vmminsecs) {
12298 ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
12299 }
12300 } else {
12301 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12302 }
12303 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
12304 static int maxmessage_deprecate = 0;
12305 if (maxmessage_deprecate == 0) {
12306 maxmessage_deprecate = 1;
12307 ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
12308 }
12309 if (sscanf(val, "%30d", &x) == 1) {
12310 vmminsecs = x;
12311 if (maxsilence / 1000 >= vmminsecs) {
12312 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
12313 }
12314 } else {
12315 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12316 }
12317 }
12318
12319 val = ast_variable_retrieve(cfg, "general", "format");
12320 if (!val) {
12321 val = "wav";
12322 } else {
12323 tmp = ast_strdupa(val);
12324 val = ast_format_str_reduce(tmp);
12325 if (!val) {
12326 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
12327 val = "wav";
12328 }
12329 }
12330 ast_copy_string(vmfmts, val, sizeof(vmfmts));
12331
12332 skipms = 3000;
12333 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
12334 if (sscanf(val, "%30d", &x) == 1) {
12335 maxgreet = x;
12336 } else {
12337 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
12338 }
12339 }
12340
12341 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
12342 if (sscanf(val, "%30d", &x) == 1) {
12343 skipms = x;
12344 } else {
12345 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
12346 }
12347 }
12348
12349 maxlogins = 3;
12350 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
12351 if (sscanf(val, "%30d", &x) == 1) {
12352 maxlogins = x;
12353 } else {
12354 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
12355 }
12356 }
12357
12358 minpassword = MINPASSWORD;
12359 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
12360 if (sscanf(val, "%30d", &x) == 1) {
12361 minpassword = x;
12362 } else {
12363 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
12364 }
12365 }
12366
12367
12368 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
12369 val = "no";
12370 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
12371
12372
12373 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
12374 val = "no";
12375 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
12376
12377 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
12378 ast_debug(1, "VM_CID Internal context string: %s\n", val);
12379 stringp = ast_strdupa(val);
12380 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
12381 if (!ast_strlen_zero(stringp)) {
12382 q = strsep(&stringp, ",");
12383 while ((*q == ' ')||(*q == '\t'))
12384 q++;
12385 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
12386 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
12387 } else {
12388 cidinternalcontexts[x][0] = '\0';
12389 }
12390 }
12391 }
12392 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
12393 ast_debug(1, "VM Review Option disabled globally\n");
12394 val = "no";
12395 }
12396 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
12397
12398
12399 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
12400 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
12401 val = "no";
12402 } else {
12403 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
12404 }
12405 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
12406 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
12407 ast_debug(1, "VM next message wrap disabled globally\n");
12408 val = "no";
12409 }
12410 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);
12411
12412 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
12413 ast_debug(1, "VM Operator break disabled globally\n");
12414 val = "no";
12415 }
12416 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
12417
12418 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
12419 ast_debug(1, "VM CID Info before msg disabled globally\n");
12420 val = "no";
12421 }
12422 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
12423
12424 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
12425 ast_debug(1, "Send Voicemail msg disabled globally\n");
12426 val = "no";
12427 }
12428 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
12429
12430 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
12431 ast_debug(1, "ENVELOPE before msg enabled globally\n");
12432 val = "yes";
12433 }
12434 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
12435
12436 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
12437 ast_debug(1, "Move Heard enabled globally\n");
12438 val = "yes";
12439 }
12440 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
12441
12442 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
12443 ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
12444 val = "no";
12445 }
12446 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);
12447
12448 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
12449 ast_debug(1, "Duration info before msg enabled globally\n");
12450 val = "yes";
12451 }
12452 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
12453
12454 saydurationminfo = 2;
12455 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
12456 if (sscanf(val, "%30d", &x) == 1) {
12457 saydurationminfo = x;
12458 } else {
12459 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
12460 }
12461 }
12462
12463 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
12464 ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
12465 val = "no";
12466 }
12467 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
12468
12469 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
12470 ast_copy_string(dialcontext, val, sizeof(dialcontext));
12471 ast_debug(1, "found dialout context: %s\n", dialcontext);
12472 } else {
12473 dialcontext[0] = '\0';
12474 }
12475
12476 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
12477 ast_copy_string(callcontext, val, sizeof(callcontext));
12478 ast_debug(1, "found callback context: %s\n", callcontext);
12479 } else {
12480 callcontext[0] = '\0';
12481 }
12482
12483 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
12484 ast_copy_string(exitcontext, val, sizeof(exitcontext));
12485 ast_debug(1, "found operator context: %s\n", exitcontext);
12486 } else {
12487 exitcontext[0] = '\0';
12488 }
12489
12490
12491 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
12492 ast_copy_string(vm_password, val, sizeof(vm_password));
12493 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
12494 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
12495 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
12496 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
12497 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
12498 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
12499 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
12500 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
12501 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
12502 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
12503 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
12504 ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
12505 }
12506 if ((val = ast_variable_retrieve(cfg, "general", "vm-prepend-timeout"))) {
12507 ast_copy_string(vm_prepend_timeout, val, sizeof(vm_prepend_timeout));
12508 }
12509
12510 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
12511 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
12512 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
12513 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
12514 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
12515 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
12516 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
12517 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
12518 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
12519 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
12520
12521 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
12522 val = "no";
12523 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
12524
12525 if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
12526 val = "voicemail.conf";
12527 }
12528 if (!(strcmp(val, "spooldir"))) {
12529 passwordlocation = OPT_PWLOC_SPOOLDIR;
12530 } else {
12531 passwordlocation = OPT_PWLOC_VOICEMAILCONF;
12532 }
12533
12534 poll_freq = DEFAULT_POLL_FREQ;
12535 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
12536 if (sscanf(val, "%30u", &poll_freq) != 1) {
12537 poll_freq = DEFAULT_POLL_FREQ;
12538 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
12539 }
12540 }
12541
12542 poll_mailboxes = 0;
12543 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
12544 poll_mailboxes = ast_true(val);
12545
12546 memset(fromstring, 0, sizeof(fromstring));
12547 memset(pagerfromstring, 0, sizeof(pagerfromstring));
12548 strcpy(charset, "ISO-8859-1");
12549 if (emailbody) {
12550 ast_free(emailbody);
12551 emailbody = NULL;
12552 }
12553 if (emailsubject) {
12554 ast_free(emailsubject);
12555 emailsubject = NULL;
12556 }
12557 if (pagerbody) {
12558 ast_free(pagerbody);
12559 pagerbody = NULL;
12560 }
12561 if (pagersubject) {
12562 ast_free(pagersubject);
12563 pagersubject = NULL;
12564 }
12565 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
12566 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
12567 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
12568 ast_copy_string(fromstring, val, sizeof(fromstring));
12569 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
12570 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
12571 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
12572 ast_copy_string(charset, val, sizeof(charset));
12573 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
12574 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12575 for (x = 0; x < 4; x++) {
12576 memcpy(&adsifdn[x], &tmpadsi[x], 1);
12577 }
12578 }
12579 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
12580 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12581 for (x = 0; x < 4; x++) {
12582 memcpy(&adsisec[x], &tmpadsi[x], 1);
12583 }
12584 }
12585 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
12586 if (atoi(val)) {
12587 adsiver = atoi(val);
12588 }
12589 }
12590 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
12591 ast_copy_string(zonetag, val, sizeof(zonetag));
12592 }
12593 if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
12594 ast_copy_string(locale, val, sizeof(locale));
12595 }
12596 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
12597 emailsubject = ast_strdup(substitute_escapes(val));
12598 }
12599 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
12600 emailbody = ast_strdup(substitute_escapes(val));
12601 }
12602 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
12603 pagersubject = ast_strdup(substitute_escapes(val));
12604 }
12605 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
12606 pagerbody = ast_strdup(substitute_escapes(val));
12607 }
12608
12609
12610 if (ucfg) {
12611 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
12612 if (!strcasecmp(cat, "general")) {
12613 continue;
12614 }
12615 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
12616 continue;
12617 if ((current = find_or_create(userscontext, cat))) {
12618 populate_defaults(current);
12619 apply_options_full(current, ast_variable_browse(ucfg, cat));
12620 ast_copy_string(current->context, userscontext, sizeof(current->context));
12621 if (!ast_strlen_zero(current->password) && current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
12622 current->passwordlocation = OPT_PWLOC_USERSCONF;
12623 }
12624
12625 switch (current->passwordlocation) {
12626 case OPT_PWLOC_SPOOLDIR:
12627 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
12628 read_password_from_file(secretfn, current->password, sizeof(current->password));
12629 }
12630 }
12631 }
12632 }
12633
12634
12635 cat = ast_category_browse(cfg, NULL);
12636 while (cat) {
12637 if (strcasecmp(cat, "general")) {
12638 var = ast_variable_browse(cfg, cat);
12639 if (strcasecmp(cat, "zonemessages")) {
12640
12641 while (var) {
12642 append_mailbox(cat, var->name, var->value);
12643 var = var->next;
12644 }
12645 } else {
12646
12647 while (var) {
12648 struct vm_zone *z;
12649 if ((z = ast_malloc(sizeof(*z)))) {
12650 char *msg_format, *tzone;
12651 msg_format = ast_strdupa(var->value);
12652 tzone = strsep(&msg_format, "|,");
12653 if (msg_format) {
12654 ast_copy_string(z->name, var->name, sizeof(z->name));
12655 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
12656 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
12657 AST_LIST_LOCK(&zones);
12658 AST_LIST_INSERT_HEAD(&zones, z, list);
12659 AST_LIST_UNLOCK(&zones);
12660 } else {
12661 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
12662 ast_free(z);
12663 }
12664 } else {
12665 AST_LIST_UNLOCK(&users);
12666 return -1;
12667 }
12668 var = var->next;
12669 }
12670 }
12671 }
12672 cat = ast_category_browse(cfg, cat);
12673 }
12674
12675 AST_LIST_UNLOCK(&users);
12676
12677 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
12678 start_poll_thread();
12679 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
12680 stop_poll_thread();;
12681
12682 return 0;
12683 } else {
12684 AST_LIST_UNLOCK(&users);
12685 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
12686 return 0;
12687 }
12688 }
12689
12690 static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
12691 {
12692 int res = -1;
12693 char dir[PATH_MAX];
12694 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
12695 ast_debug(2, "About to try retrieving name file %s\n", dir);
12696 RETRIEVE(dir, -1, mailbox, context);
12697 if (ast_fileexists(dir, NULL, NULL)) {
12698 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
12699 }
12700 DISPOSE(dir, -1);
12701 return res;
12702 }
12703
12704 static void read_password_from_file(const char *secretfn, char *password, int passwordlen) {
12705 struct ast_config *pwconf;
12706 struct ast_flags config_flags = { 0 };
12707
12708 pwconf = ast_config_load(secretfn, config_flags);
12709 if (pwconf) {
12710 const char *val = ast_variable_retrieve(pwconf, "general", "password");
12711 if (val) {
12712 ast_copy_string(password, val, passwordlen);
12713 return;
12714 }
12715 }
12716 ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
12717 }
12718
12719 static int write_password_to_file(const char *secretfn, const char *password) {
12720 struct ast_config *conf;
12721 struct ast_category *cat;
12722 struct ast_variable *var;
12723
12724 if (!(conf=ast_config_new())) {
12725 ast_log(LOG_ERROR, "Error creating new config structure\n");
12726 return -1;
12727 }
12728 if (!(cat=ast_category_new("general","",1))) {
12729 ast_log(LOG_ERROR, "Error creating new category structure\n");
12730 return -1;
12731 }
12732 if (!(var=ast_variable_new("password",password,""))) {
12733 ast_log(LOG_ERROR, "Error creating new variable structure\n");
12734 return -1;
12735 }
12736 ast_category_append(conf,cat);
12737 ast_variable_append(cat,var);
12738 if (ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
12739 ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn);
12740 return -1;
12741 }
12742 return 0;
12743 }
12744
12745 static int vmsayname_exec(struct ast_channel *chan, const char *data)
12746 {
12747 char *context;
12748 char *args_copy;
12749 int res;
12750
12751 if (ast_strlen_zero(data)) {
12752 ast_log(LOG_WARNING, "VMSayName requires argument mailbox@context");
12753 return -1;
12754 }
12755
12756 args_copy = ast_strdupa(data);
12757 if ((context = strchr(args_copy, '@'))) {
12758 *context++ = '\0';
12759 } else {
12760 context = "default";
12761 }
12762
12763 if ((res = sayname(chan, args_copy, context)) < 0) {
12764 ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context);
12765 res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
12766 if (!res) {
12767 res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, ast_channel_language(chan));
12768 }
12769 }
12770
12771 return res;
12772 }
12773
12774 #ifdef TEST_FRAMEWORK
12775 static int fake_write(struct ast_channel *ast, struct ast_frame *frame)
12776 {
12777 return 0;
12778 }
12779
12780 static struct ast_frame *fake_read(struct ast_channel *ast)
12781 {
12782 return &ast_null_frame;
12783 }
12784
12785 AST_TEST_DEFINE(test_voicemail_vmsayname)
12786 {
12787 char dir[PATH_MAX];
12788 char dir2[PATH_MAX];
12789 static const char TEST_CONTEXT[] = "very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
12790 static const char TEST_EXTENSION[] = "1234";
12791
12792 struct ast_channel *test_channel1 = NULL;
12793 int res = -1;
12794
12795 static const struct ast_channel_tech fake_tech = {
12796 .write = fake_write,
12797 .read = fake_read,
12798 };
12799
12800 switch (cmd) {
12801 case TEST_INIT:
12802 info->name = "vmsayname_exec";
12803 info->category = "/apps/app_voicemail/";
12804 info->summary = "Vmsayname unit test";
12805 info->description =
12806 "This tests passing various parameters to vmsayname";
12807 return AST_TEST_NOT_RUN;
12808 case TEST_EXECUTE:
12809 break;
12810 }
12811
12812 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
12813 NULL, NULL, 0, 0, "TestChannel1"))) {
12814 goto exit_vmsayname_test;
12815 }
12816
12817
12818 ast_format_set(&test_channel1->writeformat, AST_FORMAT_GSM, 0);
12819 ast_format_cap_add(test_channel1->nativeformats, &test_channel1->writeformat);
12820 ast_format_set(&test_channel1->rawwriteformat, AST_FORMAT_GSM, 0);
12821 ast_format_set(&test_channel1->readformat, AST_FORMAT_GSM, 0);
12822 ast_format_set(&test_channel1->rawreadformat, AST_FORMAT_GSM, 0);
12823 test_channel1->tech = &fake_tech;
12824
12825 ast_test_status_update(test, "Test playing of extension when greeting is not available...\n");
12826 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12827 if (!(res = vmsayname_exec(test_channel1, dir))) {
12828 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12829 if (ast_fileexists(dir, NULL, NULL)) {
12830 ast_test_status_update(test, "This should not happen, most likely means clean up from previous test failed\n");
12831 res = -1;
12832 goto exit_vmsayname_test;
12833 } else {
12834
12835 if ((res = create_dirpath(dir, sizeof(dir), TEST_CONTEXT, TEST_EXTENSION, ""))) {
12836 ast_log(AST_LOG_WARNING, "Failed to make test directory\n");
12837 goto exit_vmsayname_test;
12838 }
12839 snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_VAR_DIR);
12840 snprintf(dir2, sizeof(dir2), "%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12841
12842 if ((res = symlink(dir, dir2))) {
12843 ast_log(LOG_WARNING, "Symlink reported %s\n", strerror(errno));
12844 goto exit_vmsayname_test;
12845 }
12846 ast_test_status_update(test, "Test playing created mailbox greeting...\n");
12847 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12848 res = vmsayname_exec(test_channel1, dir);
12849
12850
12851 unlink(dir2);
12852 snprintf(dir2, sizeof(dir2), "%s%s/%s", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12853 rmdir(dir2);
12854 snprintf(dir2, sizeof(dir2), "%s%s", VM_SPOOL_DIR, TEST_CONTEXT);
12855 rmdir(dir2);
12856 }
12857 }
12858
12859 exit_vmsayname_test:
12860
12861 if (test_channel1) {
12862 ast_hangup(test_channel1);
12863 }
12864
12865 return res ? AST_TEST_FAIL : AST_TEST_PASS;
12866 }
12867
12868 AST_TEST_DEFINE(test_voicemail_msgcount)
12869 {
12870 int i, j, res = AST_TEST_PASS, syserr;
12871 struct ast_vm_user *vmu;
12872 struct vm_state vms;
12873 #ifdef IMAP_STORAGE
12874 struct ast_channel *chan = NULL;
12875 #endif
12876 struct {
12877 char dir[256];
12878 char file[256];
12879 char txtfile[256];
12880 } tmp[3];
12881 char syscmd[256];
12882 const char origweasels[] = "tt-weasels";
12883 const char testcontext[] = "test";
12884 const char testmailbox[] = "00000000";
12885 const char testspec[] = "00000000@test";
12886 FILE *txt;
12887 int new, old, urgent;
12888 const char *folders[3] = { "Old", "Urgent", "INBOX" };
12889 const int folder2mbox[3] = { 1, 11, 0 };
12890 const int expected_results[3][12] = {
12891
12892 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
12893 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
12894 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
12895 };
12896
12897 switch (cmd) {
12898 case TEST_INIT:
12899 info->name = "test_voicemail_msgcount";
12900 info->category = "/apps/app_voicemail/";
12901 info->summary = "Test Voicemail status checks";
12902 info->description =
12903 "Verify that message counts are correct when retrieved through the public API";
12904 return AST_TEST_NOT_RUN;
12905 case TEST_EXECUTE:
12906 break;
12907 }
12908
12909
12910 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12911 if ((syserr = ast_safe_system(syscmd))) {
12912 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12913 syserr > 0 ? strerror(syserr) : "unable to fork()");
12914 return AST_TEST_FAIL;
12915 }
12916
12917 #ifdef IMAP_STORAGE
12918 if (!(chan = ast_dummy_channel_alloc())) {
12919 ast_test_status_update(test, "Unable to create dummy channel\n");
12920 return AST_TEST_FAIL;
12921 }
12922 #endif
12923
12924 if (!(vmu = find_user(NULL, testcontext, testmailbox)) &&
12925 !(vmu = find_or_create(testcontext, testmailbox))) {
12926 ast_test_status_update(test, "Cannot create vmu structure\n");
12927 ast_unreplace_sigchld();
12928 #ifdef IMAP_STORAGE
12929 chan = ast_channel_unref(chan);
12930 #endif
12931 return AST_TEST_FAIL;
12932 }
12933
12934 populate_defaults(vmu);
12935 memset(&vms, 0, sizeof(vms));
12936
12937
12938 for (i = 0; i < 3; i++) {
12939 create_dirpath(tmp[i].dir, sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
12940 make_file(tmp[i].file, sizeof(tmp[i].file), tmp[i].dir, 0);
12941 snprintf(tmp[i].txtfile, sizeof(tmp[i].txtfile), "%s.txt", tmp[i].file);
12942
12943 if (ast_fileexists(origweasels, "gsm", "en") > 0) {
12944 snprintf(syscmd, sizeof(syscmd), "cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"", ast_config_AST_DATA_DIR, origweasels,
12945 VM_SPOOL_DIR, testcontext, testmailbox, folders[i]);
12946 if ((syserr = ast_safe_system(syscmd))) {
12947 ast_test_status_update(test, "Unable to create test voicemail: %s\n",
12948 syserr > 0 ? strerror(syserr) : "unable to fork()");
12949 ast_unreplace_sigchld();
12950 #ifdef IMAP_STORAGE
12951 chan = ast_channel_unref(chan);
12952 #endif
12953 return AST_TEST_FAIL;
12954 }
12955 }
12956
12957 if ((txt = fopen(tmp[i].txtfile, "w+"))) {
12958 fprintf(txt, "; just a stub\n[message]\nflag=%s\n", strcmp(folders[i], "Urgent") ? "" : "Urgent");
12959 fclose(txt);
12960 } else {
12961 ast_test_status_update(test, "Unable to write message file '%s'\n", tmp[i].txtfile);
12962 res = AST_TEST_FAIL;
12963 break;
12964 }
12965 open_mailbox(&vms, vmu, folder2mbox[i]);
12966 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu, "gsm", 600, &vms, strcmp(folders[i], "Urgent") ? "" : "Urgent");
12967
12968
12969 for (j = 0; j < 3; j++) {
12970
12971 if (ast_app_has_voicemail(testspec, (j==2 ? NULL : folders[j])) != expected_results[i][0 + j]) {
12972 ast_test_status_update(test, "has_voicemail(%s, %s) returned %d and we expected %d\n",
12973 testspec, folders[j], ast_app_has_voicemail(testspec, folders[j]), expected_results[i][0 + j]);
12974 res = AST_TEST_FAIL;
12975 }
12976 }
12977
12978 new = old = urgent = 0;
12979 if (ast_app_inboxcount(testspec, &new, &old)) {
12980 ast_test_status_update(test, "inboxcount returned failure\n");
12981 res = AST_TEST_FAIL;
12982 } else if (old != expected_results[i][3 + 0] || new != expected_results[i][3 + 2]) {
12983 ast_test_status_update(test, "inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n",
12984 testspec, old, expected_results[i][3 + 0], new, expected_results[i][3 + 2]);
12985 res = AST_TEST_FAIL;
12986 }
12987
12988 new = old = urgent = 0;
12989 if (ast_app_inboxcount2(testspec, &urgent, &new, &old)) {
12990 ast_test_status_update(test, "inboxcount2 returned failure\n");
12991 res = AST_TEST_FAIL;
12992 } else if (old != expected_results[i][6 + 0] ||
12993 urgent != expected_results[i][6 + 1] ||
12994 new != expected_results[i][6 + 2] ) {
12995 ast_test_status_update(test, "inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
12996 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1], new, expected_results[i][6 + 2]);
12997 res = AST_TEST_FAIL;
12998 }
12999
13000 new = old = urgent = 0;
13001 for (j = 0; j < 3; j++) {
13002 if (ast_app_messagecount(testcontext, testmailbox, folders[j]) != expected_results[i][9 + j]) {
13003 ast_test_status_update(test, "messagecount(%s, %s) returned %d and we expected %d\n",
13004 testspec, folders[j], ast_app_messagecount(testcontext, testmailbox, folders[j]), expected_results[i][9 + j]);
13005 res = AST_TEST_FAIL;
13006 }
13007 }
13008 }
13009
13010 for (i = 0; i < 3; i++) {
13011
13012
13013
13014 DELETE(tmp[i].dir, 0, tmp[i].file, vmu);
13015 DISPOSE(tmp[i].dir, 0);
13016 }
13017
13018 if (vms.deleted) {
13019 ast_free(vms.deleted);
13020 }
13021 if (vms.heard) {
13022 ast_free(vms.heard);
13023 }
13024
13025 #ifdef IMAP_STORAGE
13026 chan = ast_channel_unref(chan);
13027 #endif
13028
13029
13030 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
13031 if ((syserr = ast_safe_system(syscmd))) {
13032 ast_test_status_update(test, "Unable to clear test directory: %s\n",
13033 syserr > 0 ? strerror(syserr) : "unable to fork()");
13034 }
13035
13036 return res;
13037 }
13038
13039 AST_TEST_DEFINE(test_voicemail_notify_endl)
13040 {
13041 int res = AST_TEST_PASS;
13042 char testcontext[] = "test";
13043 char testmailbox[] = "00000000";
13044 char from[] = "test@example.net", cidnum[] = "1234", cidname[] = "Mark Spencer", format[] = "gsm";
13045 char attach[256], attach2[256];
13046 char buf[256] = "";
13047 struct ast_channel *chan = NULL;
13048 struct ast_vm_user *vmu, vmus = {
13049 .flags = 0,
13050 };
13051 FILE *file;
13052 struct {
13053 char *name;
13054 enum { INT, FLAGVAL, STATIC, STRPTR } type;
13055 void *location;
13056 union {
13057 int intval;
13058 char *strval;
13059 } u;
13060 } test_items[] = {
13061 { "plain jane config", STATIC, vmus.password, .u.strval = "1234" },
13062 { "emailsubject", STRPTR, vmus.emailsubject, .u.strval = "Oogly boogly\xf8koogly with what appears to be UTF-8" },
13063 { "emailbody", STRPTR, vmus.emailbody, .u.strval = "This is a test\n\twith multiple\nlines\nwithin\n" },
13064 { "serveremail", STATIC, vmus.serveremail, .u.strval = "\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
13065 { "attachment flag", FLAGVAL, &vmus.flags, .u.intval = VM_ATTACH },
13066 { "attach2", STRPTR, attach2, .u.strval = "" },
13067 { "attach", STRPTR, attach, .u.strval = "" },
13068 };
13069 int which;
13070
13071 switch (cmd) {
13072 case TEST_INIT:
13073 info->name = "test_voicemail_notify_endl";
13074 info->category = "/apps/app_voicemail/";
13075 info->summary = "Test Voicemail notification end-of-line";
13076 info->description =
13077 "Verify that notification emails use a consistent end-of-line character";
13078 return AST_TEST_NOT_RUN;
13079 case TEST_EXECUTE:
13080 break;
13081 }
13082
13083 snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_VAR_DIR);
13084 snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_VAR_DIR);
13085
13086 if (!(vmu = find_user(&vmus, testcontext, testmailbox)) &&
13087 !(vmu = find_or_create(testcontext, testmailbox))) {
13088 ast_test_status_update(test, "Cannot create vmu structure\n");
13089 return AST_TEST_NOT_RUN;
13090 }
13091
13092 if (vmu != &vmus && !(vmu = find_user(&vmus, testcontext, testmailbox))) {
13093 ast_test_status_update(test, "Cannot find vmu structure?!!\n");
13094 return AST_TEST_NOT_RUN;
13095 }
13096
13097 populate_defaults(vmu);
13098 ast_copy_string(vmu->email, "test2@example.net", sizeof(vmu->email));
13099 #ifdef IMAP_STORAGE
13100
13101 #endif
13102
13103 file = tmpfile();
13104 for (which = 0; which < ARRAY_LEN(test_items); which++) {
13105
13106 rewind(file);
13107 if (ftruncate(fileno(file), 0)) {
13108 ast_test_status_update(test, "Cannot truncate test output file: %s\n", strerror(errno));
13109 res = AST_TEST_FAIL;
13110 break;
13111 }
13112
13113
13114 if (test_items[which].type == INT) {
13115 *((int *) test_items[which].location) = test_items[which].u.intval;
13116 } else if (test_items[which].type == FLAGVAL) {
13117 if (ast_test_flag(vmu, test_items[which].u.intval)) {
13118 ast_clear_flag(vmu, test_items[which].u.intval);
13119 } else {
13120 ast_set_flag(vmu, test_items[which].u.intval);
13121 }
13122 } else if (test_items[which].type == STATIC) {
13123 strcpy(test_items[which].location, test_items[which].u.strval);
13124 } else if (test_items[which].type == STRPTR) {
13125 test_items[which].location = test_items[which].u.strval;
13126 }
13127
13128 make_email_file(file, from, vmu, 0, testcontext, testmailbox, "INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan, NULL, 0, NULL);
13129 rewind(file);
13130 while (fgets(buf, sizeof(buf), file)) {
13131 if (
13132 #ifdef IMAP_STORAGE
13133 buf[strlen(buf) - 2] != '\r'
13134 #else
13135 buf[strlen(buf) - 2] == '\r'
13136 #endif
13137 || buf[strlen(buf) - 1] != '\n') {
13138 res = AST_TEST_FAIL;
13139 }
13140 }
13141 }
13142 fclose(file);
13143 return res;
13144 }
13145
13146 AST_TEST_DEFINE(test_voicemail_load_config)
13147 {
13148 int res = AST_TEST_PASS;
13149 struct ast_vm_user *vmu;
13150 struct ast_config *cfg;
13151 char config_filename[32] = "/tmp/voicemail.conf.XXXXXX";
13152 int fd;
13153 FILE *file;
13154 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
13155
13156 switch (cmd) {
13157 case TEST_INIT:
13158 info->name = "test_voicemail_load_config";
13159 info->category = "/apps/app_voicemail/";
13160 info->summary = "Test loading Voicemail config";
13161 info->description =
13162 "Verify that configuration is loaded consistently. "
13163 "This is to test regressions of ASTERISK-18838 where it was noticed that "
13164 "some options were loaded after the mailboxes were instantiated, causing "
13165 "those options not to be set correctly.";
13166 return AST_TEST_NOT_RUN;
13167 case TEST_EXECUTE:
13168 break;
13169 }
13170
13171
13172 if ((fd = mkstemp(config_filename)) < 0) {
13173 return AST_TEST_FAIL;
13174 }
13175 if (!(file = fdopen(fd, "w"))) {
13176 close(fd);
13177 unlink(config_filename);
13178 return AST_TEST_FAIL;
13179 }
13180 fputs("[general]\ncallback=somecontext\nlocale=de_DE.UTF-8\ntz=european\n[test]", file);
13181 fputs("00000001 => 9999,Mr. Test,,,callback=othercontext|locale=nl_NL.UTF-8|tz=central\n", file);
13182 fputs("00000002 => 9999,Mrs. Test\n", file);
13183 fclose(file);
13184
13185 if (!(cfg = ast_config_load(config_filename, config_flags))) {
13186 res = AST_TEST_FAIL;
13187 goto cleanup;
13188 }
13189
13190 load_config_from_memory(1, cfg, NULL);
13191 ast_config_destroy(cfg);
13192
13193 #define CHECK(u, attr, value) else if (strcmp(u->attr, value)) { \
13194 ast_test_status_update(test, "mailbox %s should have %s '%s', but has '%s'\n", \
13195 u->mailbox, #attr, value, u->attr); res = AST_TEST_FAIL; break; }
13196
13197 AST_LIST_LOCK(&users);
13198 AST_LIST_TRAVERSE(&users, vmu, list) {
13199 if (!strcmp(vmu->mailbox, "00000001")) {
13200 if (0);
13201 CHECK(vmu, callback, "othercontext")
13202 CHECK(vmu, locale, "nl_NL.UTF-8")
13203 CHECK(vmu, zonetag, "central")
13204 } else if (!strcmp(vmu->mailbox, "00000002")) {
13205 if (0);
13206 CHECK(vmu, callback, "somecontext")
13207 CHECK(vmu, locale, "de_DE.UTF-8")
13208 CHECK(vmu, zonetag, "european")
13209 }
13210 }
13211 AST_LIST_UNLOCK(&users);
13212
13213 #undef CHECK
13214
13215
13216 load_config(1);
13217
13218 cleanup:
13219 unlink(config_filename);
13220 return res;
13221 }
13222
13223 AST_TEST_DEFINE(test_voicemail_vm_info)
13224 {
13225 struct ast_vm_user *vmu;
13226 struct ast_channel *chan = NULL;
13227 const char testcontext[] = "test";
13228 const char testmailbox[] = "00000000";
13229 const char vminfo_cmd[] = "VM_INFO";
13230 char vminfo_buf[256], vminfo_args[256];
13231 int res = AST_TEST_PASS;
13232 int test_ret = 0;
13233 int test_counter = 0;
13234
13235 struct {
13236 char *vminfo_test_args;
13237 char *vminfo_expected;
13238 int vminfo_ret;
13239 } test_items[] = {
13240 { "", "", -1 },
13241 { "00000000@test,badparam", "", -1 },
13242 { "00000000@test", "", -1 },
13243 { "00000000@test,exists", "1", 0 },
13244 { "11111111@test,exists", "0", 0 },
13245 { "00000000@test,email", "vm-info-test@example.net", 0 },
13246 { "11111111@test,email", "", 0 },
13247 { "00000000@test,fullname", "Test Framework Mailbox", 0 },
13248 { "00000000@test,pager", "vm-info-pager-test@example.net", 0 },
13249 { "00000000@test,locale", "en_US", 0 },
13250 { "00000000@test,tz", "central", 0 },
13251 { "00000000@test,language", "en", 0 },
13252 { "00000000@test,password", "9876", 0 },
13253 };
13254
13255 switch (cmd) {
13256 case TEST_INIT:
13257 info->name = "test_voicemail_vm_info";
13258 info->category = "/apps/app_voicemail/";
13259 info->summary = "VM_INFO unit test";
13260 info->description =
13261 "This tests passing various parameters to VM_INFO";
13262 return AST_TEST_NOT_RUN;
13263 case TEST_EXECUTE:
13264 break;
13265 }
13266
13267 if (!(chan = ast_dummy_channel_alloc())) {
13268 ast_test_status_update(test, "Unable to create dummy channel\n");
13269 return AST_TEST_FAIL;
13270 }
13271
13272 if (!(vmu = find_user(NULL, testcontext, testmailbox)) &&
13273 !(vmu = find_or_create(testcontext, testmailbox))) {
13274 ast_test_status_update(test, "Cannot create vmu structure\n");
13275 chan = ast_channel_unref(chan);
13276 return AST_TEST_FAIL;
13277 }
13278
13279 populate_defaults(vmu);
13280
13281 ast_copy_string(vmu->email, "vm-info-test@example.net", sizeof(vmu->email));
13282 ast_copy_string(vmu->fullname, "Test Framework Mailbox", sizeof(vmu->fullname));
13283 ast_copy_string(vmu->pager, "vm-info-pager-test@example.net", sizeof(vmu->pager));
13284 ast_copy_string(vmu->language, "en", sizeof(vmu->language));
13285 ast_copy_string(vmu->zonetag, "central", sizeof(vmu->zonetag));
13286 ast_copy_string(vmu->locale, "en_US", sizeof(vmu->zonetag));
13287 ast_copy_string(vmu->password, "9876", sizeof(vmu->password));
13288
13289 for (test_counter = 0; test_counter < ARRAY_LEN(test_items); test_counter++) {
13290 ast_copy_string(vminfo_args, test_items[test_counter].vminfo_test_args, sizeof(vminfo_args));
13291 test_ret = acf_vm_info(chan, vminfo_cmd, vminfo_args, vminfo_buf, sizeof(vminfo_buf));
13292 if (strcmp(vminfo_buf, test_items[test_counter].vminfo_expected)) {
13293 ast_test_status_update(test, "VM_INFO respose was: '%s', but expected: '%s'\n", vminfo_buf, test_items[test_counter].vminfo_expected);
13294 res = AST_TEST_FAIL;
13295 }
13296 if (!(test_ret == test_items[test_counter].vminfo_ret)) {
13297 ast_test_status_update(test, "VM_INFO return code was: '%i', but expected '%i'\n", test_ret, test_items[test_counter].vminfo_ret);
13298 res = AST_TEST_FAIL;
13299 }
13300 }
13301
13302 chan = ast_channel_unref(chan);
13303 return res;
13304 }
13305 #endif
13306
13307 static int reload(void)
13308 {
13309 return load_config(1);
13310 }
13311
13312 static int unload_module(void)
13313 {
13314 int res;
13315
13316 res = ast_unregister_application(app);
13317 res |= ast_unregister_application(app2);
13318 res |= ast_unregister_application(app3);
13319 res |= ast_unregister_application(app4);
13320 res |= ast_unregister_application(sayname_app);
13321 res |= ast_custom_function_unregister(&mailbox_exists_acf);
13322 res |= ast_custom_function_unregister(&vm_info_acf);
13323 res |= ast_manager_unregister("VoicemailUsersList");
13324 res |= ast_data_unregister(NULL);
13325 #ifdef TEST_FRAMEWORK
13326 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
13327 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
13328 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
13329 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
13330 res |= AST_TEST_UNREGISTER(test_voicemail_load_config);
13331 res |= AST_TEST_UNREGISTER(test_voicemail_vm_info);
13332 #endif
13333 ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13334 ast_uninstall_vm_functions();
13335 ao2_ref(inprocess_container, -1);
13336
13337 if (poll_thread != AST_PTHREADT_NULL)
13338 stop_poll_thread();
13339
13340 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
13341 ast_unload_realtime("voicemail");
13342 ast_unload_realtime("voicemail_data");
13343
13344 free_vm_users();
13345 free_vm_zones();
13346 return res;
13347 }
13348
13349 static int load_module(void)
13350 {
13351 int res;
13352 my_umask = umask(0);
13353 umask(my_umask);
13354
13355 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
13356 return AST_MODULE_LOAD_DECLINE;
13357 }
13358
13359
13360 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
13361
13362 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
13363 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
13364 }
13365
13366 if ((res = load_config(0)))
13367 return res;
13368
13369 res = ast_register_application_xml(app, vm_exec);
13370 res |= ast_register_application_xml(app2, vm_execmain);
13371 res |= ast_register_application_xml(app3, vm_box_exists);
13372 res |= ast_register_application_xml(app4, vmauthenticate);
13373 res |= ast_register_application_xml(sayname_app, vmsayname_exec);
13374 res |= ast_custom_function_register(&mailbox_exists_acf);
13375 res |= ast_custom_function_register(&vm_info_acf);
13376 res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
13377 #ifdef TEST_FRAMEWORK
13378 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
13379 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
13380 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
13381 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
13382 res |= AST_TEST_REGISTER(test_voicemail_load_config);
13383 res |= AST_TEST_REGISTER(test_voicemail_vm_info);
13384 #endif
13385
13386 if (res)
13387 return res;
13388
13389 ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13390 ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));
13391
13392 ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
13393 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
13394 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
13395
13396 return res;
13397 }
13398
13399 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
13400 {
13401 int cmd = 0;
13402 char destination[80] = "";
13403 int retries = 0;
13404
13405 if (!num) {
13406 ast_verb(3, "Destination number will be entered manually\n");
13407 while (retries < 3 && cmd != 't') {
13408 destination[1] = '\0';
13409 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
13410 if (!cmd)
13411 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
13412 if (!cmd)
13413 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
13414 if (!cmd) {
13415 cmd = ast_waitfordigit(chan, 6000);
13416 if (cmd)
13417 destination[0] = cmd;
13418 }
13419 if (!cmd) {
13420 retries++;
13421 } else {
13422
13423 if (cmd < 0)
13424 return 0;
13425 if (cmd == '*') {
13426 ast_verb(3, "User hit '*' to cancel outgoing call\n");
13427 return 0;
13428 }
13429 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0)
13430 retries++;
13431 else
13432 cmd = 't';
13433 }
13434 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
13435 }
13436 if (retries >= 3) {
13437 return 0;
13438 }
13439
13440 } else {
13441 ast_verb(3, "Destination number is CID number '%s'\n", num);
13442 ast_copy_string(destination, num, sizeof(destination));
13443 }
13444
13445 if (!ast_strlen_zero(destination)) {
13446 if (destination[strlen(destination) -1 ] == '*')
13447 return 0;
13448 ast_verb(3, "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
13449 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
13450 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
13451 chan->priority = 0;
13452 return 9;
13453 }
13454 return 0;
13455 }
13456
13457
13458
13459
13460
13461
13462
13463
13464
13465
13466
13467
13468
13469
13470 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)
13471 {
13472 int res = 0;
13473 char filename[PATH_MAX];
13474 struct ast_config *msg_cfg = NULL;
13475 const char *origtime, *context;
13476 char *name, *num;
13477 int retries = 0;
13478 char *cid;
13479 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
13480
13481 vms->starting = 0;
13482
13483 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13484
13485
13486 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
13487 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
13488 msg_cfg = ast_config_load(filename, config_flags);
13489 DISPOSE(vms->curdir, vms->curmsg);
13490 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
13491 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
13492 return 0;
13493 }
13494
13495 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
13496 ast_config_destroy(msg_cfg);
13497 return 0;
13498 }
13499
13500 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
13501
13502 context = ast_variable_retrieve(msg_cfg, "message", "context");
13503 if (!strncasecmp("macro", context, 5))
13504 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
13505 switch (option) {
13506 case 3:
13507 if (!res) {
13508 res = play_message_datetime(chan, vmu, origtime, filename);
13509 }
13510 if (!res) {
13511 res = play_message_callerid(chan, vms, cid, context, 0, 1);
13512 }
13513
13514 res = 't';
13515 break;
13516
13517 case 2:
13518
13519 if (ast_strlen_zero(cid))
13520 break;
13521
13522 ast_callerid_parse(cid, &name, &num);
13523 while ((res > -1) && (res != 't')) {
13524 switch (res) {
13525 case '1':
13526 if (num) {
13527
13528 res = dialout(chan, vmu, num, vmu->callback);
13529 if (res) {
13530 ast_config_destroy(msg_cfg);
13531 return 9;
13532 }
13533 } else {
13534 res = '2';
13535 }
13536 break;
13537
13538 case '2':
13539
13540 if (!ast_strlen_zero(vmu->dialout)) {
13541 res = dialout(chan, vmu, NULL, vmu->dialout);
13542 if (res) {
13543 ast_config_destroy(msg_cfg);
13544 return 9;
13545 }
13546 } else {
13547 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
13548 res = ast_play_and_wait(chan, "vm-sorry");
13549 }
13550 ast_config_destroy(msg_cfg);
13551 return res;
13552 case '*':
13553 res = 't';
13554 break;
13555 case '3':
13556 case '4':
13557 case '5':
13558 case '6':
13559 case '7':
13560 case '8':
13561 case '9':
13562 case '0':
13563
13564 res = ast_play_and_wait(chan, "vm-sorry");
13565 retries++;
13566 break;
13567 default:
13568 if (num) {
13569 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
13570 res = ast_play_and_wait(chan, "vm-num-i-have");
13571 if (!res)
13572 res = play_message_callerid(chan, vms, num, vmu->context, 1, 1);
13573 if (!res)
13574 res = ast_play_and_wait(chan, "vm-tocallnum");
13575
13576 if (!ast_strlen_zero(vmu->dialout)) {
13577 if (!res)
13578 res = ast_play_and_wait(chan, "vm-calldiffnum");
13579 }
13580 } else {
13581 res = ast_play_and_wait(chan, "vm-nonumber");
13582 if (!ast_strlen_zero(vmu->dialout)) {
13583 if (!res)
13584 res = ast_play_and_wait(chan, "vm-toenternumber");
13585 }
13586 }
13587 if (!res) {
13588 res = ast_play_and_wait(chan, "vm-star-cancel");
13589 }
13590 if (!res) {
13591 res = ast_waitfordigit(chan, 6000);
13592 }
13593 if (!res) {
13594 retries++;
13595 if (retries > 3) {
13596 res = 't';
13597 }
13598 }
13599 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
13600 break;
13601
13602 }
13603 if (res == 't')
13604 res = 0;
13605 else if (res == '*')
13606 res = -1;
13607 }
13608 break;
13609
13610 case 1:
13611
13612 if (ast_strlen_zero(cid))
13613 break;
13614
13615 ast_callerid_parse(cid, &name, &num);
13616 if (!num) {
13617 ast_verb(3, "No CID number available, no reply sent\n");
13618 if (!res)
13619 res = ast_play_and_wait(chan, "vm-nonumber");
13620 ast_config_destroy(msg_cfg);
13621 return res;
13622 } else {
13623 struct ast_vm_user vmu2;
13624 if (find_user(&vmu2, vmu->context, num)) {
13625 struct leave_vm_options leave_options;
13626 char mailbox[AST_MAX_EXTENSION * 2 + 2];
13627 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
13628
13629 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
13630
13631 memset(&leave_options, 0, sizeof(leave_options));
13632 leave_options.record_gain = record_gain;
13633 res = leave_voicemail(chan, mailbox, &leave_options);
13634 if (!res)
13635 res = 't';
13636 ast_config_destroy(msg_cfg);
13637 return res;
13638 } else {
13639
13640 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
13641 ast_play_and_wait(chan, "vm-nobox");
13642 res = 't';
13643 ast_config_destroy(msg_cfg);
13644 return res;
13645 }
13646 }
13647 res = 0;
13648
13649 break;
13650 }
13651
13652 #ifndef IMAP_STORAGE
13653 ast_config_destroy(msg_cfg);
13654
13655 if (!res) {
13656 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13657 vms->heard[msg] = 1;
13658 res = wait_file(chan, vms, vms->fn);
13659 }
13660 #endif
13661 return res;
13662 }
13663
13664 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
13665 int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
13666 signed char record_gain, struct vm_state *vms, char *flag)
13667 {
13668
13669 int res = 0;
13670 int cmd = 0;
13671 int max_attempts = 3;
13672 int attempts = 0;
13673 int recorded = 0;
13674 int msg_exists = 0;
13675 signed char zero_gain = 0;
13676 char tempfile[PATH_MAX];
13677 char *acceptdtmf = "#";
13678 char *canceldtmf = "";
13679 int canceleddtmf = 0;
13680
13681
13682
13683
13684 if (duration == NULL) {
13685 ast_log(AST_LOG_WARNING, "Error play_record_review called without duration pointer\n");
13686 return -1;
13687 }
13688
13689 if (!outsidecaller)
13690 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
13691 else
13692 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
13693
13694 cmd = '3';
13695
13696 while ((cmd >= 0) && (cmd != 't')) {
13697 switch (cmd) {
13698 case '1':
13699 if (!msg_exists) {
13700
13701 cmd = '3';
13702 break;
13703 } else {
13704
13705 ast_verb(3, "Saving message as is\n");
13706 if (!outsidecaller)
13707 ast_filerename(tempfile, recordfile, NULL);
13708 ast_stream_and_wait(chan, "vm-msgsaved", "");
13709 if (!outsidecaller) {
13710
13711 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag);
13712 DISPOSE(recordfile, -1);
13713 }
13714 cmd = 't';
13715 return res;
13716 }
13717 case '2':
13718
13719 ast_verb(3, "Reviewing the message\n");
13720 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
13721 break;
13722 case '3':
13723 msg_exists = 0;
13724
13725 if (recorded == 1)
13726 ast_verb(3, "Re-recording the message\n");
13727 else
13728 ast_verb(3, "Recording the message\n");
13729
13730 if (recorded && outsidecaller) {
13731 cmd = ast_play_and_wait(chan, INTRO);
13732 cmd = ast_play_and_wait(chan, "beep");
13733 }
13734 recorded = 1;
13735
13736 if (record_gain)
13737 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
13738 if (ast_test_flag(vmu, VM_OPERATOR))
13739 canceldtmf = "0";
13740 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
13741 if (strchr(canceldtmf, cmd)) {
13742
13743 canceleddtmf = 1;
13744 }
13745 if (record_gain)
13746 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
13747 if (cmd == -1) {
13748
13749 if (!outsidecaller) {
13750
13751 ast_filedelete(tempfile, NULL);
13752 }
13753 return cmd;
13754 }
13755 if (cmd == '0') {
13756 break;
13757 } else if (cmd == '*') {
13758 break;
13759 #if 0
13760 } else if (vmu->review && sound_duration && (*sound_duration < 5)) {
13761
13762 ast_verb(3, "Message too short\n");
13763 cmd = ast_play_and_wait(chan, "vm-tooshort");
13764 cmd = ast_filedelete(tempfile, NULL);
13765 break;
13766 } else if (vmu->review && (cmd == 2 && sound_duration && *sound_duration < (maxsilence + 3))) {
13767
13768 ast_verb(3, "Nothing recorded\n");
13769 cmd = ast_filedelete(tempfile, NULL);
13770 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
13771 if (!cmd)
13772 cmd = ast_play_and_wait(chan, "vm-speakup");
13773 break;
13774 #endif
13775 } else {
13776
13777 msg_exists = 1;
13778 cmd = 0;
13779 }
13780 break;
13781 case '4':
13782 if (outsidecaller) {
13783
13784 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13785 ast_verb(3, "marking message as Urgent\n");
13786 res = ast_play_and_wait(chan, "vm-marked-urgent");
13787 strcpy(flag, "Urgent");
13788 } else if (flag) {
13789 ast_verb(3, "UNmarking message as Urgent\n");
13790 res = ast_play_and_wait(chan, "vm-urgent-removed");
13791 strcpy(flag, "");
13792 } else {
13793 ast_play_and_wait(chan, "vm-sorry");
13794 }
13795 cmd = 0;
13796 } else {
13797 cmd = ast_play_and_wait(chan, "vm-sorry");
13798 }
13799 break;
13800 case '5':
13801 case '6':
13802 case '7':
13803 case '8':
13804 case '9':
13805 case '*':
13806 case '#':
13807 cmd = ast_play_and_wait(chan, "vm-sorry");
13808 break;
13809 #if 0
13810
13811
13812 case '*':
13813
13814 cmd = ast_play_and_wait(chan, "vm-deleted");
13815 cmd = ast_filedelete(tempfile, NULL);
13816 if (outsidecaller) {
13817 res = vm_exec(chan, NULL);
13818 return res;
13819 }
13820 else
13821 return 1;
13822 #endif
13823 case '0':
13824 if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
13825 cmd = ast_play_and_wait(chan, "vm-sorry");
13826 break;
13827 }
13828 if (msg_exists || recorded) {
13829 cmd = ast_play_and_wait(chan, "vm-saveoper");
13830 if (!cmd)
13831 cmd = ast_waitfordigit(chan, 3000);
13832 if (cmd == '1') {
13833 ast_filerename(tempfile, recordfile, NULL);
13834 ast_play_and_wait(chan, "vm-msgsaved");
13835 cmd = '0';
13836 } else if (cmd == '4') {
13837 if (flag) {
13838 ast_play_and_wait(chan, "vm-marked-urgent");
13839 strcpy(flag, "Urgent");
13840 }
13841 ast_play_and_wait(chan, "vm-msgsaved");
13842 cmd = '0';
13843 } else {
13844 ast_play_and_wait(chan, "vm-deleted");
13845 DELETE(tempfile, -1, tempfile, vmu);
13846 cmd = '0';
13847 }
13848 }
13849 return cmd;
13850 default:
13851
13852
13853
13854 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
13855 return cmd;
13856 if (msg_exists) {
13857 cmd = ast_play_and_wait(chan, "vm-review");
13858 if (!cmd && outsidecaller) {
13859 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13860 cmd = ast_play_and_wait(chan, "vm-review-urgent");
13861 } else if (flag) {
13862 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
13863 }
13864 }
13865 } else {
13866 cmd = ast_play_and_wait(chan, "vm-torerecord");
13867 if (!cmd)
13868 cmd = ast_waitfordigit(chan, 600);
13869 }
13870
13871 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
13872 cmd = ast_play_and_wait(chan, "vm-reachoper");
13873 if (!cmd)
13874 cmd = ast_waitfordigit(chan, 600);
13875 }
13876 #if 0
13877 if (!cmd)
13878 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
13879 #endif
13880 if (!cmd)
13881 cmd = ast_waitfordigit(chan, 6000);
13882 if (!cmd) {
13883 attempts++;
13884 }
13885 if (attempts > max_attempts) {
13886 cmd = 't';
13887 }
13888 }
13889 }
13890 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
13891
13892 ast_filedelete(tempfile, NULL);
13893 }
13894
13895 if (cmd != 't' && outsidecaller)
13896 ast_play_and_wait(chan, "vm-goodbye");
13897
13898 return cmd;
13899 }
13900
13901
13902
13903
13904
13905 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
13906 .load = load_module,
13907 .unload = unload_module,
13908 .reload = reload,
13909 .nonoptreq = "res_adsi,res_smdi",
13910 );