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 #include "asterisk.h"
00070
00071 #ifdef IMAP_STORAGE
00072 #include <ctype.h>
00073 #include <signal.h>
00074 #include <pwd.h>
00075 #ifdef USE_SYSTEM_IMAP
00076 #include <imap/c-client.h>
00077 #include <imap/imap4r1.h>
00078 #include <imap/linkage.h>
00079 #elif defined (USE_SYSTEM_CCLIENT)
00080 #include <c-client/c-client.h>
00081 #include <c-client/imap4r1.h>
00082 #include <c-client/linkage.h>
00083 #else
00084 #include "c-client.h"
00085 #include "imap4r1.h"
00086 #include "linkage.h"
00087 #endif
00088 #endif
00089
00090 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 301047 $")
00091
00092 #include "asterisk/paths.h"
00093 #include <sys/time.h>
00094 #include <sys/stat.h>
00095 #include <sys/mman.h>
00096 #include <time.h>
00097 #include <dirent.h>
00098 #if defined(__FreeBSD__) || defined(__OpenBSD__)
00099 #include <sys/wait.h>
00100 #endif
00101
00102 #include "asterisk/logger.h"
00103 #include "asterisk/lock.h"
00104 #include "asterisk/file.h"
00105 #include "asterisk/channel.h"
00106 #include "asterisk/pbx.h"
00107 #include "asterisk/config.h"
00108 #include "asterisk/say.h"
00109 #include "asterisk/module.h"
00110 #include "asterisk/adsi.h"
00111 #include "asterisk/app.h"
00112 #include "asterisk/manager.h"
00113 #include "asterisk/dsp.h"
00114 #include "asterisk/localtime.h"
00115 #include "asterisk/cli.h"
00116 #include "asterisk/utils.h"
00117 #include "asterisk/stringfields.h"
00118 #include "asterisk/smdi.h"
00119 #include "asterisk/astobj2.h"
00120 #include "asterisk/event.h"
00121 #include "asterisk/taskprocessor.h"
00122 #include "asterisk/test.h"
00123
00124 #ifdef ODBC_STORAGE
00125 #include "asterisk/res_odbc.h"
00126 #endif
00127
00128 #ifdef IMAP_STORAGE
00129 #include "asterisk/threadstorage.h"
00130 #endif
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364 #ifdef IMAP_STORAGE
00365 static char imapserver[48];
00366 static char imapport[8];
00367 static char imapflags[128];
00368 static char imapfolder[64];
00369 static char imapparentfolder[64] = "\0";
00370 static char greetingfolder[64];
00371 static char authuser[32];
00372 static char authpassword[42];
00373 static int imapversion = 1;
00374
00375 static int expungeonhangup = 1;
00376 static int imapgreetings = 0;
00377 static char delimiter = '\0';
00378
00379 struct vm_state;
00380 struct ast_vm_user;
00381
00382 AST_THREADSTORAGE(ts_vmstate);
00383
00384
00385 static int init_mailstream(struct vm_state *vms, int box);
00386 static void write_file(char *filename, char *buffer, unsigned long len);
00387 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len);
00388 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu);
00389 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len);
00390 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive);
00391 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive);
00392 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu);
00393 static void vmstate_insert(struct vm_state *vms);
00394 static void vmstate_delete(struct vm_state *vms);
00395 static void set_update(MAILSTREAM * stream);
00396 static void init_vm_state(struct vm_state *vms);
00397 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro);
00398 static void get_mailbox_delimiter(MAILSTREAM *stream);
00399 static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
00400 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
00401 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);
00402 static void update_messages_by_imapuser(const char *user, unsigned long number);
00403 static int vm_delete(char *file);
00404
00405 static int imap_remove_file (char *dir, int msgnum);
00406 static int imap_retrieve_file (const char *dir, const int msgnum, const char *mailbox, const char *context);
00407 static int imap_delete_old_greeting (char *dir, struct vm_state *vms);
00408 static void check_quota(struct vm_state *vms, char *mailbox);
00409 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00410 struct vmstate {
00411 struct vm_state *vms;
00412 AST_LIST_ENTRY(vmstate) list;
00413 };
00414
00415 static AST_LIST_HEAD_STATIC(vmstates, vmstate);
00416
00417 #endif
00418
00419 #define SMDI_MWI_WAIT_TIMEOUT 1000
00420
00421 #define COMMAND_TIMEOUT 5000
00422
00423 #define VOICEMAIL_DIR_MODE 0777
00424 #define VOICEMAIL_FILE_MODE 0666
00425 #define CHUNKSIZE 65536
00426
00427 #define VOICEMAIL_CONFIG "voicemail.conf"
00428 #define ASTERISK_USERNAME "asterisk"
00429
00430
00431
00432
00433 #define DEFAULT_LISTEN_CONTROL_FORWARD_KEY "#"
00434 #define DEFAULT_LISTEN_CONTROL_REVERSE_KEY "*"
00435 #define DEFAULT_LISTEN_CONTROL_PAUSE_KEY "0"
00436 #define DEFAULT_LISTEN_CONTROL_RESTART_KEY "2"
00437 #define DEFAULT_LISTEN_CONTROL_STOP_KEY "13456789"
00438 #define VALID_DTMF "1234567890*#"
00439
00440
00441
00442 #define SENDMAIL "/usr/sbin/sendmail -t"
00443
00444 #define INTRO "vm-intro"
00445
00446 #define MAXMSG 100
00447 #define MAXMSGLIMIT 9999
00448
00449 #define MINPASSWORD 0
00450
00451 #define BASELINELEN 72
00452 #define BASEMAXINLINE 256
00453 #ifdef IMAP_STORAGE
00454 #define ENDL "\r\n"
00455 #else
00456 #define ENDL "\n"
00457 #endif
00458
00459 #define MAX_DATETIME_FORMAT 512
00460 #define MAX_NUM_CID_CONTEXTS 10
00461
00462 #define VM_REVIEW (1 << 0)
00463 #define VM_OPERATOR (1 << 1)
00464 #define VM_SAYCID (1 << 2)
00465 #define VM_SVMAIL (1 << 3)
00466 #define VM_ENVELOPE (1 << 4)
00467 #define VM_SAYDURATION (1 << 5)
00468 #define VM_SKIPAFTERCMD (1 << 6)
00469 #define VM_FORCENAME (1 << 7)
00470 #define VM_FORCEGREET (1 << 8)
00471 #define VM_PBXSKIP (1 << 9)
00472 #define VM_DIRECFORWARD (1 << 10)
00473 #define VM_ATTACH (1 << 11)
00474 #define VM_DELETE (1 << 12)
00475 #define VM_ALLOCED (1 << 13)
00476 #define VM_SEARCH (1 << 14)
00477 #define VM_TEMPGREETWARN (1 << 15)
00478 #define VM_MOVEHEARD (1 << 16)
00479 #define VM_MESSAGEWRAP (1 << 17)
00480 #define VM_FWDURGAUTO (1 << 18)
00481 #define ERROR_LOCK_PATH -100
00482 #define OPERATOR_EXIT 300
00483
00484
00485 enum vm_box {
00486 NEW_FOLDER,
00487 OLD_FOLDER,
00488 WORK_FOLDER,
00489 FAMILY_FOLDER,
00490 FRIENDS_FOLDER,
00491 GREETINGS_FOLDER
00492 };
00493
00494 enum vm_option_flags {
00495 OPT_SILENT = (1 << 0),
00496 OPT_BUSY_GREETING = (1 << 1),
00497 OPT_UNAVAIL_GREETING = (1 << 2),
00498 OPT_RECORDGAIN = (1 << 3),
00499 OPT_PREPEND_MAILBOX = (1 << 4),
00500 OPT_AUTOPLAY = (1 << 6),
00501 OPT_DTMFEXIT = (1 << 7),
00502 OPT_MESSAGE_Urgent = (1 << 8),
00503 OPT_MESSAGE_PRIORITY = (1 << 9)
00504 };
00505
00506 enum vm_option_args {
00507 OPT_ARG_RECORDGAIN = 0,
00508 OPT_ARG_PLAYFOLDER = 1,
00509 OPT_ARG_DTMFEXIT = 2,
00510
00511 OPT_ARG_ARRAY_SIZE = 3,
00512 };
00513
00514 enum vm_passwordlocation {
00515 OPT_PWLOC_VOICEMAILCONF = 0,
00516 OPT_PWLOC_SPOOLDIR = 1,
00517 OPT_PWLOC_USERSCONF = 2,
00518 };
00519
00520 AST_APP_OPTIONS(vm_app_options, {
00521 AST_APP_OPTION('s', OPT_SILENT),
00522 AST_APP_OPTION('b', OPT_BUSY_GREETING),
00523 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
00524 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
00525 AST_APP_OPTION_ARG('d', OPT_DTMFEXIT, OPT_ARG_DTMFEXIT),
00526 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
00527 AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
00528 AST_APP_OPTION('U', OPT_MESSAGE_Urgent),
00529 AST_APP_OPTION('P', OPT_MESSAGE_PRIORITY)
00530 });
00531
00532 static int load_config(int reload);
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617 struct baseio {
00618 int iocp;
00619 int iolen;
00620 int linelength;
00621 int ateof;
00622 unsigned char iobuf[BASEMAXINLINE];
00623 };
00624
00625
00626
00627 struct ast_vm_user {
00628 char context[AST_MAX_CONTEXT];
00629 char mailbox[AST_MAX_EXTENSION];
00630 char password[80];
00631 char fullname[80];
00632 char email[80];
00633 char *emailsubject;
00634 char *emailbody;
00635 char pager[80];
00636 char serveremail[80];
00637 char mailcmd[160];
00638 char language[MAX_LANGUAGE];
00639 char zonetag[80];
00640 char locale[20];
00641 char callback[80];
00642 char dialout[80];
00643 char uniqueid[80];
00644 char exit[80];
00645 char attachfmt[20];
00646 unsigned int flags;
00647 int saydurationm;
00648 int minsecs;
00649 int maxmsg;
00650 int maxdeletedmsg;
00651 int maxsecs;
00652 int passwordlocation;
00653 #ifdef IMAP_STORAGE
00654 char imapuser[80];
00655 char imappassword[80];
00656 char imapfolder[64];
00657 char imapvmshareid[80];
00658 int imapversion;
00659 #endif
00660 double volgain;
00661 AST_LIST_ENTRY(ast_vm_user) list;
00662 };
00663
00664
00665 struct vm_zone {
00666 AST_LIST_ENTRY(vm_zone) list;
00667 char name[80];
00668 char timezone[80];
00669 char msg_format[512];
00670 };
00671
00672 #define VMSTATE_MAX_MSG_ARRAY 256
00673
00674
00675 struct vm_state {
00676 char curbox[80];
00677 char username[80];
00678 char context[80];
00679 char curdir[PATH_MAX];
00680 char vmbox[PATH_MAX];
00681 char fn[PATH_MAX];
00682 char intro[PATH_MAX];
00683 int *deleted;
00684 int *heard;
00685 int dh_arraysize;
00686 int curmsg;
00687 int lastmsg;
00688 int newmessages;
00689 int oldmessages;
00690 int urgentmessages;
00691 int starting;
00692 int repeats;
00693 #ifdef IMAP_STORAGE
00694 ast_mutex_t lock;
00695 int updated;
00696 long msgArray[VMSTATE_MAX_MSG_ARRAY];
00697 MAILSTREAM *mailstream;
00698 int vmArrayIndex;
00699 char imapuser[80];
00700 char imapfolder[64];
00701 int imapversion;
00702 int interactive;
00703 char introfn[PATH_MAX];
00704 unsigned int quota_limit;
00705 unsigned int quota_usage;
00706 struct vm_state *persist_vms;
00707 #endif
00708 };
00709
00710 #ifdef ODBC_STORAGE
00711 static char odbc_database[80];
00712 static char odbc_table[80];
00713 #define RETRIEVE(a,b,c,d) retrieve_file(a,b)
00714 #define DISPOSE(a,b) remove_file(a,b)
00715 #define STORE(a,b,c,d,e,f,g,h,i,j) store_file(a,b,c,d)
00716 #define EXISTS(a,b,c,d) (message_exists(a,b))
00717 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
00718 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
00719 #define DELETE(a,b,c,d) (delete_file(a,b))
00720 #else
00721 #ifdef IMAP_STORAGE
00722 #define DISPOSE(a,b) (imap_remove_file(a,b))
00723 #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))
00724 #define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
00725 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00726 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00727 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
00728 #define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
00729 #else
00730 #define RETRIEVE(a,b,c,d)
00731 #define DISPOSE(a,b)
00732 #define STORE(a,b,c,d,e,f,g,h,i,j)
00733 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00734 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00735 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
00736 #define DELETE(a,b,c,d) (vm_delete(c))
00737 #endif
00738 #endif
00739
00740 static char VM_SPOOL_DIR[PATH_MAX];
00741
00742 static char ext_pass_cmd[128];
00743 static char ext_pass_check_cmd[128];
00744
00745 static int my_umask;
00746
00747 #define PWDCHANGE_INTERNAL (1 << 1)
00748 #define PWDCHANGE_EXTERNAL (1 << 2)
00749 static int pwdchange = PWDCHANGE_INTERNAL;
00750
00751 #ifdef ODBC_STORAGE
00752 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
00753 #else
00754 # ifdef IMAP_STORAGE
00755 # define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
00756 # else
00757 # define tdesc "Comedian Mail (Voicemail System)"
00758 # endif
00759 #endif
00760
00761 static char userscontext[AST_MAX_EXTENSION] = "default";
00762
00763 static char *addesc = "Comedian Mail";
00764
00765
00766 static char *app = "VoiceMail";
00767
00768
00769 static char *app2 = "VoiceMailMain";
00770
00771 static char *app3 = "MailboxExists";
00772 static char *app4 = "VMAuthenticate";
00773
00774 static char *sayname_app = "VMSayName";
00775
00776 static AST_LIST_HEAD_STATIC(users, ast_vm_user);
00777 static AST_LIST_HEAD_STATIC(zones, vm_zone);
00778 static char zonetag[80];
00779 static char locale[20];
00780 static int maxsilence;
00781 static int maxmsg;
00782 static int maxdeletedmsg;
00783 static int silencethreshold = 128;
00784 static char serveremail[80];
00785 static char mailcmd[160];
00786 static char externnotify[160];
00787 static struct ast_smdi_interface *smdi_iface = NULL;
00788 static char vmfmts[80];
00789 static double volgain;
00790 static int vmminsecs;
00791 static int vmmaxsecs;
00792 static int maxgreet;
00793 static int skipms;
00794 static int maxlogins;
00795 static int minpassword;
00796 static int passwordlocation;
00797
00798
00799
00800 static unsigned int poll_mailboxes;
00801
00802
00803 static unsigned int poll_freq;
00804
00805 #define DEFAULT_POLL_FREQ 30
00806
00807 AST_MUTEX_DEFINE_STATIC(poll_lock);
00808 static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
00809 static pthread_t poll_thread = AST_PTHREADT_NULL;
00810 static unsigned char poll_thread_run;
00811
00812
00813 static struct ast_event_sub *mwi_sub_sub;
00814
00815 static struct ast_event_sub *mwi_unsub_sub;
00816
00817
00818
00819
00820
00821
00822
00823
00824 struct mwi_sub {
00825 AST_RWLIST_ENTRY(mwi_sub) entry;
00826 int old_urgent;
00827 int old_new;
00828 int old_old;
00829 uint32_t uniqueid;
00830 char mailbox[1];
00831 };
00832
00833 struct mwi_sub_task {
00834 const char *mailbox;
00835 const char *context;
00836 uint32_t uniqueid;
00837 };
00838
00839 static struct ast_taskprocessor *mwi_subscription_tps;
00840
00841 static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
00842
00843
00844 static char listen_control_forward_key[12];
00845 static char listen_control_reverse_key[12];
00846 static char listen_control_pause_key[12];
00847 static char listen_control_restart_key[12];
00848 static char listen_control_stop_key[12];
00849
00850
00851 static char vm_password[80] = "vm-password";
00852 static char vm_newpassword[80] = "vm-newpassword";
00853 static char vm_passchanged[80] = "vm-passchanged";
00854 static char vm_reenterpassword[80] = "vm-reenterpassword";
00855 static char vm_mismatch[80] = "vm-mismatch";
00856 static char vm_invalid_password[80] = "vm-invalid-password";
00857 static char vm_pls_try_again[80] = "vm-pls-try-again";
00858
00859 static struct ast_flags globalflags = {0};
00860
00861 static int saydurationminfo;
00862
00863 static char dialcontext[AST_MAX_CONTEXT] = "";
00864 static char callcontext[AST_MAX_CONTEXT] = "";
00865 static char exitcontext[AST_MAX_CONTEXT] = "";
00866
00867 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
00868
00869
00870 static char *emailbody = NULL;
00871 static char *emailsubject = NULL;
00872 static char *pagerbody = NULL;
00873 static char *pagersubject = NULL;
00874 static char fromstring[100];
00875 static char pagerfromstring[100];
00876 static char charset[32] = "ISO-8859-1";
00877
00878 static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
00879 static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
00880 static int adsiver = 1;
00881 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
00882 static char pagerdateformat[32] = "%A, %B %d, %Y at %r";
00883
00884
00885 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00886 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);
00887 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
00888 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
00889 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
00890 signed char record_gain, struct vm_state *vms, char *flag);
00891 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
00892 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
00893 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);
00894 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);
00895 static void apply_options(struct ast_vm_user *vmu, const char *options);
00896 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);
00897 static int is_valid_dtmf(const char *key);
00898 static void read_password_from_file(const char *secretfn, char *password, int passwordlen);
00899 static int write_password_to_file(const char *secretfn, const char *password);
00900
00901 struct ao2_container *inprocess_container;
00902
00903 struct inprocess {
00904 int count;
00905 char *context;
00906 char mailbox[0];
00907 };
00908
00909 static int inprocess_hash_fn(const void *obj, const int flags)
00910 {
00911 const struct inprocess *i = obj;
00912 return atoi(i->mailbox);
00913 }
00914
00915 static int inprocess_cmp_fn(void *obj, void *arg, int flags)
00916 {
00917 struct inprocess *i = obj, *j = arg;
00918 if (strcmp(i->mailbox, j->mailbox)) {
00919 return 0;
00920 }
00921 return !strcmp(i->context, j->context) ? CMP_MATCH : 0;
00922 }
00923
00924 static int inprocess_count(const char *context, const char *mailbox, int delta)
00925 {
00926 struct inprocess *i, *arg = alloca(sizeof(*arg) + strlen(context) + strlen(mailbox) + 2);
00927 arg->context = arg->mailbox + strlen(mailbox) + 1;
00928 strcpy(arg->mailbox, mailbox);
00929 strcpy(arg->context, context);
00930 ao2_lock(inprocess_container);
00931 if ((i = ao2_find(inprocess_container, arg, 0))) {
00932 int ret = ast_atomic_fetchadd_int(&i->count, delta);
00933 ao2_unlock(inprocess_container);
00934 ao2_ref(i, -1);
00935 return ret;
00936 }
00937 if (delta < 0) {
00938 ast_log(LOG_WARNING, "BUG: ref count decrement on non-existing object???\n");
00939 }
00940 if (!(i = ao2_alloc(sizeof(*i) + strlen(context) + strlen(mailbox) + 2, NULL))) {
00941 ao2_unlock(inprocess_container);
00942 return 0;
00943 }
00944 i->context = i->mailbox + strlen(mailbox) + 1;
00945 strcpy(i->mailbox, mailbox);
00946 strcpy(i->context, context);
00947 i->count = delta;
00948 ao2_link(inprocess_container, i);
00949 ao2_unlock(inprocess_container);
00950 ao2_ref(i, -1);
00951 return 0;
00952 }
00953
00954 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
00955 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
00956 #endif
00957
00958
00959
00960
00961
00962
00963
00964 static char *strip_control_and_high(const char *input, char *buf, size_t buflen)
00965 {
00966 char *bufptr = buf;
00967 for (; *input; input++) {
00968 if (*input < 32) {
00969 continue;
00970 }
00971 *bufptr++ = *input;
00972 if (bufptr == buf + buflen - 1) {
00973 break;
00974 }
00975 }
00976 *bufptr = '\0';
00977 return buf;
00978 }
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993 static void populate_defaults(struct ast_vm_user *vmu)
00994 {
00995 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
00996 vmu->passwordlocation = passwordlocation;
00997 if (saydurationminfo) {
00998 vmu->saydurationm = saydurationminfo;
00999 }
01000 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
01001 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
01002 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
01003 ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
01004 ast_copy_string(vmu->locale, locale, sizeof(vmu->locale));
01005 if (vmminsecs) {
01006 vmu->minsecs = vmminsecs;
01007 }
01008 if (vmmaxsecs) {
01009 vmu->maxsecs = vmmaxsecs;
01010 }
01011 if (maxmsg) {
01012 vmu->maxmsg = maxmsg;
01013 }
01014 if (maxdeletedmsg) {
01015 vmu->maxdeletedmsg = maxdeletedmsg;
01016 }
01017 vmu->volgain = volgain;
01018 vmu->emailsubject = NULL;
01019 vmu->emailbody = NULL;
01020 #ifdef IMAP_STORAGE
01021 ast_copy_string(vmu->imapfolder, imapfolder, sizeof(vmu->imapfolder));
01022 #endif
01023 }
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
01034 {
01035 int x;
01036 if (!strcasecmp(var, "attach")) {
01037 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
01038 } else if (!strcasecmp(var, "attachfmt")) {
01039 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
01040 } else if (!strcasecmp(var, "serveremail")) {
01041 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
01042 } else if (!strcasecmp(var, "language")) {
01043 ast_copy_string(vmu->language, value, sizeof(vmu->language));
01044 } else if (!strcasecmp(var, "tz")) {
01045 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
01046 } else if (!strcasecmp(var, "locale")) {
01047 ast_copy_string(vmu->locale, value, sizeof(vmu->locale));
01048 #ifdef IMAP_STORAGE
01049 } else if (!strcasecmp(var, "imapuser")) {
01050 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
01051 vmu->imapversion = imapversion;
01052 } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
01053 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
01054 vmu->imapversion = imapversion;
01055 } else if (!strcasecmp(var, "imapfolder")) {
01056 ast_copy_string(vmu->imapfolder, value, sizeof(vmu->imapfolder));
01057 } else if (!strcasecmp(var, "imapvmshareid")) {
01058 ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
01059 vmu->imapversion = imapversion;
01060 #endif
01061 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
01062 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
01063 } else if (!strcasecmp(var, "saycid")){
01064 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
01065 } else if (!strcasecmp(var, "sendvoicemail")){
01066 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
01067 } else if (!strcasecmp(var, "review")){
01068 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
01069 } else if (!strcasecmp(var, "tempgreetwarn")){
01070 ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
01071 } else if (!strcasecmp(var, "messagewrap")){
01072 ast_set2_flag(vmu, ast_true(value), VM_MESSAGEWRAP);
01073 } else if (!strcasecmp(var, "operator")) {
01074 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
01075 } else if (!strcasecmp(var, "envelope")){
01076 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
01077 } else if (!strcasecmp(var, "moveheard")){
01078 ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD);
01079 } else if (!strcasecmp(var, "sayduration")){
01080 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
01081 } else if (!strcasecmp(var, "saydurationm")){
01082 if (sscanf(value, "%30d", &x) == 1) {
01083 vmu->saydurationm = x;
01084 } else {
01085 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
01086 }
01087 } else if (!strcasecmp(var, "forcename")){
01088 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
01089 } else if (!strcasecmp(var, "forcegreetings")){
01090 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
01091 } else if (!strcasecmp(var, "callback")) {
01092 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
01093 } else if (!strcasecmp(var, "dialout")) {
01094 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
01095 } else if (!strcasecmp(var, "exitcontext")) {
01096 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
01097 } else if (!strcasecmp(var, "minsecs")) {
01098 if (sscanf(value, "%30d", &x) == 1 && x >= 0) {
01099 vmu->minsecs = x;
01100 } else {
01101 ast_log(LOG_WARNING, "Invalid min message length of %s. Using global value %d\n", value, vmminsecs);
01102 vmu->minsecs = vmminsecs;
01103 }
01104 } else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
01105 vmu->maxsecs = atoi(value);
01106 if (vmu->maxsecs <= 0) {
01107 ast_log(AST_LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
01108 vmu->maxsecs = vmmaxsecs;
01109 } else {
01110 vmu->maxsecs = atoi(value);
01111 }
01112 if (!strcasecmp(var, "maxmessage"))
01113 ast_log(AST_LOG_WARNING, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
01114 } else if (!strcasecmp(var, "maxmsg")) {
01115 vmu->maxmsg = atoi(value);
01116
01117 if (vmu->maxmsg < 0) {
01118 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
01119 vmu->maxmsg = MAXMSG;
01120 } else if (vmu->maxmsg > MAXMSGLIMIT) {
01121 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
01122 vmu->maxmsg = MAXMSGLIMIT;
01123 }
01124 } else if (!strcasecmp(var, "nextaftercmd")) {
01125 ast_set2_flag(vmu, ast_true(value), VM_SKIPAFTERCMD);
01126 } else if (!strcasecmp(var, "backupdeleted")) {
01127 if (sscanf(value, "%30d", &x) == 1)
01128 vmu->maxdeletedmsg = x;
01129 else if (ast_true(value))
01130 vmu->maxdeletedmsg = MAXMSG;
01131 else
01132 vmu->maxdeletedmsg = 0;
01133
01134 if (vmu->maxdeletedmsg < 0) {
01135 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
01136 vmu->maxdeletedmsg = MAXMSG;
01137 } else if (vmu->maxdeletedmsg > MAXMSGLIMIT) {
01138 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
01139 vmu->maxdeletedmsg = MAXMSGLIMIT;
01140 }
01141 } else if (!strcasecmp(var, "volgain")) {
01142 sscanf(value, "%30lf", &vmu->volgain);
01143 } else if (!strcasecmp(var, "passwordlocation")) {
01144 if (!strcasecmp(value, "spooldir")) {
01145 vmu->passwordlocation = OPT_PWLOC_SPOOLDIR;
01146 } else {
01147 vmu->passwordlocation = OPT_PWLOC_VOICEMAILCONF;
01148 }
01149 } else if (!strcasecmp(var, "options")) {
01150 apply_options(vmu, value);
01151 }
01152 }
01153
01154 static char *vm_check_password_shell(char *command, char *buf, size_t len)
01155 {
01156 int fds[2], pid = 0;
01157
01158 memset(buf, 0, len);
01159
01160 if (pipe(fds)) {
01161 snprintf(buf, len, "FAILURE: Pipe failed: %s", strerror(errno));
01162 } else {
01163
01164 pid = ast_safe_fork(0);
01165
01166 if (pid < 0) {
01167
01168 close(fds[0]);
01169 close(fds[1]);
01170 snprintf(buf, len, "FAILURE: Fork failed");
01171 } else if (pid) {
01172
01173 close(fds[1]);
01174 if (read(fds[0], buf, len) < 0) {
01175 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
01176 }
01177 close(fds[0]);
01178 } else {
01179
01180 AST_DECLARE_APP_ARGS(arg,
01181 AST_APP_ARG(v)[20];
01182 );
01183 char *mycmd = ast_strdupa(command);
01184
01185 close(fds[0]);
01186 dup2(fds[1], STDOUT_FILENO);
01187 close(fds[1]);
01188 ast_close_fds_above_n(STDOUT_FILENO);
01189
01190 AST_NONSTANDARD_APP_ARGS(arg, mycmd, ' ');
01191
01192 execv(arg.v[0], arg.v);
01193 printf("FAILURE: %s", strerror(errno));
01194 _exit(0);
01195 }
01196 }
01197 return buf;
01198 }
01199
01200
01201
01202
01203
01204
01205
01206
01207 static int check_password(struct ast_vm_user *vmu, char *password)
01208 {
01209
01210 if (strlen(password) < minpassword)
01211 return 1;
01212 if (!ast_strlen_zero(ext_pass_check_cmd)) {
01213 char cmd[255], buf[255];
01214
01215 ast_log(AST_LOG_DEBUG, "Verify password policies for %s\n", password);
01216
01217 snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
01218 if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
01219 ast_debug(5, "Result: %s\n", buf);
01220 if (!strncasecmp(buf, "VALID", 5)) {
01221 ast_debug(3, "Passed password check: '%s'\n", buf);
01222 return 0;
01223 } else if (!strncasecmp(buf, "FAILURE", 7)) {
01224 ast_log(AST_LOG_WARNING, "Unable to execute password validation script: '%s'.\n", buf);
01225 return 0;
01226 } else {
01227 ast_log(AST_LOG_NOTICE, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
01228 return 1;
01229 }
01230 }
01231 }
01232 return 0;
01233 }
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
01246 {
01247 int res = -1;
01248 if (!strcmp(vmu->password, password)) {
01249
01250 return 0;
01251 }
01252
01253 if (strlen(password) > 10) {
01254 ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL);
01255 }
01256 if (ast_update2_realtime("voicemail", "context", vmu->context, "mailbox", vmu->mailbox, SENTINEL, "password", password, SENTINEL) > 0) {
01257 ast_copy_string(vmu->password, password, sizeof(vmu->password));
01258 res = 0;
01259 }
01260 return res;
01261 }
01262
01263
01264
01265
01266 static void apply_options(struct ast_vm_user *vmu, const char *options)
01267 {
01268 char *stringp;
01269 char *s;
01270 char *var, *value;
01271 stringp = ast_strdupa(options);
01272 while ((s = strsep(&stringp, "|"))) {
01273 value = s;
01274 if ((var = strsep(&value, "=")) && value) {
01275 apply_option(vmu, var, value);
01276 }
01277 }
01278 }
01279
01280
01281
01282
01283
01284
01285 static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
01286 {
01287 for (; var; var = var->next) {
01288 if (!strcasecmp(var->name, "vmsecret")) {
01289 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01290 } else if (!strcasecmp(var->name, "secret") || !strcasecmp(var->name, "password")) {
01291 if (ast_strlen_zero(retval->password))
01292 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01293 } else if (!strcasecmp(var->name, "uniqueid")) {
01294 ast_copy_string(retval->uniqueid, var->value, sizeof(retval->uniqueid));
01295 } else if (!strcasecmp(var->name, "pager")) {
01296 ast_copy_string(retval->pager, var->value, sizeof(retval->pager));
01297 } else if (!strcasecmp(var->name, "email")) {
01298 ast_copy_string(retval->email, var->value, sizeof(retval->email));
01299 } else if (!strcasecmp(var->name, "fullname")) {
01300 ast_copy_string(retval->fullname, var->value, sizeof(retval->fullname));
01301 } else if (!strcasecmp(var->name, "context")) {
01302 ast_copy_string(retval->context, var->value, sizeof(retval->context));
01303 } else if (!strcasecmp(var->name, "emailsubject")) {
01304 retval->emailsubject = ast_strdup(var->value);
01305 } else if (!strcasecmp(var->name, "emailbody")) {
01306 retval->emailbody = ast_strdup(var->value);
01307 #ifdef IMAP_STORAGE
01308 } else if (!strcasecmp(var->name, "imapuser")) {
01309 ast_copy_string(retval->imapuser, var->value, sizeof(retval->imapuser));
01310 retval->imapversion = imapversion;
01311 } else if (!strcasecmp(var->name, "imappassword") || !strcasecmp(var->name, "imapsecret")) {
01312 ast_copy_string(retval->imappassword, var->value, sizeof(retval->imappassword));
01313 retval->imapversion = imapversion;
01314 } else if (!strcasecmp(var->name, "imapfolder")) {
01315 ast_copy_string(retval->imapfolder, var->value, sizeof(retval->imapfolder));
01316 } else if (!strcasecmp(var->name, "imapvmshareid")) {
01317 ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
01318 retval->imapversion = imapversion;
01319 #endif
01320 } else
01321 apply_option(retval, var->name, var->value);
01322 }
01323 }
01324
01325
01326
01327
01328
01329
01330
01331
01332 static int is_valid_dtmf(const char *key)
01333 {
01334 int i;
01335 char *local_key = ast_strdupa(key);
01336
01337 for (i = 0; i < strlen(key); ++i) {
01338 if (!strchr(VALID_DTMF, *local_key)) {
01339 ast_log(AST_LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
01340 return 0;
01341 }
01342 local_key++;
01343 }
01344 return 1;
01345 }
01346
01347
01348
01349
01350
01351
01352
01353
01354
01355
01356
01357 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01358 {
01359 struct ast_variable *var;
01360 struct ast_vm_user *retval;
01361
01362 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
01363 if (!ivm)
01364 ast_set_flag(retval, VM_ALLOCED);
01365 else
01366 memset(retval, 0, sizeof(*retval));
01367 if (mailbox)
01368 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
01369 populate_defaults(retval);
01370 if (!context && ast_test_flag((&globalflags), VM_SEARCH))
01371 var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
01372 else
01373 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
01374 if (var) {
01375 apply_options_full(retval, var);
01376 ast_variables_destroy(var);
01377 } else {
01378 if (!ivm)
01379 ast_free(retval);
01380 retval = NULL;
01381 }
01382 }
01383 return retval;
01384 }
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01395 {
01396
01397 struct ast_vm_user *vmu = NULL, *cur;
01398 AST_LIST_LOCK(&users);
01399
01400 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
01401 context = "default";
01402
01403 AST_LIST_TRAVERSE(&users, cur, list) {
01404 #ifdef IMAP_STORAGE
01405 if (cur->imapversion != imapversion) {
01406 continue;
01407 }
01408 #endif
01409 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
01410 break;
01411 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
01412 break;
01413 }
01414 if (cur) {
01415
01416 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
01417 memcpy(vmu, cur, sizeof(*vmu));
01418 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
01419 AST_LIST_NEXT(vmu, list) = NULL;
01420 }
01421 } else
01422 vmu = find_user_realtime(ivm, context, mailbox);
01423 AST_LIST_UNLOCK(&users);
01424 return vmu;
01425 }
01426
01427
01428
01429
01430
01431
01432
01433
01434
01435
01436
01437 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
01438 {
01439
01440 struct ast_vm_user *cur;
01441 int res = -1;
01442 AST_LIST_LOCK(&users);
01443 AST_LIST_TRAVERSE(&users, cur, list) {
01444 if ((!context || !strcasecmp(context, cur->context)) &&
01445 (!strcasecmp(mailbox, cur->mailbox)))
01446 break;
01447 }
01448 if (cur) {
01449 ast_copy_string(cur->password, newpass, sizeof(cur->password));
01450 res = 0;
01451 }
01452 AST_LIST_UNLOCK(&users);
01453 return res;
01454 }
01455
01456
01457
01458
01459
01460
01461
01462
01463 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
01464 {
01465 struct ast_config *cfg = NULL;
01466 struct ast_variable *var = NULL;
01467 struct ast_category *cat = NULL;
01468 char *category = NULL, *value = NULL, *new = NULL;
01469 const char *tmp = NULL;
01470 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
01471 char secretfn[PATH_MAX] = "";
01472 int found = 0;
01473
01474 if (!change_password_realtime(vmu, newpassword))
01475 return;
01476
01477
01478 switch (vmu->passwordlocation) {
01479 case OPT_PWLOC_SPOOLDIR:
01480 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
01481 if (write_password_to_file(secretfn, newpassword) == 0) {
01482 ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn);
01483 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01484 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01485 break;
01486 } else {
01487 ast_verb(4, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
01488 }
01489
01490 case OPT_PWLOC_VOICEMAILCONF:
01491 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01492 while ((category = ast_category_browse(cfg, category))) {
01493 if (!strcasecmp(category, vmu->context)) {
01494 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
01495 ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
01496 break;
01497 }
01498 value = strstr(tmp, ",");
01499 if (!value) {
01500 new = alloca(strlen(newpassword)+1);
01501 sprintf(new, "%s", newpassword);
01502 } else {
01503 new = alloca((strlen(value) + strlen(newpassword) + 1));
01504 sprintf(new, "%s%s", newpassword, value);
01505 }
01506 if (!(cat = ast_category_get(cfg, category))) {
01507 ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
01508 break;
01509 }
01510 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
01511 found = 1;
01512 }
01513 }
01514
01515 if (found) {
01516 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01517 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01518 ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
01519 break;
01520 }
01521 }
01522
01523 case OPT_PWLOC_USERSCONF:
01524
01525
01526 if ((cfg = ast_config_load("users.conf", config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01527 ast_debug(4, "we are looking for %s\n", vmu->mailbox);
01528 for (category = ast_category_browse(cfg, NULL); category; category = ast_category_browse(cfg, category)) {
01529 ast_debug(4, "users.conf: %s\n", category);
01530 if (!strcasecmp(category, vmu->mailbox)) {
01531 if (!(tmp = ast_variable_retrieve(cfg, category, "vmsecret"))) {
01532 ast_debug(3, "looks like we need to make vmsecret!\n");
01533 var = ast_variable_new("vmsecret", newpassword, "");
01534 } else {
01535 var = NULL;
01536 }
01537 new = alloca(strlen(newpassword) + 1);
01538 sprintf(new, "%s", newpassword);
01539 if (!(cat = ast_category_get(cfg, category))) {
01540 ast_debug(4, "failed to get category!\n");
01541 ast_free(var);
01542 break;
01543 }
01544 if (!var) {
01545 ast_variable_update(cat, "vmsecret", new, NULL, 0);
01546 } else {
01547 ast_variable_append(cat, var);
01548 }
01549 found = 1;
01550 break;
01551 }
01552 }
01553
01554 if (found) {
01555 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01556 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01557 ast_config_text_file_save("users.conf", cfg, "AppVoicemail");
01558 }
01559 }
01560 }
01561 }
01562
01563 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
01564 {
01565 char buf[255];
01566 snprintf(buf, sizeof(buf), "%s %s %s %s", ext_pass_cmd, vmu->context, vmu->mailbox, newpassword);
01567 if (!ast_safe_system(buf)) {
01568 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01569
01570 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01571 }
01572 }
01573
01574
01575
01576
01577
01578
01579
01580
01581
01582
01583
01584
01585
01586
01587 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
01588 {
01589 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
01590 }
01591
01592
01593
01594
01595
01596
01597
01598
01599
01600
01601
01602
01603
01604 static int make_file(char *dest, const int len, const char *dir, const int num)
01605 {
01606 return snprintf(dest, len, "%s/msg%04d", dir, num);
01607 }
01608
01609
01610 static FILE *vm_mkftemp(char *template)
01611 {
01612 FILE *p = NULL;
01613 int pfd = mkstemp(template);
01614 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01615 if (pfd > -1) {
01616 p = fdopen(pfd, "w+");
01617 if (!p) {
01618 close(pfd);
01619 pfd = -1;
01620 }
01621 }
01622 return p;
01623 }
01624
01625
01626
01627
01628
01629
01630
01631
01632
01633 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
01634 {
01635 mode_t mode = VOICEMAIL_DIR_MODE;
01636 int res;
01637
01638 make_dir(dest, len, context, ext, folder);
01639 if ((res = ast_mkdir(dest, mode))) {
01640 ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
01641 return -1;
01642 }
01643 return 0;
01644 }
01645
01646 static const char * const mailbox_folders[] = {
01647 #ifdef IMAP_STORAGE
01648 imapfolder,
01649 #else
01650 "INBOX",
01651 #endif
01652 "Old",
01653 "Work",
01654 "Family",
01655 "Friends",
01656 "Cust1",
01657 "Cust2",
01658 "Cust3",
01659 "Cust4",
01660 "Cust5",
01661 "Deleted",
01662 "Urgent",
01663 };
01664
01665 static const char *mbox(struct ast_vm_user *vmu, int id)
01666 {
01667 #ifdef IMAP_STORAGE
01668 if (vmu && id == 0) {
01669 return vmu->imapfolder;
01670 }
01671 #endif
01672 return (id >= 0 && id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] : "Unknown";
01673 }
01674
01675 static int get_folder_by_name(const char *name)
01676 {
01677 size_t i;
01678
01679 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
01680 if (strcasecmp(name, mailbox_folders[i]) == 0) {
01681 return i;
01682 }
01683 }
01684
01685 return -1;
01686 }
01687
01688 static void free_user(struct ast_vm_user *vmu)
01689 {
01690 if (ast_test_flag(vmu, VM_ALLOCED)) {
01691 if (vmu->emailbody != NULL) {
01692 ast_free(vmu->emailbody);
01693 vmu->emailbody = NULL;
01694 }
01695 if (vmu->emailsubject != NULL) {
01696 ast_free(vmu->emailsubject);
01697 vmu->emailsubject = NULL;
01698 }
01699 ast_free(vmu);
01700 }
01701 }
01702
01703 static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
01704
01705 int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
01706 if (!vms->dh_arraysize) {
01707
01708 if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
01709 return -1;
01710 }
01711 if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
01712 return -1;
01713 }
01714 vms->dh_arraysize = arraysize;
01715 } else if (vms->dh_arraysize < arraysize) {
01716 if (!(vms->deleted = ast_realloc(vms->deleted, arraysize * sizeof(int)))) {
01717 return -1;
01718 }
01719 if (!(vms->heard = ast_realloc(vms->heard, arraysize * sizeof(int)))) {
01720 return -1;
01721 }
01722 memset(vms->deleted, 0, arraysize * sizeof(int));
01723 memset(vms->heard, 0, arraysize * sizeof(int));
01724 vms->dh_arraysize = arraysize;
01725 }
01726
01727 return 0;
01728 }
01729
01730
01731
01732 #ifdef IMAP_STORAGE
01733 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
01734 {
01735 char arg[10];
01736 struct vm_state *vms;
01737 unsigned long messageNum;
01738
01739
01740 if (msgnum < 0 && !imapgreetings) {
01741 ast_filedelete(file, NULL);
01742 return;
01743 }
01744
01745 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01746 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);
01747 return;
01748 }
01749
01750
01751
01752 messageNum = vms->msgArray[msgnum];
01753 if (messageNum == 0) {
01754 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
01755 return;
01756 }
01757 if (option_debug > 2)
01758 ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
01759
01760 snprintf (arg, sizeof(arg), "%lu", messageNum);
01761 ast_mutex_lock(&vms->lock);
01762 mail_setflag (vms->mailstream, arg, "\\DELETED");
01763 mail_expunge(vms->mailstream);
01764 ast_mutex_unlock(&vms->lock);
01765 }
01766
01767 static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_vm_user *vmu)
01768 {
01769 struct vm_state *vms_p;
01770 char *file, *filename;
01771 char *attachment;
01772 int ret = 0, i;
01773 BODY *body;
01774
01775
01776
01777
01778 if (msgnum > -1 || !imapgreetings) {
01779 return 0;
01780 } else {
01781 file = strrchr(ast_strdupa(dir), '/');
01782 if (file)
01783 *file++ = '\0';
01784 else {
01785 ast_debug (1, "Failed to procure file name from directory passed.\n");
01786 return -1;
01787 }
01788 }
01789
01790
01791 if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) &&
01792 !(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01793
01794
01795
01796
01797 if (!(vms_p = create_vm_state_from_user(vmu))) {
01798 ast_log(LOG_NOTICE, "Unable to create vm_state object!\n");
01799 return -1;
01800 }
01801 }
01802
01803
01804 *vms_p->introfn = '\0';
01805
01806 ast_mutex_lock(&vms_p->lock);
01807 ret = init_mailstream(vms_p, GREETINGS_FOLDER);
01808 if (!vms_p->mailstream) {
01809 ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL\n");
01810 ast_mutex_unlock(&vms_p->lock);
01811 return -1;
01812 }
01813
01814
01815 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
01816 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
01817
01818 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01819 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
01820 } else {
01821 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
01822 ast_mutex_unlock(&vms_p->lock);
01823 return -1;
01824 }
01825 filename = strsep(&attachment, ".");
01826 if (!strcmp(filename, file)) {
01827 ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
01828 vms_p->msgArray[vms_p->curmsg] = i + 1;
01829 save_body(body, vms_p, "2", attachment, 0);
01830 ast_mutex_unlock(&vms_p->lock);
01831 return 0;
01832 }
01833 }
01834 ast_mutex_unlock(&vms_p->lock);
01835
01836 return -1;
01837 }
01838
01839 static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
01840 {
01841 BODY *body;
01842 char *header_content;
01843 char *attachedfilefmt;
01844 char buf[80];
01845 struct vm_state *vms;
01846 char text_file[PATH_MAX];
01847 FILE *text_file_ptr;
01848 int res = 0;
01849 struct ast_vm_user *vmu;
01850
01851 if (!(vmu = find_user(NULL, context, mailbox))) {
01852 ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
01853 return -1;
01854 }
01855
01856 if (msgnum < 0) {
01857 if (imapgreetings) {
01858 res = imap_retrieve_greeting(dir, msgnum, vmu);
01859 goto exit;
01860 } else {
01861 res = 0;
01862 goto exit;
01863 }
01864 }
01865
01866
01867
01868
01869 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01870
01871
01872
01873
01874
01875
01876
01877 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
01878 res = -1;
01879 goto exit;
01880 }
01881
01882 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
01883 snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
01884
01885
01886 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
01887 res = 0;
01888 goto exit;
01889 }
01890
01891 if (option_debug > 2)
01892 ast_log(LOG_DEBUG, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
01893 if (vms->msgArray[msgnum] == 0) {
01894 ast_log(LOG_WARNING, "Trying to access unknown message\n");
01895 res = -1;
01896 goto exit;
01897 }
01898
01899
01900 ast_mutex_lock(&vms->lock);
01901 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
01902 ast_mutex_unlock(&vms->lock);
01903
01904 if (ast_strlen_zero(header_content)) {
01905 ast_log(LOG_ERROR, "Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
01906 res = -1;
01907 goto exit;
01908 }
01909
01910 ast_mutex_lock(&vms->lock);
01911 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
01912 ast_mutex_unlock(&vms->lock);
01913
01914
01915 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01916 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
01917 } else {
01918 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01919 res = -1;
01920 goto exit;
01921 }
01922
01923
01924
01925 strsep(&attachedfilefmt, ".");
01926 if (!attachedfilefmt) {
01927 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
01928 res = -1;
01929 goto exit;
01930 }
01931
01932 save_body(body, vms, "2", attachedfilefmt, 0);
01933 if (save_body(body, vms, "3", attachedfilefmt, 1)) {
01934 *vms->introfn = '\0';
01935 }
01936
01937
01938 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
01939
01940 if (!(text_file_ptr = fopen(text_file, "w"))) {
01941 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
01942 }
01943
01944 fprintf(text_file_ptr, "%s\n", "[message]");
01945
01946 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf));
01947 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
01948 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf));
01949 fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
01950 get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf));
01951 fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
01952 get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf));
01953 fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
01954 get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf));
01955 fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
01956 get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf));
01957 fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
01958 get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf));
01959 fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
01960 fclose(text_file_ptr);
01961
01962 exit:
01963 free_user(vmu);
01964 return res;
01965 }
01966
01967 static int folder_int(const char *folder)
01968 {
01969
01970 if (!folder) {
01971 return 0;
01972 }
01973 if (!strcasecmp(folder, imapfolder)) {
01974 return 0;
01975 } else if (!strcasecmp(folder, "Old")) {
01976 return 1;
01977 } else if (!strcasecmp(folder, "Work")) {
01978 return 2;
01979 } else if (!strcasecmp(folder, "Family")) {
01980 return 3;
01981 } else if (!strcasecmp(folder, "Friends")) {
01982 return 4;
01983 } else if (!strcasecmp(folder, "Cust1")) {
01984 return 5;
01985 } else if (!strcasecmp(folder, "Cust2")) {
01986 return 6;
01987 } else if (!strcasecmp(folder, "Cust3")) {
01988 return 7;
01989 } else if (!strcasecmp(folder, "Cust4")) {
01990 return 8;
01991 } else if (!strcasecmp(folder, "Cust5")) {
01992 return 9;
01993 } else if (!strcasecmp(folder, "Urgent")) {
01994 return 11;
01995 } else {
01996 return 0;
01997 }
01998 }
01999
02000 static int __messagecount(const char *context, const char *mailbox, const char *folder)
02001 {
02002 SEARCHPGM *pgm;
02003 SEARCHHEADER *hdr;
02004
02005 struct ast_vm_user *vmu, vmus;
02006 struct vm_state *vms_p;
02007 int ret = 0;
02008 int fold = folder_int(folder);
02009 int urgent = 0;
02010
02011
02012 if (fold == 11) {
02013 fold = NEW_FOLDER;
02014 urgent = 1;
02015 }
02016
02017 if (ast_strlen_zero(mailbox))
02018 return 0;
02019
02020
02021 vmu = find_user(&vmus, context, mailbox);
02022 if (!vmu) {
02023 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
02024 return -1;
02025 } else {
02026
02027 if (vmu->imapuser[0] == '\0') {
02028 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02029 return -1;
02030 }
02031 }
02032
02033
02034 if (vmu->imapuser[0] == '\0') {
02035 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02036 free_user(vmu);
02037 return -1;
02038 }
02039
02040
02041 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
02042 if (!vms_p) {
02043 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
02044 }
02045 if (vms_p) {
02046 ast_debug(3, "Returning before search - user is logged in\n");
02047 if (fold == 0) {
02048 return urgent ? vms_p->urgentmessages : vms_p->newmessages;
02049 }
02050 if (fold == 1) {
02051 return vms_p->oldmessages;
02052 }
02053 }
02054
02055
02056 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
02057 if (!vms_p) {
02058 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
02059 }
02060
02061 if (!vms_p) {
02062 vms_p = create_vm_state_from_user(vmu);
02063 }
02064 ret = init_mailstream(vms_p, fold);
02065 if (!vms_p->mailstream) {
02066 ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
02067 return -1;
02068 }
02069 if (ret == 0) {
02070 ast_mutex_lock(&vms_p->lock);
02071 pgm = mail_newsearchpgm ();
02072 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
02073 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
02074 pgm->header = hdr;
02075 if (fold != OLD_FOLDER) {
02076 pgm->unseen = 1;
02077 pgm->seen = 0;
02078 }
02079
02080
02081
02082 else {
02083 pgm->unseen = 0;
02084 pgm->seen = 1;
02085 }
02086
02087 if (fold == NEW_FOLDER) {
02088 if (urgent) {
02089 pgm->flagged = 1;
02090 pgm->unflagged = 0;
02091 } else {
02092 pgm->flagged = 0;
02093 pgm->unflagged = 1;
02094 }
02095 }
02096 pgm->undeleted = 1;
02097 pgm->deleted = 0;
02098
02099 vms_p->vmArrayIndex = 0;
02100 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
02101 if (fold == 0 && urgent == 0)
02102 vms_p->newmessages = vms_p->vmArrayIndex;
02103 if (fold == 1)
02104 vms_p->oldmessages = vms_p->vmArrayIndex;
02105 if (fold == 0 && urgent == 1)
02106 vms_p->urgentmessages = vms_p->vmArrayIndex;
02107
02108 mail_free_searchpgm(&pgm);
02109 ast_mutex_unlock(&vms_p->lock);
02110 vms_p->updated = 0;
02111 return vms_p->vmArrayIndex;
02112 } else {
02113 ast_mutex_lock(&vms_p->lock);
02114 mail_ping(vms_p->mailstream);
02115 ast_mutex_unlock(&vms_p->lock);
02116 }
02117 return 0;
02118 }
02119
02120 static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
02121 {
02122
02123 check_quota(vms, vmu->imapfolder);
02124 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
02125 ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
02126 ast_play_and_wait(chan, "vm-mailboxfull");
02127 return -1;
02128 }
02129
02130
02131 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));
02132 if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
02133 ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
02134 ast_play_and_wait(chan, "vm-mailboxfull");
02135 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
02136 return -1;
02137 }
02138
02139 return 0;
02140 }
02141
02142
02143
02144
02145
02146
02147
02148
02149
02150
02151 static int messagecount(const char *context, const char *mailbox, const char *folder)
02152 {
02153 if (ast_strlen_zero(folder) || !strcmp(folder, "INBOX")) {
02154 return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
02155 } else {
02156 return __messagecount(context, mailbox, folder);
02157 }
02158 }
02159
02160 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)
02161 {
02162 char *myserveremail = serveremail;
02163 char fn[PATH_MAX];
02164 char introfn[PATH_MAX];
02165 char mailbox[256];
02166 char *stringp;
02167 FILE *p = NULL;
02168 char tmp[80] = "/tmp/astmail-XXXXXX";
02169 long len;
02170 void *buf;
02171 int tempcopy = 0;
02172 STRING str;
02173 int ret;
02174 char *imap_flags = NIL;
02175 int msgcount = (messagecount(vmu->context, vmu->mailbox, "INBOX") + messagecount(vmu->context, vmu->mailbox, "Old"));
02176
02177
02178 if (msgnum < 0 && !imapgreetings) {
02179 return 0;
02180 }
02181
02182 if (imap_check_limits(chan, vms, vmu, msgcount)) {
02183 return -1;
02184 }
02185
02186
02187 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
02188 ast_debug(3, "Setting message flag \\\\FLAGGED.\n");
02189 imap_flags = "\\FLAGGED";
02190 }
02191
02192
02193 fmt = ast_strdupa(fmt);
02194 stringp = fmt;
02195 strsep(&stringp, "|");
02196
02197 if (!ast_strlen_zero(vmu->serveremail))
02198 myserveremail = vmu->serveremail;
02199
02200 if (msgnum > -1)
02201 make_file(fn, sizeof(fn), dir, msgnum);
02202 else
02203 ast_copy_string (fn, dir, sizeof(fn));
02204
02205 snprintf(introfn, sizeof(introfn), "%sintro", fn);
02206 if (ast_fileexists(introfn, NULL, NULL) <= 0) {
02207 *introfn = '\0';
02208 }
02209
02210 if (ast_strlen_zero(vmu->email)) {
02211
02212
02213
02214
02215
02216 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
02217 tempcopy = 1;
02218 }
02219
02220 if (!strcmp(fmt, "wav49"))
02221 fmt = "WAV";
02222 ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
02223
02224
02225
02226 if (!(p = vm_mkftemp(tmp))) {
02227 ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
02228 if (tempcopy)
02229 *(vmu->email) = '\0';
02230 return -1;
02231 }
02232
02233 if (msgnum < 0 && imapgreetings) {
02234 if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
02235 ast_log(AST_LOG_WARNING, "Unable to open mailstream.\n");
02236 return -1;
02237 }
02238 imap_delete_old_greeting(fn, vms);
02239 }
02240
02241 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX",
02242 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
02243 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
02244 fn, introfn, fmt, duration, 1, chan, NULL, 1, flag);
02245
02246 len = ftell(p);
02247 rewind(p);
02248 if (!(buf = ast_malloc(len + 1))) {
02249 ast_log(AST_LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
02250 fclose(p);
02251 if (tempcopy)
02252 *(vmu->email) = '\0';
02253 return -1;
02254 }
02255 if (fread(buf, len, 1, p) < len) {
02256 if (ferror(p)) {
02257 ast_log(LOG_ERROR, "Short read while reading in mail file.\n");
02258 return -1;
02259 }
02260 }
02261 ((char *) buf)[len] = '\0';
02262 INIT(&str, mail_string, buf, len);
02263 ret = init_mailstream(vms, NEW_FOLDER);
02264 if (ret == 0) {
02265 imap_mailbox_name(mailbox, sizeof(mailbox), vms, NEW_FOLDER, 1);
02266 ast_mutex_lock(&vms->lock);
02267 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
02268 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
02269 ast_mutex_unlock(&vms->lock);
02270 fclose(p);
02271 unlink(tmp);
02272 ast_free(buf);
02273 } else {
02274 ast_log(LOG_ERROR, "Could not initialize mailstream for %s\n", mailbox);
02275 fclose(p);
02276 unlink(tmp);
02277 ast_free(buf);
02278 return -1;
02279 }
02280 ast_debug(3, "%s stored\n", fn);
02281
02282 if (tempcopy)
02283 *(vmu->email) = '\0';
02284 inprocess_count(vmu->mailbox, vmu->context, -1);
02285 return 0;
02286
02287 }
02288
02289
02290
02291
02292
02293
02294
02295
02296
02297
02298
02299
02300
02301
02302 static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
02303 {
02304 char tmp[PATH_MAX] = "";
02305 char *mailboxnc;
02306 char *context;
02307 char *mb;
02308 char *cur;
02309 if (newmsgs)
02310 *newmsgs = 0;
02311 if (oldmsgs)
02312 *oldmsgs = 0;
02313 if (urgentmsgs)
02314 *urgentmsgs = 0;
02315
02316 ast_debug(3, "Mailbox is set to %s\n", mailbox_context);
02317
02318 if (ast_strlen_zero(mailbox_context))
02319 return 0;
02320
02321 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02322 context = strchr(tmp, '@');
02323 if (strchr(mailbox_context, ',')) {
02324 int tmpnew, tmpold, tmpurgent;
02325 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02326 mb = tmp;
02327 while ((cur = strsep(&mb, ", "))) {
02328 if (!ast_strlen_zero(cur)) {
02329 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
02330 return -1;
02331 else {
02332 if (newmsgs)
02333 *newmsgs += tmpnew;
02334 if (oldmsgs)
02335 *oldmsgs += tmpold;
02336 if (urgentmsgs)
02337 *urgentmsgs += tmpurgent;
02338 }
02339 }
02340 }
02341 return 0;
02342 }
02343 if (context) {
02344 *context = '\0';
02345 mailboxnc = tmp;
02346 context++;
02347 } else {
02348 context = "default";
02349 mailboxnc = (char *) mailbox_context;
02350 }
02351
02352 if (newmsgs) {
02353 struct ast_vm_user *vmu = find_user(NULL, context, mailboxnc);
02354 if (!vmu) {
02355 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailboxnc, context);
02356 return -1;
02357 }
02358 if ((*newmsgs = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
02359 return -1;
02360 }
02361 }
02362 if (oldmsgs) {
02363 if ((*oldmsgs = __messagecount(context, mailboxnc, "Old")) < 0) {
02364 return -1;
02365 }
02366 }
02367 if (urgentmsgs) {
02368 if ((*urgentmsgs = __messagecount(context, mailboxnc, "Urgent")) < 0) {
02369 return -1;
02370 }
02371 }
02372 return 0;
02373 }
02374
02375
02376
02377
02378
02379
02380
02381
02382
02383
02384
02385 static int has_voicemail(const char *mailbox, const char *folder)
02386 {
02387 char tmp[256], *tmp2, *box, *context;
02388 ast_copy_string(tmp, mailbox, sizeof(tmp));
02389 tmp2 = tmp;
02390 if (strchr(tmp2, ',') || strchr(tmp2, '&')) {
02391 while ((box = strsep(&tmp2, ",&"))) {
02392 if (!ast_strlen_zero(box)) {
02393 if (has_voicemail(box, folder)) {
02394 return 1;
02395 }
02396 }
02397 }
02398 }
02399 if ((context = strchr(tmp, '@'))) {
02400 *context++ = '\0';
02401 } else {
02402 context = "default";
02403 }
02404 return __messagecount(context, tmp, folder) ? 1 : 0;
02405 }
02406
02407
02408
02409
02410
02411
02412
02413
02414
02415
02416
02417
02418
02419
02420
02421
02422 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)
02423 {
02424 struct vm_state *sendvms = NULL, *destvms = NULL;
02425 char messagestring[10];
02426 if (msgnum >= recip->maxmsg) {
02427 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
02428 return -1;
02429 }
02430 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
02431 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
02432 return -1;
02433 }
02434 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
02435 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
02436 return -1;
02437 }
02438 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
02439 ast_mutex_lock(&sendvms->lock);
02440 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(vmu, imbox)) == T)) {
02441 ast_mutex_unlock(&sendvms->lock);
02442 return 0;
02443 }
02444 ast_mutex_unlock(&sendvms->lock);
02445 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
02446 return -1;
02447 }
02448
02449 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
02450 {
02451 char tmp[256], *t = tmp;
02452 size_t left = sizeof(tmp);
02453
02454 if (box == OLD_FOLDER) {
02455 ast_copy_string(vms->curbox, mbox(NULL, NEW_FOLDER), sizeof(vms->curbox));
02456 } else {
02457 ast_copy_string(vms->curbox, mbox(NULL, box), sizeof(vms->curbox));
02458 }
02459
02460 if (box == NEW_FOLDER) {
02461 ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
02462 } else {
02463 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(NULL, box));
02464 }
02465
02466
02467 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
02468
02469
02470 if (!ast_strlen_zero(authuser))
02471 ast_build_string(&t, &left, "/authuser=%s", authuser);
02472
02473
02474 if (!ast_strlen_zero(imapflags))
02475 ast_build_string(&t, &left, "/%s", imapflags);
02476
02477
02478 #if 1
02479 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
02480 #else
02481 ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
02482 #endif
02483 if (box == NEW_FOLDER || box == OLD_FOLDER)
02484 snprintf(spec, len, "%s%s", tmp, use_folder? vms->imapfolder: "INBOX");
02485 else if (box == GREETINGS_FOLDER)
02486 snprintf(spec, len, "%s%s", tmp, greetingfolder);
02487 else {
02488 if (!ast_strlen_zero(imapparentfolder)) {
02489
02490 snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(NULL, box));
02491 } else {
02492 snprintf(spec, len, "%s%s", tmp, mbox(NULL, box));
02493 }
02494 }
02495 }
02496
02497 static int init_mailstream(struct vm_state *vms, int box)
02498 {
02499 MAILSTREAM *stream = NIL;
02500 long debug;
02501 char tmp[256];
02502
02503 if (!vms) {
02504 ast_log(LOG_ERROR, "vm_state is NULL!\n");
02505 return -1;
02506 }
02507 if (option_debug > 2)
02508 ast_log(LOG_DEBUG, "vm_state user is:%s\n", vms->imapuser);
02509 if (vms->mailstream == NIL || !vms->mailstream) {
02510 if (option_debug)
02511 ast_log(LOG_DEBUG, "mailstream not set.\n");
02512 } else {
02513 stream = vms->mailstream;
02514 }
02515
02516 debug = NIL;
02517
02518 if (delimiter == '\0') {
02519 char *cp;
02520 #ifdef USE_SYSTEM_IMAP
02521 #include <imap/linkage.c>
02522 #elif defined(USE_SYSTEM_CCLIENT)
02523 #include <c-client/linkage.c>
02524 #else
02525 #include "linkage.c"
02526 #endif
02527
02528 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
02529 ast_mutex_lock(&vms->lock);
02530 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02531 ast_mutex_unlock(&vms->lock);
02532 if (stream == NIL) {
02533 ast_log(LOG_ERROR, "Can't connect to imap server %s\n", tmp);
02534 return -1;
02535 }
02536 get_mailbox_delimiter(stream);
02537
02538 for (cp = vms->imapfolder; *cp; cp++)
02539 if (*cp == '/')
02540 *cp = delimiter;
02541 }
02542
02543 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
02544 if (option_debug > 2)
02545 ast_log(LOG_DEBUG, "Before mail_open, server: %s, box:%d\n", tmp, box);
02546 ast_mutex_lock(&vms->lock);
02547 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02548 ast_mutex_unlock(&vms->lock);
02549 if (vms->mailstream == NIL) {
02550 return -1;
02551 } else {
02552 return 0;
02553 }
02554 }
02555
02556 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
02557 {
02558 SEARCHPGM *pgm;
02559 SEARCHHEADER *hdr;
02560 int ret, urgent = 0;
02561
02562
02563 if (box == 11) {
02564 box = NEW_FOLDER;
02565 urgent = 1;
02566 }
02567
02568 ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser));
02569 ast_copy_string(vms->imapfolder, vmu->imapfolder, sizeof(vms->imapfolder));
02570 vms->imapversion = vmu->imapversion;
02571 ast_debug(3, "Before init_mailstream, user is %s\n", vmu->imapuser);
02572
02573 if ((ret = init_mailstream(vms, box)) || !vms->mailstream) {
02574 ast_log(AST_LOG_ERROR, "Could not initialize mailstream\n");
02575 return -1;
02576 }
02577
02578 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
02579
02580
02581 if (box == 0) {
02582 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(vmu, box));
02583 check_quota(vms, (char *) mbox(vmu, box));
02584 }
02585
02586 ast_mutex_lock(&vms->lock);
02587 pgm = mail_newsearchpgm();
02588
02589
02590 hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
02591 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
02592 pgm->header = hdr;
02593 pgm->deleted = 0;
02594 pgm->undeleted = 1;
02595
02596
02597 if (box == NEW_FOLDER && urgent == 1) {
02598 pgm->unseen = 1;
02599 pgm->seen = 0;
02600 pgm->flagged = 1;
02601 pgm->unflagged = 0;
02602 } else if (box == NEW_FOLDER && urgent == 0) {
02603 pgm->unseen = 1;
02604 pgm->seen = 0;
02605 pgm->flagged = 0;
02606 pgm->unflagged = 1;
02607 } else if (box == OLD_FOLDER) {
02608 pgm->seen = 1;
02609 pgm->unseen = 0;
02610 }
02611
02612 ast_debug(3, "Before mail_search_full, user is %s\n", vmu->imapuser);
02613
02614 vms->vmArrayIndex = 0;
02615 mail_search_full (vms->mailstream, NULL, pgm, NIL);
02616 vms->lastmsg = vms->vmArrayIndex - 1;
02617 mail_free_searchpgm(&pgm);
02618
02619
02620
02621
02622 if (box == 0 && !vms->dh_arraysize) {
02623 ast_log(LOG_WARNING, "The code expects the old messages to be checked first, fix the code.\n");
02624 }
02625 if (vm_allocate_dh(vms, vmu, box == 0 ? vms->vmArrayIndex + vms->oldmessages : vms->lastmsg)) {
02626 ast_mutex_unlock(&vms->lock);
02627 return -1;
02628 }
02629
02630 ast_mutex_unlock(&vms->lock);
02631 return 0;
02632 }
02633
02634 static void write_file(char *filename, char *buffer, unsigned long len)
02635 {
02636 FILE *output;
02637
02638 output = fopen (filename, "w");
02639 if (fwrite(buffer, len, 1, output) != 1) {
02640 if (ferror(output)) {
02641 ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno));
02642 }
02643 }
02644 fclose (output);
02645 }
02646
02647 static void update_messages_by_imapuser(const char *user, unsigned long number)
02648 {
02649 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
02650
02651 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
02652 return;
02653 }
02654
02655 ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
02656 vms->msgArray[vms->vmArrayIndex++] = number;
02657 }
02658
02659 void mm_searched(MAILSTREAM *stream, unsigned long number)
02660 {
02661 char *mailbox = stream->mailbox, buf[1024] = "", *user;
02662
02663 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
02664 return;
02665
02666 update_messages_by_imapuser(user, number);
02667 }
02668
02669 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
02670 {
02671 struct ast_variable *var;
02672 struct ast_vm_user *vmu;
02673
02674 vmu = ast_calloc(1, sizeof *vmu);
02675 if (!vmu)
02676 return NULL;
02677 ast_set_flag(vmu, VM_ALLOCED);
02678 populate_defaults(vmu);
02679
02680 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
02681 if (var) {
02682 apply_options_full(vmu, var);
02683 ast_variables_destroy(var);
02684 return vmu;
02685 } else {
02686 ast_free(vmu);
02687 return NULL;
02688 }
02689 }
02690
02691
02692
02693 void mm_exists(MAILSTREAM * stream, unsigned long number)
02694 {
02695
02696 ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
02697 if (number == 0) return;
02698 set_update(stream);
02699 }
02700
02701
02702 void mm_expunged(MAILSTREAM * stream, unsigned long number)
02703 {
02704
02705 ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
02706 if (number == 0) return;
02707 set_update(stream);
02708 }
02709
02710
02711 void mm_flags(MAILSTREAM * stream, unsigned long number)
02712 {
02713
02714 ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
02715 if (number == 0) return;
02716 set_update(stream);
02717 }
02718
02719
02720 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
02721 {
02722 ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string);
02723 mm_log (string, errflg);
02724 }
02725
02726
02727 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02728 {
02729 if (delimiter == '\0') {
02730 delimiter = delim;
02731 }
02732
02733 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02734 if (attributes & LATT_NOINFERIORS)
02735 ast_debug(5, "no inferiors\n");
02736 if (attributes & LATT_NOSELECT)
02737 ast_debug(5, "no select\n");
02738 if (attributes & LATT_MARKED)
02739 ast_debug(5, "marked\n");
02740 if (attributes & LATT_UNMARKED)
02741 ast_debug(5, "unmarked\n");
02742 }
02743
02744
02745 void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02746 {
02747 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02748 if (attributes & LATT_NOINFERIORS)
02749 ast_debug(5, "no inferiors\n");
02750 if (attributes & LATT_NOSELECT)
02751 ast_debug(5, "no select\n");
02752 if (attributes & LATT_MARKED)
02753 ast_debug(5, "marked\n");
02754 if (attributes & LATT_UNMARKED)
02755 ast_debug(5, "unmarked\n");
02756 }
02757
02758
02759 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
02760 {
02761 ast_log(AST_LOG_NOTICE, " Mailbox %s", mailbox);
02762 if (status->flags & SA_MESSAGES)
02763 ast_log(AST_LOG_NOTICE, ", %lu messages", status->messages);
02764 if (status->flags & SA_RECENT)
02765 ast_log(AST_LOG_NOTICE, ", %lu recent", status->recent);
02766 if (status->flags & SA_UNSEEN)
02767 ast_log(AST_LOG_NOTICE, ", %lu unseen", status->unseen);
02768 if (status->flags & SA_UIDVALIDITY)
02769 ast_log(AST_LOG_NOTICE, ", %lu UID validity", status->uidvalidity);
02770 if (status->flags & SA_UIDNEXT)
02771 ast_log(AST_LOG_NOTICE, ", %lu next UID", status->uidnext);
02772 ast_log(AST_LOG_NOTICE, "\n");
02773 }
02774
02775
02776 void mm_log(char *string, long errflg)
02777 {
02778 switch ((short) errflg) {
02779 case NIL:
02780 ast_debug(1, "IMAP Info: %s\n", string);
02781 break;
02782 case PARSE:
02783 case WARN:
02784 ast_log(AST_LOG_WARNING, "IMAP Warning: %s\n", string);
02785 break;
02786 case ERROR:
02787 ast_log(AST_LOG_ERROR, "IMAP Error: %s\n", string);
02788 break;
02789 }
02790 }
02791
02792
02793 void mm_dlog(char *string)
02794 {
02795 ast_log(AST_LOG_NOTICE, "%s\n", string);
02796 }
02797
02798
02799 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
02800 {
02801 struct ast_vm_user *vmu;
02802
02803 ast_debug(4, "Entering callback mm_login\n");
02804
02805 ast_copy_string(user, mb->user, MAILTMPLEN);
02806
02807
02808 if (!ast_strlen_zero(authpassword)) {
02809 ast_copy_string(pwd, authpassword, MAILTMPLEN);
02810 } else {
02811 AST_LIST_TRAVERSE(&users, vmu, list) {
02812 if (!strcasecmp(mb->user, vmu->imapuser)) {
02813 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02814 break;
02815 }
02816 }
02817 if (!vmu) {
02818 if ((vmu = find_user_realtime_imapuser(mb->user))) {
02819 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02820 free_user(vmu);
02821 }
02822 }
02823 }
02824 }
02825
02826
02827 void mm_critical(MAILSTREAM * stream)
02828 {
02829 }
02830
02831
02832 void mm_nocritical(MAILSTREAM * stream)
02833 {
02834 }
02835
02836
02837 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
02838 {
02839 kill (getpid (), SIGSTOP);
02840 return NIL;
02841 }
02842
02843
02844 void mm_fatal(char *string)
02845 {
02846 ast_log(AST_LOG_ERROR, "IMAP access FATAL error: %s\n", string);
02847 }
02848
02849
02850 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
02851 {
02852 struct vm_state *vms;
02853 char *mailbox = stream->mailbox, *user;
02854 char buf[1024] = "";
02855 unsigned long usage = 0, limit = 0;
02856
02857 while (pquota) {
02858 usage = pquota->usage;
02859 limit = pquota->limit;
02860 pquota = pquota->next;
02861 }
02862
02863 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)))) {
02864 ast_log(AST_LOG_ERROR, "No state found.\n");
02865 return;
02866 }
02867
02868 ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
02869
02870 vms->quota_usage = usage;
02871 vms->quota_limit = limit;
02872 }
02873
02874 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
02875 {
02876 char *start, *eol_pnt;
02877 int taglen;
02878
02879 if (ast_strlen_zero(header) || ast_strlen_zero(tag))
02880 return NULL;
02881
02882 taglen = strlen(tag) + 1;
02883 if (taglen < 1)
02884 return NULL;
02885
02886 if (!(start = strstr(header, tag)))
02887 return NULL;
02888
02889
02890 memset(buf, 0, len);
02891
02892 ast_copy_string(buf, start+taglen, len);
02893 if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n')))
02894 *eol_pnt = '\0';
02895 return buf;
02896 }
02897
02898 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
02899 {
02900 char *start, *quote, *eol_pnt;
02901
02902 if (ast_strlen_zero(mailbox))
02903 return NULL;
02904
02905 if (!(start = strstr(mailbox, "/user=")))
02906 return NULL;
02907
02908 ast_copy_string(buf, start+6, len);
02909
02910 if (!(quote = strchr(buf, '\"'))) {
02911 if (!(eol_pnt = strchr(buf, '/')))
02912 eol_pnt = strchr(buf,'}');
02913 *eol_pnt = '\0';
02914 return buf;
02915 } else {
02916 eol_pnt = strchr(buf+1,'\"');
02917 *eol_pnt = '\0';
02918 return buf+1;
02919 }
02920 }
02921
02922 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
02923 {
02924 struct vm_state *vms_p;
02925
02926 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02927 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
02928 return vms_p;
02929 }
02930 if (option_debug > 4)
02931 ast_log(AST_LOG_DEBUG, "Adding new vmstate for %s\n", vmu->imapuser);
02932 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
02933 return NULL;
02934 ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
02935 ast_copy_string(vms_p->imapfolder, vmu->imapfolder, sizeof(vms_p->imapfolder));
02936 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
02937 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
02938 vms_p->mailstream = NIL;
02939 vms_p->imapversion = vmu->imapversion;
02940 if (option_debug > 4)
02941 ast_log(AST_LOG_DEBUG, "Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
02942 vms_p->updated = 1;
02943
02944 ast_copy_string(vms_p->curbox, mbox(vmu, 0), sizeof(vms_p->curbox));
02945 init_vm_state(vms_p);
02946 vmstate_insert(vms_p);
02947 return vms_p;
02948 }
02949
02950 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
02951 {
02952 struct vmstate *vlist = NULL;
02953
02954 if (interactive) {
02955 struct vm_state *vms;
02956 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02957 vms = pthread_getspecific(ts_vmstate.key);
02958 return vms;
02959 }
02960
02961 AST_LIST_LOCK(&vmstates);
02962 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
02963 if (!vlist->vms) {
02964 ast_debug(3, "error: vms is NULL for %s\n", user);
02965 continue;
02966 }
02967 if (vlist->vms->imapversion != imapversion) {
02968 continue;
02969 }
02970 if (!vlist->vms->imapuser) {
02971 ast_debug(3, "error: imapuser is NULL for %s\n", user);
02972 continue;
02973 }
02974
02975 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
02976 AST_LIST_UNLOCK(&vmstates);
02977 return vlist->vms;
02978 }
02979 }
02980 AST_LIST_UNLOCK(&vmstates);
02981
02982 ast_debug(3, "%s not found in vmstates\n", user);
02983
02984 return NULL;
02985 }
02986
02987 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
02988 {
02989
02990 struct vmstate *vlist = NULL;
02991 const char *local_context = S_OR(context, "default");
02992
02993 if (interactive) {
02994 struct vm_state *vms;
02995 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02996 vms = pthread_getspecific(ts_vmstate.key);
02997 return vms;
02998 }
02999
03000 AST_LIST_LOCK(&vmstates);
03001 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03002 if (!vlist->vms) {
03003 ast_debug(3, "error: vms is NULL for %s\n", mailbox);
03004 continue;
03005 }
03006 if (vlist->vms->imapversion != imapversion) {
03007 continue;
03008 }
03009 if (!vlist->vms->username || !vlist->vms->context) {
03010 ast_debug(3, "error: username is NULL for %s\n", mailbox);
03011 continue;
03012 }
03013
03014 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);
03015
03016 if (!strcmp(vlist->vms->username, mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
03017 ast_debug(3, "Found it!\n");
03018 AST_LIST_UNLOCK(&vmstates);
03019 return vlist->vms;
03020 }
03021 }
03022 AST_LIST_UNLOCK(&vmstates);
03023
03024 ast_debug(3, "%s not found in vmstates\n", mailbox);
03025
03026 return NULL;
03027 }
03028
03029 static void vmstate_insert(struct vm_state *vms)
03030 {
03031 struct vmstate *v;
03032 struct vm_state *altvms;
03033
03034
03035
03036
03037 if (vms->interactive == 1) {
03038 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
03039 if (altvms) {
03040 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03041 vms->newmessages = altvms->newmessages;
03042 vms->oldmessages = altvms->oldmessages;
03043 vms->vmArrayIndex = altvms->vmArrayIndex;
03044 vms->lastmsg = altvms->lastmsg;
03045 vms->curmsg = altvms->curmsg;
03046
03047 vms->persist_vms = altvms;
03048
03049 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
03050 vms->mailstream = altvms->mailstream;
03051 #else
03052 vms->mailstream = NIL;
03053 #endif
03054 }
03055 return;
03056 }
03057
03058 if (!(v = ast_calloc(1, sizeof(*v))))
03059 return;
03060
03061 v->vms = vms;
03062
03063 ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03064
03065 AST_LIST_LOCK(&vmstates);
03066 AST_LIST_INSERT_TAIL(&vmstates, v, list);
03067 AST_LIST_UNLOCK(&vmstates);
03068 }
03069
03070 static void vmstate_delete(struct vm_state *vms)
03071 {
03072 struct vmstate *vc = NULL;
03073 struct vm_state *altvms = NULL;
03074
03075
03076
03077 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
03078 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03079 altvms->newmessages = vms->newmessages;
03080 altvms->oldmessages = vms->oldmessages;
03081 altvms->updated = 1;
03082 vms->mailstream = mail_close(vms->mailstream);
03083
03084
03085 return;
03086 }
03087
03088 ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03089
03090 AST_LIST_LOCK(&vmstates);
03091 AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
03092 if (vc->vms == vms) {
03093 AST_LIST_REMOVE_CURRENT(list);
03094 break;
03095 }
03096 }
03097 AST_LIST_TRAVERSE_SAFE_END
03098 AST_LIST_UNLOCK(&vmstates);
03099
03100 if (vc) {
03101 ast_mutex_destroy(&vc->vms->lock);
03102 ast_free(vc);
03103 }
03104 else
03105 ast_log(AST_LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03106 }
03107
03108 static void set_update(MAILSTREAM * stream)
03109 {
03110 struct vm_state *vms;
03111 char *mailbox = stream->mailbox, *user;
03112 char buf[1024] = "";
03113
03114 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
03115 if (user && option_debug > 2)
03116 ast_log(AST_LOG_WARNING, "User %s mailbox not found for update.\n", user);
03117 return;
03118 }
03119
03120 ast_debug(3, "User %s mailbox set for update.\n", user);
03121
03122 vms->updated = 1;
03123 }
03124
03125 static void init_vm_state(struct vm_state *vms)
03126 {
03127 int x;
03128 vms->vmArrayIndex = 0;
03129 for (x = 0; x < VMSTATE_MAX_MSG_ARRAY; x++) {
03130 vms->msgArray[x] = 0;
03131 }
03132 ast_mutex_init(&vms->lock);
03133 }
03134
03135 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro)
03136 {
03137 char *body_content;
03138 char *body_decoded;
03139 char *fn = is_intro ? vms->introfn : vms->fn;
03140 unsigned long len;
03141 unsigned long newlen;
03142 char filename[256];
03143
03144 if (!body || body == NIL)
03145 return -1;
03146
03147 ast_mutex_lock(&vms->lock);
03148 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
03149 ast_mutex_unlock(&vms->lock);
03150 if (body_content != NIL) {
03151 snprintf(filename, sizeof(filename), "%s.%s", fn, format);
03152
03153 body_decoded = rfc822_base64((unsigned char *) body_content, len, &newlen);
03154
03155 if (!newlen) {
03156 return -1;
03157 }
03158 write_file(filename, (char *) body_decoded, newlen);
03159 } else {
03160 ast_debug(5, "Body of message is NULL.\n");
03161 return -1;
03162 }
03163 return 0;
03164 }
03165
03166
03167
03168
03169
03170
03171
03172
03173 static void get_mailbox_delimiter(MAILSTREAM *stream) {
03174 char tmp[50];
03175 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
03176 mail_list(stream, tmp, "*");
03177 }
03178
03179
03180
03181
03182
03183
03184
03185
03186 static void check_quota(struct vm_state *vms, char *mailbox) {
03187 ast_mutex_lock(&vms->lock);
03188 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
03189 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox);
03190 if (vms && vms->mailstream != NULL) {
03191 imap_getquotaroot(vms->mailstream, mailbox);
03192 } else {
03193 ast_log(AST_LOG_WARNING, "Mailstream not available for mailbox: %s\n", mailbox);
03194 }
03195 ast_mutex_unlock(&vms->lock);
03196 }
03197
03198 #endif
03199
03200
03201
03202
03203
03204 static int vm_lock_path(const char *path)
03205 {
03206 switch (ast_lock_path(path)) {
03207 case AST_LOCK_TIMEOUT:
03208 return -1;
03209 default:
03210 return 0;
03211 }
03212 }
03213
03214
03215 #ifdef ODBC_STORAGE
03216 struct generic_prepare_struct {
03217 char *sql;
03218 int argc;
03219 char **argv;
03220 };
03221
03222 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
03223 {
03224 struct generic_prepare_struct *gps = data;
03225 int res, i;
03226 SQLHSTMT stmt;
03227
03228 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03229 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03230 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03231 return NULL;
03232 }
03233 res = SQLPrepare(stmt, (unsigned char *) gps->sql, SQL_NTS);
03234 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03235 ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
03236 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03237 return NULL;
03238 }
03239 for (i = 0; i < gps->argc; i++)
03240 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
03241
03242 return stmt;
03243 }
03244
03245
03246
03247
03248
03249
03250
03251
03252
03253
03254
03255
03256
03257
03258
03259 static int retrieve_file(char *dir, int msgnum)
03260 {
03261 int x = 0;
03262 int res;
03263 int fd = -1;
03264 size_t fdlen = 0;
03265 void *fdm = MAP_FAILED;
03266 SQLSMALLINT colcount = 0;
03267 SQLHSTMT stmt;
03268 char sql[PATH_MAX];
03269 char fmt[80]="";
03270 char *c;
03271 char coltitle[256];
03272 SQLSMALLINT collen;
03273 SQLSMALLINT datatype;
03274 SQLSMALLINT decimaldigits;
03275 SQLSMALLINT nullable;
03276 SQLULEN colsize;
03277 SQLLEN colsize2;
03278 FILE *f = NULL;
03279 char rowdata[80];
03280 char fn[PATH_MAX];
03281 char full_fn[PATH_MAX];
03282 char msgnums[80];
03283 char *argv[] = { dir, msgnums };
03284 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03285
03286 struct odbc_obj *obj;
03287 obj = ast_odbc_request_obj(odbc_database, 0);
03288 if (obj) {
03289 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03290 c = strchr(fmt, '|');
03291 if (c)
03292 *c = '\0';
03293 if (!strcasecmp(fmt, "wav49"))
03294 strcpy(fmt, "WAV");
03295 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03296 if (msgnum > -1)
03297 make_file(fn, sizeof(fn), dir, msgnum);
03298 else
03299 ast_copy_string(fn, dir, sizeof(fn));
03300
03301
03302 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03303
03304 if (!(f = fopen(full_fn, "w+"))) {
03305 ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
03306 goto yuck;
03307 }
03308
03309 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03310 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03311 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03312 if (!stmt) {
03313 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03314 ast_odbc_release_obj(obj);
03315 goto yuck;
03316 }
03317 res = SQLFetch(stmt);
03318 if (res == SQL_NO_DATA) {
03319 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03320 ast_odbc_release_obj(obj);
03321 goto yuck;
03322 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03323 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03324 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03325 ast_odbc_release_obj(obj);
03326 goto yuck;
03327 }
03328 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
03329 if (fd < 0) {
03330 ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
03331 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03332 ast_odbc_release_obj(obj);
03333 goto yuck;
03334 }
03335 res = SQLNumResultCols(stmt, &colcount);
03336 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03337 ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
03338 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03339 ast_odbc_release_obj(obj);
03340 goto yuck;
03341 }
03342 if (f)
03343 fprintf(f, "[message]\n");
03344 for (x = 0; x < colcount; x++) {
03345 rowdata[0] = '\0';
03346 collen = sizeof(coltitle);
03347 res = SQLDescribeCol(stmt, x + 1, (unsigned char *) coltitle, sizeof(coltitle), &collen,
03348 &datatype, &colsize, &decimaldigits, &nullable);
03349 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03350 ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
03351 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03352 ast_odbc_release_obj(obj);
03353 goto yuck;
03354 }
03355 if (!strcasecmp(coltitle, "recording")) {
03356 off_t offset;
03357 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
03358 fdlen = colsize2;
03359 if (fd > -1) {
03360 char tmp[1]="";
03361 lseek(fd, fdlen - 1, SEEK_SET);
03362 if (write(fd, tmp, 1) != 1) {
03363 close(fd);
03364 fd = -1;
03365 continue;
03366 }
03367
03368 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
03369 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
03370 ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
03371 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03372 ast_odbc_release_obj(obj);
03373 goto yuck;
03374 } else {
03375 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
03376 munmap(fdm, CHUNKSIZE);
03377 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03378 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03379 unlink(full_fn);
03380 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03381 ast_odbc_release_obj(obj);
03382 goto yuck;
03383 }
03384 }
03385 }
03386 if (truncate(full_fn, fdlen) < 0) {
03387 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
03388 }
03389 }
03390 } else {
03391 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03392 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03393 ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
03394 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03395 ast_odbc_release_obj(obj);
03396 goto yuck;
03397 }
03398 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
03399 fprintf(f, "%s=%s\n", coltitle, rowdata);
03400 }
03401 }
03402 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03403 ast_odbc_release_obj(obj);
03404 } else
03405 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03406 yuck:
03407 if (f)
03408 fclose(f);
03409 if (fd > -1)
03410 close(fd);
03411 return x - 1;
03412 }
03413
03414
03415
03416
03417
03418
03419
03420
03421
03422
03423
03424 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03425 {
03426 int x = 0;
03427 int res;
03428 SQLHSTMT stmt;
03429 char sql[PATH_MAX];
03430 char rowdata[20];
03431 char *argv[] = { dir };
03432 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03433
03434 struct odbc_obj *obj;
03435 obj = ast_odbc_request_obj(odbc_database, 0);
03436 if (obj) {
03437 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
03438 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03439 if (!stmt) {
03440 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03441 ast_odbc_release_obj(obj);
03442 goto yuck;
03443 }
03444 res = SQLFetch(stmt);
03445 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03446 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03447 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03448 ast_odbc_release_obj(obj);
03449 goto yuck;
03450 }
03451 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03452 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03453 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03454 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03455 ast_odbc_release_obj(obj);
03456 goto yuck;
03457 }
03458 if (sscanf(rowdata, "%30d", &x) != 1)
03459 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03460 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03461 ast_odbc_release_obj(obj);
03462 } else
03463 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03464 yuck:
03465 return x - 1;
03466 }
03467
03468
03469
03470
03471
03472
03473
03474
03475
03476
03477 static int message_exists(char *dir, int msgnum)
03478 {
03479 int x = 0;
03480 int res;
03481 SQLHSTMT stmt;
03482 char sql[PATH_MAX];
03483 char rowdata[20];
03484 char msgnums[20];
03485 char *argv[] = { dir, msgnums };
03486 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03487
03488 struct odbc_obj *obj;
03489 obj = ast_odbc_request_obj(odbc_database, 0);
03490 if (obj) {
03491 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03492 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03493 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03494 if (!stmt) {
03495 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03496 ast_odbc_release_obj(obj);
03497 goto yuck;
03498 }
03499 res = SQLFetch(stmt);
03500 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03501 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03502 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03503 ast_odbc_release_obj(obj);
03504 goto yuck;
03505 }
03506 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03507 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03508 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03509 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03510 ast_odbc_release_obj(obj);
03511 goto yuck;
03512 }
03513 if (sscanf(rowdata, "%30d", &x) != 1)
03514 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03515 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03516 ast_odbc_release_obj(obj);
03517 } else
03518 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03519 yuck:
03520 return x;
03521 }
03522
03523
03524
03525
03526
03527
03528
03529
03530
03531
03532
03533
03534
03535 static int count_messages(struct ast_vm_user *vmu, char *dir)
03536 {
03537 return last_message_index(vmu, dir) + 1;
03538 }
03539
03540
03541
03542
03543
03544
03545
03546
03547
03548
03549
03550 static void delete_file(const char *sdir, int smsg)
03551 {
03552 SQLHSTMT stmt;
03553 char sql[PATH_MAX];
03554 char msgnums[20];
03555 char *argv[] = { NULL, msgnums };
03556 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03557 struct odbc_obj *obj;
03558
03559 argv[0] = ast_strdupa(sdir);
03560
03561 obj = ast_odbc_request_obj(odbc_database, 0);
03562 if (obj) {
03563 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03564 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03565 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03566 if (!stmt)
03567 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03568 else
03569 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03570 ast_odbc_release_obj(obj);
03571 } else
03572 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03573 return;
03574 }
03575
03576
03577
03578
03579
03580
03581
03582
03583
03584
03585
03586
03587 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
03588 {
03589 SQLHSTMT stmt;
03590 char sql[512];
03591 char msgnums[20];
03592 char msgnumd[20];
03593 struct odbc_obj *obj;
03594 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
03595 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03596
03597 delete_file(ddir, dmsg);
03598 obj = ast_odbc_request_obj(odbc_database, 0);
03599 if (obj) {
03600 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03601 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03602 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);
03603 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03604 if (!stmt)
03605 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
03606 else
03607 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03608 ast_odbc_release_obj(obj);
03609 } else
03610 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03611 return;
03612 }
03613
03614 struct insert_data {
03615 char *sql;
03616 const char *dir;
03617 const char *msgnums;
03618 void *data;
03619 SQLLEN datalen;
03620 SQLLEN indlen;
03621 const char *context;
03622 const char *macrocontext;
03623 const char *callerid;
03624 const char *origtime;
03625 const char *duration;
03626 const char *mailboxuser;
03627 const char *mailboxcontext;
03628 const char *category;
03629 const char *flag;
03630 };
03631
03632 static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
03633 {
03634 struct insert_data *data = vdata;
03635 int res;
03636 SQLHSTMT stmt;
03637
03638 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03639 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03640 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03641 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03642 return NULL;
03643 }
03644
03645 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (void *) data->dir, 0, NULL);
03646 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (void *) data->msgnums, 0, NULL);
03647 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (void *) data->data, data->datalen, &data->indlen);
03648 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (void *) data->context, 0, NULL);
03649 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (void *) data->macrocontext, 0, NULL);
03650 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (void *) data->callerid, 0, NULL);
03651 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (void *) data->origtime, 0, NULL);
03652 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (void *) data->duration, 0, NULL);
03653 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (void *) data->mailboxuser, 0, NULL);
03654 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (void *) data->mailboxcontext, 0, NULL);
03655 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (void *) data->flag, 0, NULL);
03656 if (!ast_strlen_zero(data->category)) {
03657 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *) data->category, 0, NULL);
03658 }
03659 res = SQLExecDirect(stmt, (unsigned char *) data->sql, SQL_NTS);
03660 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03661 ast_log(AST_LOG_WARNING, "SQL Direct Execute failed!\n");
03662 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03663 return NULL;
03664 }
03665
03666 return stmt;
03667 }
03668
03669
03670
03671
03672
03673
03674
03675
03676
03677
03678
03679
03680
03681
03682 static int store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum)
03683 {
03684 int res = 0;
03685 int fd = -1;
03686 void *fdm = MAP_FAILED;
03687 size_t fdlen = -1;
03688 SQLHSTMT stmt;
03689 char sql[PATH_MAX];
03690 char msgnums[20];
03691 char fn[PATH_MAX];
03692 char full_fn[PATH_MAX];
03693 char fmt[80]="";
03694 char *c;
03695 struct ast_config *cfg = NULL;
03696 struct odbc_obj *obj;
03697 struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
03698 .context = "", .macrocontext = "", .callerid = "", .origtime = "", .duration = "", .category = "", .flag = "" };
03699 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03700
03701 delete_file(dir, msgnum);
03702 if (!(obj = ast_odbc_request_obj(odbc_database, 0))) {
03703 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03704 return -1;
03705 }
03706
03707 do {
03708 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03709 c = strchr(fmt, '|');
03710 if (c)
03711 *c = '\0';
03712 if (!strcasecmp(fmt, "wav49"))
03713 strcpy(fmt, "WAV");
03714 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03715 if (msgnum > -1)
03716 make_file(fn, sizeof(fn), dir, msgnum);
03717 else
03718 ast_copy_string(fn, dir, sizeof(fn));
03719 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03720 cfg = ast_config_load(full_fn, config_flags);
03721 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03722 fd = open(full_fn, O_RDWR);
03723 if (fd < 0) {
03724 ast_log(AST_LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
03725 res = -1;
03726 break;
03727 }
03728 if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
03729 if (!(idata.context = ast_variable_retrieve(cfg, "message", "context"))) {
03730 idata.context = "";
03731 }
03732 if (!(idata.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"))) {
03733 idata.macrocontext = "";
03734 }
03735 if (!(idata.callerid = ast_variable_retrieve(cfg, "message", "callerid"))) {
03736 idata.callerid = "";
03737 }
03738 if (!(idata.origtime = ast_variable_retrieve(cfg, "message", "origtime"))) {
03739 idata.origtime = "";
03740 }
03741 if (!(idata.duration = ast_variable_retrieve(cfg, "message", "duration"))) {
03742 idata.duration = "";
03743 }
03744 if (!(idata.category = ast_variable_retrieve(cfg, "message", "category"))) {
03745 idata.category = "";
03746 }
03747 if (!(idata.flag = ast_variable_retrieve(cfg, "message", "flag"))) {
03748 idata.flag = "";
03749 }
03750 }
03751 fdlen = lseek(fd, 0, SEEK_END);
03752 lseek(fd, 0, SEEK_SET);
03753 printf("Length is %zd\n", fdlen);
03754 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
03755 if (fdm == MAP_FAILED) {
03756 ast_log(AST_LOG_WARNING, "Memory map failed!\n");
03757 res = -1;
03758 break;
03759 }
03760 idata.data = fdm;
03761 idata.datalen = idata.indlen = fdlen;
03762
03763 if (!ast_strlen_zero(idata.category))
03764 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03765 else
03766 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag) VALUES (?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03767
03768 if ((stmt = ast_odbc_direct_execute(obj, insert_data_cb, &idata))) {
03769 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03770 } else {
03771 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03772 res = -1;
03773 }
03774 } while (0);
03775 if (obj) {
03776 ast_odbc_release_obj(obj);
03777 }
03778 if (cfg)
03779 ast_config_destroy(cfg);
03780 if (fdm != MAP_FAILED)
03781 munmap(fdm, fdlen);
03782 if (fd > -1)
03783 close(fd);
03784 return res;
03785 }
03786
03787
03788
03789
03790
03791
03792
03793
03794
03795
03796
03797
03798
03799
03800 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
03801 {
03802 SQLHSTMT stmt;
03803 char sql[PATH_MAX];
03804 char msgnums[20];
03805 char msgnumd[20];
03806 struct odbc_obj *obj;
03807 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
03808 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03809
03810 delete_file(ddir, dmsg);
03811 obj = ast_odbc_request_obj(odbc_database, 0);
03812 if (obj) {
03813 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03814 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03815 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table);
03816 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03817 if (!stmt)
03818 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03819 else
03820 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03821 ast_odbc_release_obj(obj);
03822 } else
03823 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03824 return;
03825 }
03826
03827
03828
03829
03830
03831
03832
03833
03834
03835
03836
03837
03838 static int remove_file(char *dir, int msgnum)
03839 {
03840 char fn[PATH_MAX];
03841 char full_fn[PATH_MAX];
03842 char msgnums[80];
03843
03844 if (msgnum > -1) {
03845 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03846 make_file(fn, sizeof(fn), dir, msgnum);
03847 } else
03848 ast_copy_string(fn, dir, sizeof(fn));
03849 ast_filedelete(fn, NULL);
03850 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03851 unlink(full_fn);
03852 return 0;
03853 }
03854 #else
03855 #ifndef IMAP_STORAGE
03856
03857
03858
03859
03860
03861
03862
03863
03864
03865 static int count_messages(struct ast_vm_user *vmu, char *dir)
03866 {
03867
03868 int vmcount = 0;
03869 DIR *vmdir = NULL;
03870 struct dirent *vment = NULL;
03871
03872 if (vm_lock_path(dir))
03873 return ERROR_LOCK_PATH;
03874
03875 if ((vmdir = opendir(dir))) {
03876 while ((vment = readdir(vmdir))) {
03877 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
03878 vmcount++;
03879 }
03880 }
03881 closedir(vmdir);
03882 }
03883 ast_unlock_path(dir);
03884
03885 return vmcount;
03886 }
03887
03888
03889
03890
03891
03892
03893
03894
03895 static void rename_file(char *sfn, char *dfn)
03896 {
03897 char stxt[PATH_MAX];
03898 char dtxt[PATH_MAX];
03899 ast_filerename(sfn, dfn, NULL);
03900 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
03901 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
03902 if (ast_check_realtime("voicemail_data")) {
03903 ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL);
03904 }
03905 rename(stxt, dtxt);
03906 }
03907
03908
03909
03910
03911
03912
03913
03914
03915
03916
03917
03918
03919 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03920 {
03921 int x;
03922 unsigned char map[MAXMSGLIMIT] = "";
03923 DIR *msgdir;
03924 struct dirent *msgdirent;
03925 int msgdirint;
03926
03927
03928
03929
03930
03931 if (!(msgdir = opendir(dir))) {
03932 return -1;
03933 }
03934
03935 while ((msgdirent = readdir(msgdir))) {
03936 if (sscanf(msgdirent->d_name, "msg%30d", &msgdirint) == 1 && msgdirint < MAXMSGLIMIT)
03937 map[msgdirint] = 1;
03938 }
03939 closedir(msgdir);
03940
03941 for (x = 0; x < vmu->maxmsg; x++) {
03942 if (map[x] == 0)
03943 break;
03944 }
03945
03946 return x - 1;
03947 }
03948
03949 #endif
03950 #endif
03951 #ifndef IMAP_STORAGE
03952
03953
03954
03955
03956
03957
03958
03959
03960
03961
03962 static int copy(char *infile, char *outfile)
03963 {
03964 int ifd;
03965 int ofd;
03966 int res;
03967 int len;
03968 char buf[4096];
03969
03970 #ifdef HARDLINK_WHEN_POSSIBLE
03971
03972 if (link(infile, outfile)) {
03973 #endif
03974 if ((ifd = open(infile, O_RDONLY)) < 0) {
03975 ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
03976 return -1;
03977 }
03978 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
03979 ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
03980 close(ifd);
03981 return -1;
03982 }
03983 do {
03984 len = read(ifd, buf, sizeof(buf));
03985 if (len < 0) {
03986 ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
03987 close(ifd);
03988 close(ofd);
03989 unlink(outfile);
03990 }
03991 if (len) {
03992 res = write(ofd, buf, len);
03993 if (errno == ENOMEM || errno == ENOSPC || res != len) {
03994 ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
03995 close(ifd);
03996 close(ofd);
03997 unlink(outfile);
03998 }
03999 }
04000 } while (len);
04001 close(ifd);
04002 close(ofd);
04003 return 0;
04004 #ifdef HARDLINK_WHEN_POSSIBLE
04005 } else {
04006
04007 return 0;
04008 }
04009 #endif
04010 }
04011
04012
04013
04014
04015
04016
04017
04018
04019
04020
04021 static void copy_plain_file(char *frompath, char *topath)
04022 {
04023 char frompath2[PATH_MAX], topath2[PATH_MAX];
04024 struct ast_variable *tmp,*var = NULL;
04025 const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
04026 ast_filecopy(frompath, topath, NULL);
04027 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
04028 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
04029 if (ast_check_realtime("voicemail_data")) {
04030 var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
04031
04032 for (tmp = var; tmp; tmp = tmp->next) {
04033 if (!strcasecmp(tmp->name, "origmailbox")) {
04034 origmailbox = tmp->value;
04035 } else if (!strcasecmp(tmp->name, "context")) {
04036 context = tmp->value;
04037 } else if (!strcasecmp(tmp->name, "macrocontext")) {
04038 macrocontext = tmp->value;
04039 } else if (!strcasecmp(tmp->name, "exten")) {
04040 exten = tmp->value;
04041 } else if (!strcasecmp(tmp->name, "priority")) {
04042 priority = tmp->value;
04043 } else if (!strcasecmp(tmp->name, "callerchan")) {
04044 callerchan = tmp->value;
04045 } else if (!strcasecmp(tmp->name, "callerid")) {
04046 callerid = tmp->value;
04047 } else if (!strcasecmp(tmp->name, "origdate")) {
04048 origdate = tmp->value;
04049 } else if (!strcasecmp(tmp->name, "origtime")) {
04050 origtime = tmp->value;
04051 } else if (!strcasecmp(tmp->name, "category")) {
04052 category = tmp->value;
04053 } else if (!strcasecmp(tmp->name, "duration")) {
04054 duration = tmp->value;
04055 }
04056 }
04057 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);
04058 }
04059 copy(frompath2, topath2);
04060 ast_variables_destroy(var);
04061 }
04062 #endif
04063
04064
04065
04066
04067
04068
04069
04070
04071
04072 static int vm_delete(char *file)
04073 {
04074 char *txt;
04075 int txtsize = 0;
04076
04077 txtsize = (strlen(file) + 5)*sizeof(char);
04078 txt = alloca(txtsize);
04079
04080
04081
04082 if (ast_check_realtime("voicemail_data")) {
04083 ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
04084 }
04085 snprintf(txt, txtsize, "%s.txt", file);
04086 unlink(txt);
04087 return ast_filedelete(file, NULL);
04088 }
04089
04090
04091
04092
04093 static int inbuf(struct baseio *bio, FILE *fi)
04094 {
04095 int l;
04096
04097 if (bio->ateof)
04098 return 0;
04099
04100 if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) <= 0) {
04101 if (ferror(fi))
04102 return -1;
04103
04104 bio->ateof = 1;
04105 return 0;
04106 }
04107
04108 bio->iolen = l;
04109 bio->iocp = 0;
04110
04111 return 1;
04112 }
04113
04114
04115
04116
04117 static int inchar(struct baseio *bio, FILE *fi)
04118 {
04119 if (bio->iocp>=bio->iolen) {
04120 if (!inbuf(bio, fi))
04121 return EOF;
04122 }
04123
04124 return bio->iobuf[bio->iocp++];
04125 }
04126
04127
04128
04129
04130 static int ochar(struct baseio *bio, int c, FILE *so)
04131 {
04132 if (bio->linelength >= BASELINELEN) {
04133 if (fputs(ENDL, so) == EOF) {
04134 return -1;
04135 }
04136
04137 bio->linelength = 0;
04138 }
04139
04140 if (putc(((unsigned char) c), so) == EOF) {
04141 return -1;
04142 }
04143
04144 bio->linelength++;
04145
04146 return 1;
04147 }
04148
04149
04150
04151
04152
04153
04154
04155
04156
04157
04158 static int base_encode(char *filename, FILE *so)
04159 {
04160 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
04161 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
04162 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
04163 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
04164 int i, hiteof = 0;
04165 FILE *fi;
04166 struct baseio bio;
04167
04168 memset(&bio, 0, sizeof(bio));
04169 bio.iocp = BASEMAXINLINE;
04170
04171 if (!(fi = fopen(filename, "rb"))) {
04172 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
04173 return -1;
04174 }
04175
04176 while (!hiteof){
04177 unsigned char igroup[3], ogroup[4];
04178 int c, n;
04179
04180 memset(igroup, 0, sizeof(igroup));
04181
04182 for (n = 0; n < 3; n++) {
04183 if ((c = inchar(&bio, fi)) == EOF) {
04184 hiteof = 1;
04185 break;
04186 }
04187
04188 igroup[n] = (unsigned char) c;
04189 }
04190
04191 if (n > 0) {
04192 ogroup[0]= dtable[igroup[0] >> 2];
04193 ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
04194 ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
04195 ogroup[3]= dtable[igroup[2] & 0x3F];
04196
04197 if (n < 3) {
04198 ogroup[3] = '=';
04199
04200 if (n < 2)
04201 ogroup[2] = '=';
04202 }
04203
04204 for (i = 0; i < 4; i++)
04205 ochar(&bio, ogroup[i], so);
04206 }
04207 }
04208
04209 fclose(fi);
04210
04211 if (fputs(ENDL, so) == EOF) {
04212 return 0;
04213 }
04214
04215 return 1;
04216 }
04217
04218 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)
04219 {
04220 char callerid[256];
04221 char num[12];
04222 char fromdir[256], fromfile[256];
04223 struct ast_config *msg_cfg;
04224 const char *origcallerid, *origtime;
04225 char origcidname[80], origcidnum[80], origdate[80];
04226 int inttime;
04227 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04228
04229
04230 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
04231 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
04232 snprintf(num, sizeof(num), "%d", msgnum);
04233 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", num);
04234 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
04235 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
04236 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
04237 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
04238 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
04239 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
04240 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
04241 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
04242 pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
04243
04244
04245 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04246 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
04247 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04248 strcat(fromfile, ".txt");
04249 }
04250 if (!(msg_cfg = ast_config_load(fromfile, config_flags))) {
04251 if (option_debug > 0) {
04252 ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile);
04253 }
04254 return;
04255 }
04256
04257 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04258 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
04259 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
04260 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
04261 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
04262 }
04263
04264 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
04265 struct timeval tv = { inttime, };
04266 struct ast_tm tm;
04267 ast_localtime(&tv, &tm, NULL);
04268 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04269 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
04270 }
04271 ast_config_destroy(msg_cfg);
04272 }
04273
04274
04275
04276
04277
04278
04279
04280
04281
04282 static const char *ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
04283 {
04284 const char *ptr;
04285
04286
04287 ast_str_set(buf, maxlen, "\"");
04288 for (ptr = from; *ptr; ptr++) {
04289 if (*ptr == '"' || *ptr == '\\') {
04290 ast_str_append(buf, maxlen, "\\%c", *ptr);
04291 } else {
04292 ast_str_append(buf, maxlen, "%c", *ptr);
04293 }
04294 }
04295 ast_str_append(buf, maxlen, "\"");
04296
04297 return ast_str_buffer(*buf);
04298 }
04299
04300
04301
04302
04303
04304 static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
04305 {
04306 const struct vm_zone *z = NULL;
04307 struct timeval t = ast_tvnow();
04308
04309
04310 if (!ast_strlen_zero(vmu->zonetag)) {
04311
04312 AST_LIST_LOCK(&zones);
04313 AST_LIST_TRAVERSE(&zones, z, list) {
04314 if (!strcmp(z->name, vmu->zonetag))
04315 break;
04316 }
04317 AST_LIST_UNLOCK(&zones);
04318 }
04319 ast_localtime(&t, tm, z ? z->timezone : NULL);
04320 return tm;
04321 }
04322
04323
04324
04325
04326
04327 static int check_mime(const char *str)
04328 {
04329 for (; *str; str++) {
04330 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
04331 return 1;
04332 }
04333 }
04334 return 0;
04335 }
04336
04337
04338
04339
04340
04341
04342
04343
04344
04345
04346
04347
04348
04349
04350
04351
04352
04353
04354 static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
04355 {
04356 struct ast_str *tmp = ast_str_alloca(80);
04357 int first_section = 1;
04358
04359 ast_str_reset(*end);
04360 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04361 for (; *start; start++) {
04362 int need_encoding = 0;
04363 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
04364 need_encoding = 1;
04365 }
04366 if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
04367 (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
04368 (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
04369 (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
04370
04371 ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
04372 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04373 first_section = 0;
04374 }
04375 if (need_encoding && *start == ' ') {
04376 ast_str_append(&tmp, -1, "_");
04377 } else if (need_encoding) {
04378 ast_str_append(&tmp, -1, "=%hhX", *start);
04379 } else {
04380 ast_str_append(&tmp, -1, "%c", *start);
04381 }
04382 }
04383 ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
04384 return ast_str_buffer(*end);
04385 }
04386
04387
04388
04389
04390
04391
04392
04393
04394
04395
04396
04397
04398
04399
04400
04401
04402
04403
04404
04405
04406
04407
04408
04409
04410 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)
04411 {
04412 char date[256];
04413 char host[MAXHOSTNAMELEN] = "";
04414 char who[256];
04415 char bound[256];
04416 char dur[256];
04417 struct ast_tm tm;
04418 char enc_cidnum[256] = "", enc_cidname[256] = "";
04419 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04420 char *greeting_attachment;
04421 char filename[256];
04422
04423 if (!str1 || !str2) {
04424 ast_free(str1);
04425 ast_free(str2);
04426 return;
04427 }
04428
04429 if (cidnum) {
04430 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04431 }
04432 if (cidname) {
04433 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04434 }
04435 gethostname(host, sizeof(host) - 1);
04436
04437 if (strchr(srcemail, '@')) {
04438 ast_copy_string(who, srcemail, sizeof(who));
04439 } else {
04440 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04441 }
04442
04443 greeting_attachment = strrchr(ast_strdupa(attach), '/');
04444 if (greeting_attachment) {
04445 *greeting_attachment++ = '\0';
04446 }
04447
04448 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04449 ast_strftime_locale(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04450 fprintf(p, "Date: %s" ENDL, date);
04451
04452
04453 ast_strftime_locale(date, sizeof(date), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04454
04455 if (!ast_strlen_zero(fromstring)) {
04456 struct ast_channel *ast;
04457 if ((ast = ast_dummy_channel_alloc())) {
04458 char *ptr;
04459 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04460 ast_str_substitute_variables(&str1, 0, ast, fromstring);
04461
04462 if (check_mime(ast_str_buffer(str1))) {
04463 int first_line = 1;
04464 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04465 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04466 *ptr = '\0';
04467 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04468 first_line = 0;
04469
04470 ast_str_set(&str2, 0, "%s", ptr + 1);
04471 }
04472 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04473 } else {
04474 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04475 }
04476 ast = ast_channel_release(ast);
04477 } else {
04478 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04479 }
04480 } else {
04481 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04482 }
04483
04484 if (check_mime(vmu->fullname)) {
04485 int first_line = 1;
04486 char *ptr;
04487 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(vmu->email) + 3);
04488 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04489 *ptr = '\0';
04490 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04491 first_line = 0;
04492
04493 ast_str_set(&str2, 0, "%s", ptr + 1);
04494 }
04495 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), vmu->email);
04496 } else {
04497 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), vmu->email);
04498 }
04499
04500 if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) {
04501 char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject;
04502 struct ast_channel *ast;
04503 if ((ast = ast_dummy_channel_alloc())) {
04504 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04505 ast_str_substitute_variables(&str1, 0, ast, e_subj);
04506 if (check_mime(ast_str_buffer(str1))) {
04507 int first_line = 1;
04508 char *ptr;
04509 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04510 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04511 *ptr = '\0';
04512 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04513 first_line = 0;
04514
04515 ast_str_set(&str2, 0, "%s", ptr + 1);
04516 }
04517 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04518 } else {
04519 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04520 }
04521 ast = ast_channel_release(ast);
04522 } else {
04523 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04524 }
04525 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
04526 if (ast_strlen_zero(flag)) {
04527 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04528 } else {
04529 fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04530 }
04531 } else {
04532 if (ast_strlen_zero(flag)) {
04533 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04534 } else {
04535 fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04536 }
04537 }
04538
04539 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1,
04540 (unsigned int) ast_random(), mailbox, (int) getpid(), host);
04541 if (imap) {
04542
04543 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
04544
04545 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
04546 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
04547 #ifdef IMAP_STORAGE
04548 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
04549 #else
04550 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
04551 #endif
04552
04553 fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
04554 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
04555 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
04556 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
04557 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
04558 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
04559 if (!ast_strlen_zero(category)) {
04560 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
04561 } else {
04562 fprintf(p, "X-Asterisk-VM-Category: " ENDL);
04563 }
04564 fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
04565 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
04566 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long) time(NULL));
04567 }
04568 if (!ast_strlen_zero(cidnum)) {
04569 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
04570 }
04571 if (!ast_strlen_zero(cidname)) {
04572 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
04573 }
04574 fprintf(p, "MIME-Version: 1.0" ENDL);
04575 if (attach_user_voicemail) {
04576
04577 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox,
04578 (int) getpid(), (unsigned int) ast_random());
04579
04580 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
04581 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
04582 fprintf(p, "--%s" ENDL, bound);
04583 }
04584 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
04585 if (emailbody || vmu->emailbody) {
04586 char* e_body = vmu->emailbody ? vmu->emailbody : emailbody;
04587 struct ast_channel *ast;
04588 if ((ast = ast_dummy_channel_alloc())) {
04589 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04590 ast_str_substitute_variables(&str1, 0, ast, e_body);
04591 #ifdef IMAP_STORAGE
04592 {
04593
04594 char *line = ast_str_buffer(str1), *next;
04595 do {
04596
04597 if ((next = strchr(line, '\n'))) {
04598 *next++ = '\0';
04599 }
04600 fprintf(p, "%s" ENDL, line);
04601 line = next;
04602 } while (!ast_strlen_zero(line));
04603 }
04604 #else
04605 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04606 #endif
04607 ast = ast_channel_release(ast);
04608 } else {
04609 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04610 }
04611 } else if (msgnum > -1) {
04612 if (strcmp(vmu->mailbox, mailbox)) {
04613
04614 struct ast_config *msg_cfg;
04615 const char *v;
04616 int inttime;
04617 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
04618 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04619
04620 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04621 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
04622 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04623 strcat(fromfile, ".txt");
04624 }
04625 if ((msg_cfg = ast_config_load(fromfile, config_flags))) {
04626 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04627 ast_copy_string(origcallerid, v, sizeof(origcallerid));
04628 }
04629
04630
04631
04632 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
04633 struct timeval tv = { inttime, };
04634 struct ast_tm tm;
04635 ast_localtime(&tv, &tm, NULL);
04636 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04637 }
04638 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
04639 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
04640 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
04641 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
04642 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
04643 date, origcallerid, origdate);
04644 ast_config_destroy(msg_cfg);
04645 } else {
04646 goto plain_message;
04647 }
04648 } else {
04649 plain_message:
04650 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
04651 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
04652 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
04653 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
04654 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
04655 }
04656 } else {
04657 fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
04658 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
04659 }
04660
04661 if (imap || attach_user_voicemail) {
04662 if (!ast_strlen_zero(attach2)) {
04663 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04664 ast_debug(5, "creating second attachment filename %s\n", filename);
04665 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
04666 snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
04667 ast_debug(5, "creating attachment filename %s\n", filename);
04668 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04669 } else {
04670 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04671 ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
04672 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04673 }
04674 }
04675 ast_free(str1);
04676 ast_free(str2);
04677 }
04678
04679 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)
04680 {
04681 char tmpdir[256], newtmp[256];
04682 char fname[256];
04683 char tmpcmd[256];
04684 int tmpfd = -1;
04685
04686
04687 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
04688
04689 if (vmu->volgain < -.001 || vmu->volgain > .001) {
04690 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
04691 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
04692 tmpfd = mkstemp(newtmp);
04693 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
04694 ast_debug(3, "newtmp: %s\n", newtmp);
04695 if (tmpfd > -1) {
04696 int soxstatus;
04697 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
04698 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
04699 attach = newtmp;
04700 ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
04701 } else {
04702 ast_log(LOG_WARNING, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
04703 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
04704 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
04705 }
04706 }
04707 }
04708 fprintf(p, "--%s" ENDL, bound);
04709 if (msgnum > -1)
04710 fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
04711 else
04712 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
04713 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
04714 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
04715 if (msgnum > -1)
04716 fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
04717 else
04718 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
04719 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
04720 base_encode(fname, p);
04721 if (last)
04722 fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
04723 if (tmpfd > -1) {
04724 unlink(fname);
04725 close(tmpfd);
04726 unlink(newtmp);
04727 }
04728 return 0;
04729 }
04730
04731 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)
04732 {
04733 FILE *p = NULL;
04734 char tmp[80] = "/tmp/astmail-XXXXXX";
04735 char tmp2[256];
04736 char *stringp;
04737
04738 if (vmu && ast_strlen_zero(vmu->email)) {
04739 ast_log(AST_LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
04740 return(0);
04741 }
04742
04743
04744 format = ast_strdupa(format);
04745 stringp = format;
04746 strsep(&stringp, "|");
04747
04748 if (!strcmp(format, "wav49"))
04749 format = "WAV";
04750 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));
04751
04752
04753 if ((p = vm_mkftemp(tmp)) == NULL) {
04754 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04755 return -1;
04756 } else {
04757 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag);
04758 fclose(p);
04759 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04760 ast_safe_system(tmp2);
04761 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
04762 }
04763 return 0;
04764 }
04765
04766 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)
04767 {
04768 char enc_cidnum[256], enc_cidname[256];
04769 char date[256];
04770 char host[MAXHOSTNAMELEN] = "";
04771 char who[256];
04772 char dur[PATH_MAX];
04773 char tmp[80] = "/tmp/astmail-XXXXXX";
04774 char tmp2[PATH_MAX];
04775 struct ast_tm tm;
04776 FILE *p;
04777 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04778
04779 if (!str1 || !str2) {
04780 ast_free(str1);
04781 ast_free(str2);
04782 return -1;
04783 }
04784
04785 if (cidnum) {
04786 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04787 }
04788 if (cidname) {
04789 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04790 }
04791
04792 if ((p = vm_mkftemp(tmp)) == NULL) {
04793 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04794 ast_free(str1);
04795 ast_free(str2);
04796 return -1;
04797 }
04798 gethostname(host, sizeof(host)-1);
04799 if (strchr(srcemail, '@')) {
04800 ast_copy_string(who, srcemail, sizeof(who));
04801 } else {
04802 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04803 }
04804 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04805 ast_strftime_locale(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04806 fprintf(p, "Date: %s\n", date);
04807
04808
04809 ast_strftime_locale(date, sizeof(date), pagerdateformat, vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04810
04811 if (!ast_strlen_zero(pagerfromstring)) {
04812 struct ast_channel *ast;
04813 if ((ast = ast_dummy_channel_alloc())) {
04814 char *ptr;
04815 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04816 ast_str_substitute_variables(&str1, 0, ast, pagerfromstring);
04817
04818 if (check_mime(ast_str_buffer(str1))) {
04819 int first_line = 1;
04820 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04821 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04822 *ptr = '\0';
04823 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04824 first_line = 0;
04825
04826 ast_str_set(&str2, 0, "%s", ptr + 1);
04827 }
04828 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04829 } else {
04830 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04831 }
04832 ast = ast_channel_release(ast);
04833 } else {
04834 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04835 }
04836 } else {
04837 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04838 }
04839
04840 if (check_mime(vmu->fullname)) {
04841 int first_line = 1;
04842 char *ptr;
04843 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(pager) + 3);
04844 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04845 *ptr = '\0';
04846 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04847 first_line = 0;
04848
04849 ast_str_set(&str2, 0, "%s", ptr + 1);
04850 }
04851 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), pager);
04852 } else {
04853 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), pager);
04854 }
04855
04856 if (!ast_strlen_zero(pagersubject)) {
04857 struct ast_channel *ast;
04858 if ((ast = ast_dummy_channel_alloc())) {
04859 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04860 ast_str_substitute_variables(&str1, 0, ast, pagersubject);
04861 if (check_mime(ast_str_buffer(str1))) {
04862 int first_line = 1;
04863 char *ptr;
04864 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04865 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04866 *ptr = '\0';
04867 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04868 first_line = 0;
04869
04870 ast_str_set(&str2, 0, "%s", ptr + 1);
04871 }
04872 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04873 } else {
04874 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04875 }
04876 ast = ast_channel_release(ast);
04877 } else {
04878 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04879 }
04880 } else {
04881 if (ast_strlen_zero(flag)) {
04882 fprintf(p, "Subject: New VM\n\n");
04883 } else {
04884 fprintf(p, "Subject: New %s VM\n\n", flag);
04885 }
04886 }
04887
04888 if (pagerbody) {
04889 struct ast_channel *ast;
04890 if ((ast = ast_dummy_channel_alloc())) {
04891 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04892 ast_str_substitute_variables(&str1, 0, ast, pagerbody);
04893 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04894 ast = ast_channel_release(ast);
04895 } else {
04896 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04897 }
04898 } else {
04899 fprintf(p, "New %s long %s msg in box %s\n"
04900 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
04901 }
04902
04903 fclose(p);
04904 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04905 ast_safe_system(tmp2);
04906 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
04907 ast_free(str1);
04908 ast_free(str2);
04909 return 0;
04910 }
04911
04912
04913
04914
04915
04916
04917
04918
04919
04920
04921 static int get_date(char *s, int len)
04922 {
04923 struct ast_tm tm;
04924 struct timeval t = ast_tvnow();
04925
04926 ast_localtime(&t, &tm, "UTC");
04927
04928 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
04929 }
04930
04931 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
04932 {
04933 int res;
04934 char fn[PATH_MAX];
04935 char dest[PATH_MAX];
04936
04937 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
04938
04939 if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
04940 ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
04941 return -1;
04942 }
04943
04944 RETRIEVE(fn, -1, ext, context);
04945 if (ast_fileexists(fn, NULL, NULL) > 0) {
04946 res = ast_stream_and_wait(chan, fn, ecodes);
04947 if (res) {
04948 DISPOSE(fn, -1);
04949 return res;
04950 }
04951 } else {
04952
04953 DISPOSE(fn, -1);
04954 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
04955 if (res)
04956 return res;
04957 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
04958 if (res)
04959 return res;
04960 }
04961 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
04962 return res;
04963 }
04964
04965 static void free_zone(struct vm_zone *z)
04966 {
04967 ast_free(z);
04968 }
04969
04970 #ifdef ODBC_STORAGE
04971 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
04972 {
04973 int x = -1;
04974 int res;
04975 SQLHSTMT stmt = NULL;
04976 char sql[PATH_MAX];
04977 char rowdata[20];
04978 char tmp[PATH_MAX] = "";
04979 struct odbc_obj *obj = NULL;
04980 char *context;
04981 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
04982
04983 if (newmsgs)
04984 *newmsgs = 0;
04985 if (oldmsgs)
04986 *oldmsgs = 0;
04987 if (urgentmsgs)
04988 *urgentmsgs = 0;
04989
04990
04991 if (ast_strlen_zero(mailbox))
04992 return 0;
04993
04994 ast_copy_string(tmp, mailbox, sizeof(tmp));
04995
04996 if (strchr(mailbox, ' ') || strchr(mailbox, ',')) {
04997 int u, n, o;
04998 char *next, *remaining = tmp;
04999 while ((next = strsep(&remaining, " ,"))) {
05000 if (inboxcount2(next, urgentmsgs ? &u : NULL, &n, &o)) {
05001 return -1;
05002 }
05003 if (urgentmsgs) {
05004 *urgentmsgs += u;
05005 }
05006 if (newmsgs) {
05007 *newmsgs += n;
05008 }
05009 if (oldmsgs) {
05010 *oldmsgs += o;
05011 }
05012 }
05013 return 0;
05014 }
05015
05016 context = strchr(tmp, '@');
05017 if (context) {
05018 *context = '\0';
05019 context++;
05020 } else
05021 context = "default";
05022
05023 if ((obj = ast_odbc_request_obj(odbc_database, 0))) {
05024 do {
05025 if (newmsgs) {
05026 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
05027 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05028 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05029 break;
05030 }
05031 res = SQLFetch(stmt);
05032 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05033 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05034 break;
05035 }
05036 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05037 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05038 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05039 break;
05040 }
05041 *newmsgs = atoi(rowdata);
05042 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05043 }
05044
05045 if (oldmsgs) {
05046 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
05047 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05048 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05049 break;
05050 }
05051 res = SQLFetch(stmt);
05052 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05053 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05054 break;
05055 }
05056 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05057 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05058 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05059 break;
05060 }
05061 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
05062 *oldmsgs = atoi(rowdata);
05063 }
05064
05065 if (urgentmsgs) {
05066 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent");
05067 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05068 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05069 break;
05070 }
05071 res = SQLFetch(stmt);
05072 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05073 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05074 break;
05075 }
05076 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05077 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05078 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05079 break;
05080 }
05081 *urgentmsgs = atoi(rowdata);
05082 }
05083
05084 x = 0;
05085 } while (0);
05086 } else {
05087 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05088 }
05089
05090 if (stmt) {
05091 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05092 }
05093 if (obj) {
05094 ast_odbc_release_obj(obj);
05095 }
05096
05097 return x;
05098 }
05099
05100
05101
05102
05103
05104
05105
05106
05107
05108
05109 static int messagecount(const char *context, const char *mailbox, const char *folder)
05110 {
05111 struct odbc_obj *obj = NULL;
05112 int nummsgs = 0;
05113 int res;
05114 SQLHSTMT stmt = NULL;
05115 char sql[PATH_MAX];
05116 char rowdata[20];
05117 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05118 if (!folder)
05119 folder = "INBOX";
05120
05121 if (ast_strlen_zero(mailbox))
05122 return 0;
05123
05124 obj = ast_odbc_request_obj(odbc_database, 0);
05125 if (obj) {
05126 if (!strcmp(folder, "INBOX")) {
05127 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);
05128 } else {
05129 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
05130 }
05131 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
05132 if (!stmt) {
05133 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05134 goto yuck;
05135 }
05136 res = SQLFetch(stmt);
05137 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05138 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05139 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05140 goto yuck;
05141 }
05142 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05143 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05144 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05145 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05146 goto yuck;
05147 }
05148 nummsgs = atoi(rowdata);
05149 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05150 } else
05151 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05152
05153 yuck:
05154 if (obj)
05155 ast_odbc_release_obj(obj);
05156 return nummsgs;
05157 }
05158
05159
05160
05161
05162
05163
05164
05165
05166
05167 static int has_voicemail(const char *mailbox, const char *folder)
05168 {
05169 char tmp[256], *tmp2 = tmp, *box, *context;
05170 ast_copy_string(tmp, mailbox, sizeof(tmp));
05171 while ((context = box = strsep(&tmp2, ",&"))) {
05172 strsep(&context, "@");
05173 if (ast_strlen_zero(context))
05174 context = "default";
05175 if (messagecount(context, box, folder))
05176 return 1;
05177 }
05178 return 0;
05179 }
05180 #endif
05181 #ifndef IMAP_STORAGE
05182
05183
05184
05185
05186
05187
05188
05189
05190
05191
05192
05193
05194
05195
05196
05197
05198 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)
05199 {
05200 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
05201 const char *frombox = mbox(vmu, imbox);
05202 int recipmsgnum;
05203 int res = 0;
05204
05205 ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
05206
05207 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05208 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, "Urgent");
05209 } else {
05210 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
05211 }
05212
05213 if (!dir)
05214 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
05215 else
05216 ast_copy_string(fromdir, dir, sizeof(fromdir));
05217
05218 make_file(frompath, sizeof(frompath), fromdir, msgnum);
05219 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
05220
05221 if (vm_lock_path(todir))
05222 return ERROR_LOCK_PATH;
05223
05224 recipmsgnum = last_message_index(recip, todir) + 1;
05225 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
05226 make_file(topath, sizeof(topath), todir, recipmsgnum);
05227 #ifndef ODBC_STORAGE
05228 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
05229 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
05230 } else {
05231 #endif
05232
05233
05234
05235 copy_plain_file(frompath, topath);
05236 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL);
05237 vm_delete(topath);
05238 #ifndef ODBC_STORAGE
05239 }
05240 #endif
05241 } else {
05242 ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
05243 res = -1;
05244 }
05245 ast_unlock_path(todir);
05246 notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt,
05247 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05248 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05249 flag);
05250
05251 return res;
05252 }
05253 #endif
05254 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
05255
05256 static int messagecount(const char *context, const char *mailbox, const char *folder)
05257 {
05258 return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
05259 }
05260
05261 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
05262 {
05263 DIR *dir;
05264 struct dirent *de;
05265 char fn[256];
05266 int ret = 0;
05267
05268
05269 if (ast_strlen_zero(mailbox))
05270 return 0;
05271
05272 if (ast_strlen_zero(folder))
05273 folder = "INBOX";
05274 if (ast_strlen_zero(context))
05275 context = "default";
05276
05277 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
05278
05279 if (!(dir = opendir(fn)))
05280 return 0;
05281
05282 while ((de = readdir(dir))) {
05283 if (!strncasecmp(de->d_name, "msg", 3)) {
05284 if (shortcircuit) {
05285 ret = 1;
05286 break;
05287 } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
05288 ret++;
05289 }
05290 }
05291 }
05292
05293 closedir(dir);
05294
05295 return ret;
05296 }
05297
05298
05299
05300
05301
05302
05303
05304
05305
05306
05307 static int has_voicemail(const char *mailbox, const char *folder)
05308 {
05309 char tmp[256], *tmp2 = tmp, *box, *context;
05310 ast_copy_string(tmp, mailbox, sizeof(tmp));
05311 if (ast_strlen_zero(folder)) {
05312 folder = "INBOX";
05313 }
05314 while ((box = strsep(&tmp2, ",&"))) {
05315 if ((context = strchr(box, '@')))
05316 *context++ = '\0';
05317 else
05318 context = "default";
05319 if (__has_voicemail(context, box, folder, 1))
05320 return 1;
05321
05322 if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
05323 return 1;
05324 }
05325 }
05326 return 0;
05327 }
05328
05329
05330 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05331 {
05332 char tmp[256];
05333 char *context;
05334
05335
05336 if (ast_strlen_zero(mailbox))
05337 return 0;
05338
05339 if (newmsgs)
05340 *newmsgs = 0;
05341 if (oldmsgs)
05342 *oldmsgs = 0;
05343 if (urgentmsgs)
05344 *urgentmsgs = 0;
05345
05346 if (strchr(mailbox, ',')) {
05347 int tmpnew, tmpold, tmpurgent;
05348 char *mb, *cur;
05349
05350 ast_copy_string(tmp, mailbox, sizeof(tmp));
05351 mb = tmp;
05352 while ((cur = strsep(&mb, ", "))) {
05353 if (!ast_strlen_zero(cur)) {
05354 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
05355 return -1;
05356 else {
05357 if (newmsgs)
05358 *newmsgs += tmpnew;
05359 if (oldmsgs)
05360 *oldmsgs += tmpold;
05361 if (urgentmsgs)
05362 *urgentmsgs += tmpurgent;
05363 }
05364 }
05365 }
05366 return 0;
05367 }
05368
05369 ast_copy_string(tmp, mailbox, sizeof(tmp));
05370
05371 if ((context = strchr(tmp, '@')))
05372 *context++ = '\0';
05373 else
05374 context = "default";
05375
05376 if (newmsgs)
05377 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
05378 if (oldmsgs)
05379 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
05380 if (urgentmsgs)
05381 *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
05382
05383 return 0;
05384 }
05385
05386 #endif
05387
05388
05389 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
05390 {
05391 int urgentmsgs = 0;
05392 int res = inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
05393 if (newmsgs) {
05394 *newmsgs += urgentmsgs;
05395 }
05396 return res;
05397 }
05398
05399 static void run_externnotify(char *context, char *extension, const char *flag)
05400 {
05401 char arguments[255];
05402 char ext_context[256] = "";
05403 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
05404 struct ast_smdi_mwi_message *mwi_msg;
05405
05406 if (!ast_strlen_zero(context))
05407 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
05408 else
05409 ast_copy_string(ext_context, extension, sizeof(ext_context));
05410
05411 if (smdi_iface) {
05412 if (ast_app_has_voicemail(ext_context, NULL))
05413 ast_smdi_mwi_set(smdi_iface, extension);
05414 else
05415 ast_smdi_mwi_unset(smdi_iface, extension);
05416
05417 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
05418 ast_log(AST_LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
05419 if (!strncmp(mwi_msg->cause, "INV", 3))
05420 ast_log(AST_LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
05421 else if (!strncmp(mwi_msg->cause, "BLK", 3))
05422 ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
05423 ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
05424 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
05425 } else {
05426 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
05427 }
05428 }
05429
05430 if (!ast_strlen_zero(externnotify)) {
05431 if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
05432 ast_log(AST_LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
05433 } else {
05434 snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &", externnotify, context, extension, newvoicemails, oldvoicemails, urgentvoicemails);
05435 ast_debug(1, "Executing %s\n", arguments);
05436 ast_safe_system(arguments);
05437 }
05438 }
05439 }
05440
05441
05442
05443
05444
05445
05446 struct leave_vm_options {
05447 unsigned int flags;
05448 signed char record_gain;
05449 char *exitcontext;
05450 };
05451
05452
05453
05454
05455
05456
05457
05458
05459
05460
05461
05462 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
05463 {
05464 #ifdef IMAP_STORAGE
05465 int newmsgs, oldmsgs;
05466 #else
05467 char urgdir[PATH_MAX];
05468 #endif
05469 char txtfile[PATH_MAX];
05470 char tmptxtfile[PATH_MAX];
05471 struct vm_state *vms = NULL;
05472 char callerid[256];
05473 FILE *txt;
05474 char date[256];
05475 int txtdes;
05476 int res = 0;
05477 int msgnum;
05478 int duration = 0;
05479 int ausemacro = 0;
05480 int ousemacro = 0;
05481 int ouseexten = 0;
05482 char tmpdur[16];
05483 char priority[16];
05484 char origtime[16];
05485 char dir[PATH_MAX];
05486 char tmpdir[PATH_MAX];
05487 char fn[PATH_MAX];
05488 char prefile[PATH_MAX] = "";
05489 char tempfile[PATH_MAX] = "";
05490 char ext_context[256] = "";
05491 char fmt[80];
05492 char *context;
05493 char ecodes[17] = "#";
05494 struct ast_str *tmp = ast_str_create(16);
05495 char *tmpptr;
05496 struct ast_vm_user *vmu;
05497 struct ast_vm_user svm;
05498 const char *category = NULL;
05499 const char *code;
05500 const char *alldtmf = "0123456789ABCD*#";
05501 char flag[80];
05502
05503 if (!tmp) {
05504 return -1;
05505 }
05506
05507 ast_str_set(&tmp, 0, "%s", ext);
05508 ext = ast_str_buffer(tmp);
05509 if ((context = strchr(ext, '@'))) {
05510 *context++ = '\0';
05511 tmpptr = strchr(context, '&');
05512 } else {
05513 tmpptr = strchr(ext, '&');
05514 }
05515
05516 if (tmpptr)
05517 *tmpptr++ = '\0';
05518
05519 ast_channel_lock(chan);
05520 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
05521 category = ast_strdupa(category);
05522 }
05523 ast_channel_unlock(chan);
05524
05525 if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
05526 ast_copy_string(flag, "Urgent", sizeof(flag));
05527 } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
05528 ast_copy_string(flag, "PRIORITY", sizeof(flag));
05529 } else {
05530 flag[0] = '\0';
05531 }
05532
05533 ast_debug(3, "Before find_user\n");
05534 if (!(vmu = find_user(&svm, context, ext))) {
05535 ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
05536 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05537 ast_free(tmp);
05538 return res;
05539 }
05540
05541 if (strcmp(vmu->context, "default"))
05542 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
05543 else
05544 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
05545
05546
05547
05548
05549
05550
05551 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
05552 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
05553 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
05554 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
05555 }
05556
05557
05558
05559
05560 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
05561 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
05562 ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
05563 ast_free(tmp);
05564 return -1;
05565 }
05566 RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
05567 if (ast_fileexists(tempfile, NULL, NULL) > 0)
05568 ast_copy_string(prefile, tempfile, sizeof(prefile));
05569
05570 DISPOSE(tempfile, -1);
05571
05572 #ifndef IMAP_STORAGE
05573 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
05574 #else
05575 snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
05576 if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
05577 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
05578 }
05579 #endif
05580
05581
05582 if (ast_test_flag(vmu, VM_OPERATOR)) {
05583 if (!ast_strlen_zero(vmu->exit)) {
05584 if (ast_exists_extension(chan, vmu->exit, "o", 1,
05585 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05586 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05587 ouseexten = 1;
05588 }
05589 } else if (ast_exists_extension(chan, chan->context, "o", 1,
05590 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05591 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05592 ouseexten = 1;
05593 } else if (!ast_strlen_zero(chan->macrocontext)
05594 && ast_exists_extension(chan, chan->macrocontext, "o", 1,
05595 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05596 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05597 ousemacro = 1;
05598 }
05599 }
05600
05601 if (!ast_strlen_zero(vmu->exit)) {
05602 if (ast_exists_extension(chan, vmu->exit, "a", 1,
05603 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05604 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05605 }
05606 } else if (ast_exists_extension(chan, chan->context, "a", 1,
05607 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05608 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05609 } else if (!ast_strlen_zero(chan->macrocontext)
05610 && ast_exists_extension(chan, chan->macrocontext, "a", 1,
05611 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05612 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05613 ausemacro = 1;
05614 }
05615
05616 if (ast_test_flag(options, OPT_DTMFEXIT)) {
05617 for (code = alldtmf; *code; code++) {
05618 char e[2] = "";
05619 e[0] = *code;
05620 if (strchr(ecodes, e[0]) == NULL
05621 && ast_canmatch_extension(chan, chan->context, e, 1,
05622 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05623 strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
05624 }
05625 }
05626 }
05627
05628
05629 if (!ast_strlen_zero(prefile)) {
05630 #ifdef ODBC_STORAGE
05631 int success =
05632 #endif
05633 RETRIEVE(prefile, -1, ext, context);
05634 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05635 if (ast_streamfile(chan, prefile, chan->language) > -1)
05636 res = ast_waitstream(chan, ecodes);
05637 #ifdef ODBC_STORAGE
05638 if (success == -1) {
05639
05640 ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
05641 store_file(prefile, vmu->mailbox, vmu->context, -1);
05642 }
05643 #endif
05644 } else {
05645 ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
05646 res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
05647 }
05648 DISPOSE(prefile, -1);
05649 if (res < 0) {
05650 ast_debug(1, "Hang up during prefile playback\n");
05651 free_user(vmu);
05652 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05653 ast_free(tmp);
05654 return -1;
05655 }
05656 }
05657 if (res == '#') {
05658
05659 ast_set_flag(options, OPT_SILENT);
05660 res = 0;
05661 }
05662
05663 if (vmu->maxmsg == 0) {
05664 if (option_debug > 2)
05665 ast_log(LOG_DEBUG, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
05666 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05667 goto leave_vm_out;
05668 }
05669 if (!res && !ast_test_flag(options, OPT_SILENT)) {
05670 res = ast_stream_and_wait(chan, INTRO, ecodes);
05671 if (res == '#') {
05672 ast_set_flag(options, OPT_SILENT);
05673 res = 0;
05674 }
05675 }
05676 if (res > 0)
05677 ast_stopstream(chan);
05678
05679
05680 if (res == '*') {
05681 chan->exten[0] = 'a';
05682 chan->exten[1] = '\0';
05683 if (!ast_strlen_zero(vmu->exit)) {
05684 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05685 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
05686 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05687 }
05688 chan->priority = 0;
05689 free_user(vmu);
05690 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05691 ast_free(tmp);
05692 return 0;
05693 }
05694
05695
05696 if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
05697 transfer:
05698 if (ouseexten || ousemacro) {
05699 chan->exten[0] = 'o';
05700 chan->exten[1] = '\0';
05701 if (!ast_strlen_zero(vmu->exit)) {
05702 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05703 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
05704 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05705 }
05706 ast_play_and_wait(chan, "transfer");
05707 chan->priority = 0;
05708 free_user(vmu);
05709 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05710 }
05711 ast_free(tmp);
05712 return OPERATOR_EXIT;
05713 }
05714
05715
05716 if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
05717 if (!ast_strlen_zero(options->exitcontext))
05718 ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context));
05719 free_user(vmu);
05720 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05721 ast_free(tmp);
05722 return res;
05723 }
05724
05725 if (res < 0) {
05726 free_user(vmu);
05727 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05728 ast_free(tmp);
05729 return -1;
05730 }
05731
05732 ast_copy_string(fmt, vmfmts, sizeof(fmt));
05733 if (!ast_strlen_zero(fmt)) {
05734 msgnum = 0;
05735
05736 #ifdef IMAP_STORAGE
05737
05738
05739 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
05740 if (res < 0) {
05741 ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
05742 ast_free(tmp);
05743 return -1;
05744 }
05745 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
05746
05747
05748
05749
05750 if (!(vms = create_vm_state_from_user(vmu))) {
05751 ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
05752 ast_free(tmp);
05753 return -1;
05754 }
05755 }
05756 vms->newmessages++;
05757
05758
05759 msgnum = newmsgs + oldmsgs;
05760 ast_debug(3, "Messagecount set to %d\n", msgnum);
05761 snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
05762
05763 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05764
05765 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
05766 goto leave_vm_out;
05767 }
05768 #else
05769 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
05770 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05771 if (!res)
05772 res = ast_waitstream(chan, "");
05773 ast_log(AST_LOG_WARNING, "No more messages possible\n");
05774 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05775 inprocess_count(vmu->mailbox, vmu->context, -1);
05776 goto leave_vm_out;
05777 }
05778
05779 #endif
05780 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
05781 txtdes = mkstemp(tmptxtfile);
05782 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
05783 if (txtdes < 0) {
05784 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05785 if (!res)
05786 res = ast_waitstream(chan, "");
05787 ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
05788 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05789 inprocess_count(vmu->mailbox, vmu->context, -1);
05790 goto leave_vm_out;
05791 }
05792
05793
05794 if (res >= 0) {
05795
05796 res = ast_stream_and_wait(chan, "beep", "");
05797 }
05798
05799
05800 if (ast_check_realtime("voicemail_data")) {
05801 snprintf(priority, sizeof(priority), "%d", chan->priority);
05802 snprintf(origtime, sizeof(origtime), "%ld", (long) time(NULL));
05803 get_date(date, sizeof(date));
05804 ast_callerid_merge(callerid, sizeof(callerid),
05805 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05806 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05807 "Unknown");
05808 ast_store_realtime("voicemail_data",
05809 "origmailbox", ext,
05810 "context", chan->context,
05811 "macrocontext", chan->macrocontext,
05812 "exten", chan->exten,
05813 "priority", priority,
05814 "callerchan", chan->name,
05815 "callerid", callerid,
05816 "origdate", date,
05817 "origtime", origtime,
05818 "category", S_OR(category, ""),
05819 "filename", tmptxtfile,
05820 SENTINEL);
05821 }
05822
05823
05824 txt = fdopen(txtdes, "w+");
05825 if (txt) {
05826 get_date(date, sizeof(date));
05827 ast_callerid_merge(callerid, sizeof(callerid),
05828 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05829 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05830 "Unknown");
05831 fprintf(txt,
05832 ";\n"
05833 "; Message Information file\n"
05834 ";\n"
05835 "[message]\n"
05836 "origmailbox=%s\n"
05837 "context=%s\n"
05838 "macrocontext=%s\n"
05839 "exten=%s\n"
05840 "rdnis=%s\n"
05841 "priority=%d\n"
05842 "callerchan=%s\n"
05843 "callerid=%s\n"
05844 "origdate=%s\n"
05845 "origtime=%ld\n"
05846 "category=%s\n",
05847 ext,
05848 chan->context,
05849 chan->macrocontext,
05850 chan->exten,
05851 S_COR(chan->redirecting.from.number.valid,
05852 chan->redirecting.from.number.str, "unknown"),
05853 chan->priority,
05854 chan->name,
05855 callerid,
05856 date, (long) time(NULL),
05857 category ? category : "");
05858 } else {
05859 ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
05860 inprocess_count(vmu->mailbox, vmu->context, -1);
05861 if (ast_check_realtime("voicemail_data")) {
05862 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05863 }
05864 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05865 goto leave_vm_out;
05866 }
05867 res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, NULL, options->record_gain, vms, flag);
05868
05869 if (txt) {
05870 fprintf(txt, "flag=%s\n", flag);
05871 if (duration < vmu->minsecs) {
05872 fclose(txt);
05873 ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmu->minsecs);
05874 ast_filedelete(tmptxtfile, NULL);
05875 unlink(tmptxtfile);
05876 if (ast_check_realtime("voicemail_data")) {
05877 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05878 }
05879 inprocess_count(vmu->mailbox, vmu->context, -1);
05880 } else {
05881 fprintf(txt, "duration=%d\n", duration);
05882 fclose(txt);
05883 if (vm_lock_path(dir)) {
05884 ast_log(AST_LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
05885
05886 ast_filedelete(tmptxtfile, NULL);
05887 unlink(tmptxtfile);
05888 inprocess_count(vmu->mailbox, vmu->context, -1);
05889 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
05890 ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
05891 unlink(tmptxtfile);
05892 ast_unlock_path(dir);
05893 inprocess_count(vmu->mailbox, vmu->context, -1);
05894 if (ast_check_realtime("voicemail_data")) {
05895 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05896 }
05897 } else {
05898 #ifndef IMAP_STORAGE
05899 msgnum = last_message_index(vmu, dir) + 1;
05900 #endif
05901 make_file(fn, sizeof(fn), dir, msgnum);
05902
05903
05904 #ifndef IMAP_STORAGE
05905 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
05906 #else
05907 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05908 #endif
05909
05910 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
05911 ast_filerename(tmptxtfile, fn, NULL);
05912 rename(tmptxtfile, txtfile);
05913 inprocess_count(vmu->mailbox, vmu->context, -1);
05914
05915
05916
05917 if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
05918 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
05919
05920 ast_unlock_path(dir);
05921 if (ast_check_realtime("voicemail_data")) {
05922 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
05923 ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL);
05924 }
05925
05926
05927
05928 if (ast_fileexists(fn, NULL, NULL) > 0) {
05929 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag);
05930 }
05931
05932
05933 while (tmpptr) {
05934 struct ast_vm_user recipu, *recip;
05935 char *exten, *cntx;
05936
05937 exten = strsep(&tmpptr, "&");
05938 cntx = strchr(exten, '@');
05939 if (cntx) {
05940 *cntx = '\0';
05941 cntx++;
05942 }
05943 if ((recip = find_user(&recipu, cntx, exten))) {
05944 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag);
05945 free_user(recip);
05946 }
05947 }
05948 #ifndef IMAP_STORAGE
05949 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05950
05951 char sfn[PATH_MAX];
05952 char dfn[PATH_MAX];
05953 int x;
05954
05955 create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
05956 x = last_message_index(vmu, urgdir) + 1;
05957 make_file(sfn, sizeof(sfn), dir, msgnum);
05958 make_file(dfn, sizeof(dfn), urgdir, x);
05959 ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n", sfn, dfn);
05960 RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
05961
05962 ast_copy_string(fn, dfn, sizeof(fn));
05963 msgnum = x;
05964 }
05965 #endif
05966
05967 if (ast_fileexists(fn, NULL, NULL)) {
05968 #ifdef IMAP_STORAGE
05969 notify_new_message(chan, vmu, vms, msgnum, duration, fmt,
05970 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05971 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05972 flag);
05973 #else
05974 notify_new_message(chan, vmu, NULL, msgnum, duration, fmt,
05975 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05976 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05977 flag);
05978 #endif
05979 }
05980
05981
05982 if (ast_fileexists(fn, NULL, NULL)) {
05983 DISPOSE(dir, msgnum);
05984 }
05985 }
05986 }
05987 } else {
05988 inprocess_count(vmu->mailbox, vmu->context, -1);
05989 }
05990 if (res == '0') {
05991 goto transfer;
05992 } else if (res > 0 && res != 't')
05993 res = 0;
05994
05995 if (duration < vmu->minsecs)
05996
05997 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05998 else
05999 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
06000 } else
06001 ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
06002 leave_vm_out:
06003 free_user(vmu);
06004
06005 #ifdef IMAP_STORAGE
06006
06007 ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
06008 if (expungeonhangup == 1) {
06009 ast_mutex_lock(&vms->lock);
06010 #ifdef HAVE_IMAP_TK2006
06011 if (LEVELUIDPLUS (vms->mailstream)) {
06012 mail_expunge_full(vms->mailstream, NIL, EX_UID);
06013 } else
06014 #endif
06015 mail_expunge(vms->mailstream);
06016 ast_mutex_unlock(&vms->lock);
06017 }
06018 #endif
06019
06020 ast_free(tmp);
06021 return res;
06022 }
06023
06024 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
06025 {
06026 int d;
06027 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL);
06028 return d;
06029 }
06030
06031 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
06032 {
06033 #ifdef IMAP_STORAGE
06034
06035
06036 char sequence[10];
06037 char mailbox[256];
06038 int res;
06039
06040
06041 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
06042
06043 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(vmu, box));
06044 ast_mutex_lock(&vms->lock);
06045
06046 if (box == OLD_FOLDER) {
06047 mail_setflag(vms->mailstream, sequence, "\\Seen");
06048 mail_clearflag(vms->mailstream, sequence, "\\Unseen");
06049 } else if (box == NEW_FOLDER) {
06050 mail_setflag(vms->mailstream, sequence, "\\Unseen");
06051 mail_clearflag(vms->mailstream, sequence, "\\Seen");
06052 }
06053 if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
06054 ast_mutex_unlock(&vms->lock);
06055 return 0;
06056 }
06057
06058 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
06059 ast_debug(5, "Checking if folder exists: %s\n", mailbox);
06060 if (mail_create(vms->mailstream, mailbox) == NIL)
06061 ast_debug(5, "Folder exists.\n");
06062 else
06063 ast_log(AST_LOG_NOTICE, "Folder %s created!\n", mbox(vmu, box));
06064 res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box));
06065 ast_mutex_unlock(&vms->lock);
06066 return res;
06067 #else
06068 char *dir = vms->curdir;
06069 char *username = vms->username;
06070 char *context = vmu->context;
06071 char sfn[PATH_MAX];
06072 char dfn[PATH_MAX];
06073 char ddir[PATH_MAX];
06074 const char *dbox = mbox(vmu, box);
06075 int x, i;
06076 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
06077
06078 if (vm_lock_path(ddir))
06079 return ERROR_LOCK_PATH;
06080
06081 x = last_message_index(vmu, ddir) + 1;
06082
06083 if (box == 10 && x >= vmu->maxdeletedmsg) {
06084 x--;
06085 for (i = 1; i <= x; i++) {
06086
06087 make_file(sfn, sizeof(sfn), ddir, i);
06088 make_file(dfn, sizeof(dfn), ddir, i - 1);
06089 if (EXISTS(ddir, i, sfn, NULL)) {
06090 RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
06091 } else
06092 break;
06093 }
06094 } else {
06095 if (x >= vmu->maxmsg) {
06096 ast_unlock_path(ddir);
06097 return -1;
06098 }
06099 }
06100 make_file(sfn, sizeof(sfn), dir, msg);
06101 make_file(dfn, sizeof(dfn), ddir, x);
06102 if (strcmp(sfn, dfn)) {
06103 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
06104 }
06105 ast_unlock_path(ddir);
06106 #endif
06107 return 0;
06108 }
06109
06110 static int adsi_logo(unsigned char *buf)
06111 {
06112 int bytes = 0;
06113 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
06114 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
06115 return bytes;
06116 }
06117
06118 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
06119 {
06120 unsigned char buf[256];
06121 int bytes = 0;
06122 int x;
06123 char num[5];
06124
06125 *useadsi = 0;
06126 bytes += ast_adsi_data_mode(buf + bytes);
06127 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06128
06129 bytes = 0;
06130 bytes += adsi_logo(buf);
06131 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06132 #ifdef DISPLAY
06133 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
06134 #endif
06135 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06136 bytes += ast_adsi_data_mode(buf + bytes);
06137 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06138
06139 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
06140 bytes = 0;
06141 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
06142 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06143 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06144 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06145 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06146 return 0;
06147 }
06148
06149 #ifdef DISPLAY
06150
06151 bytes = 0;
06152 bytes += ast_adsi_logo(buf);
06153 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06154 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
06155 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06156 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06157 #endif
06158 bytes = 0;
06159 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
06160 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
06161 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
06162 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
06163 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
06164 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
06165 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06166
06167 #ifdef DISPLAY
06168
06169 bytes = 0;
06170 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
06171 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06172
06173 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06174 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06175 #endif
06176
06177 bytes = 0;
06178
06179 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
06180 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
06181 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
06182 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
06183 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
06184 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
06185 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06186
06187 #ifdef DISPLAY
06188
06189 bytes = 0;
06190 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
06191 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06192 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06193 #endif
06194
06195 bytes = 0;
06196 for (x = 0; x < 5; x++) {
06197 snprintf(num, sizeof(num), "%d", x);
06198 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(NULL, x), mbox(NULL, x), num, 1);
06199 }
06200 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
06201 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06202
06203 #ifdef DISPLAY
06204
06205 bytes = 0;
06206 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
06207 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06208 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06209 #endif
06210
06211 if (ast_adsi_end_download(chan)) {
06212 bytes = 0;
06213 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
06214 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06215 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06216 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06217 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06218 return 0;
06219 }
06220 bytes = 0;
06221 bytes += ast_adsi_download_disconnect(buf + bytes);
06222 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06223 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06224
06225 ast_debug(1, "Done downloading scripts...\n");
06226
06227 #ifdef DISPLAY
06228
06229 bytes = 0;
06230 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
06231 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06232 #endif
06233 ast_debug(1, "Restarting session...\n");
06234
06235 bytes = 0;
06236
06237 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
06238 *useadsi = 1;
06239 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
06240 } else
06241 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
06242
06243 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06244 return 0;
06245 }
06246
06247 static void adsi_begin(struct ast_channel *chan, int *useadsi)
06248 {
06249 int x;
06250 if (!ast_adsi_available(chan))
06251 return;
06252 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
06253 if (x < 0)
06254 return;
06255 if (!x) {
06256 if (adsi_load_vmail(chan, useadsi)) {
06257 ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
06258 return;
06259 }
06260 } else
06261 *useadsi = 1;
06262 }
06263
06264 static void adsi_login(struct ast_channel *chan)
06265 {
06266 unsigned char buf[256];
06267 int bytes = 0;
06268 unsigned char keys[8];
06269 int x;
06270 if (!ast_adsi_available(chan))
06271 return;
06272
06273 for (x = 0; x < 8; x++)
06274 keys[x] = 0;
06275
06276 keys[3] = ADSI_KEY_APPS + 3;
06277
06278 bytes += adsi_logo(buf + bytes);
06279 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
06280 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
06281 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06282 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
06283 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
06284 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
06285 bytes += ast_adsi_set_keys(buf + bytes, keys);
06286 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06287 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06288 }
06289
06290 static void adsi_password(struct ast_channel *chan)
06291 {
06292 unsigned char buf[256];
06293 int bytes = 0;
06294 unsigned char keys[8];
06295 int x;
06296 if (!ast_adsi_available(chan))
06297 return;
06298
06299 for (x = 0; x < 8; x++)
06300 keys[x] = 0;
06301
06302 keys[3] = ADSI_KEY_APPS + 3;
06303
06304 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06305 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
06306 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
06307 bytes += ast_adsi_set_keys(buf + bytes, keys);
06308 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06309 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06310 }
06311
06312 static void adsi_folders(struct ast_channel *chan, int start, char *label)
06313 {
06314 unsigned char buf[256];
06315 int bytes = 0;
06316 unsigned char keys[8];
06317 int x, y;
06318
06319 if (!ast_adsi_available(chan))
06320 return;
06321
06322 for (x = 0; x < 5; x++) {
06323 y = ADSI_KEY_APPS + 12 + start + x;
06324 if (y > ADSI_KEY_APPS + 12 + 4)
06325 y = 0;
06326 keys[x] = ADSI_KEY_SKT | y;
06327 }
06328 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
06329 keys[6] = 0;
06330 keys[7] = 0;
06331
06332 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
06333 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
06334 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06335 bytes += ast_adsi_set_keys(buf + bytes, keys);
06336 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06337
06338 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06339 }
06340
06341 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
06342 {
06343 int bytes = 0;
06344 unsigned char buf[256];
06345 char buf1[256], buf2[256];
06346 char fn2[PATH_MAX];
06347
06348 char cid[256] = "";
06349 char *val;
06350 char *name, *num;
06351 char datetime[21] = "";
06352 FILE *f;
06353
06354 unsigned char keys[8];
06355
06356 int x;
06357
06358 if (!ast_adsi_available(chan))
06359 return;
06360
06361
06362 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
06363 f = fopen(fn2, "r");
06364 if (f) {
06365 while (!feof(f)) {
06366 if (!fgets((char *) buf, sizeof(buf), f)) {
06367 continue;
06368 }
06369 if (!feof(f)) {
06370 char *stringp = NULL;
06371 stringp = (char *) buf;
06372 strsep(&stringp, "=");
06373 val = strsep(&stringp, "=");
06374 if (!ast_strlen_zero(val)) {
06375 if (!strcmp((char *) buf, "callerid"))
06376 ast_copy_string(cid, val, sizeof(cid));
06377 if (!strcmp((char *) buf, "origdate"))
06378 ast_copy_string(datetime, val, sizeof(datetime));
06379 }
06380 }
06381 }
06382 fclose(f);
06383 }
06384
06385 for (x = 0; x < 5; x++)
06386 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06387 keys[6] = 0x0;
06388 keys[7] = 0x0;
06389
06390 if (!vms->curmsg) {
06391
06392 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06393 }
06394 if (vms->curmsg >= vms->lastmsg) {
06395
06396 if (vms->curmsg) {
06397
06398 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06399 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06400
06401 } else {
06402
06403 keys[3] = 1;
06404 }
06405 }
06406
06407 if (!ast_strlen_zero(cid)) {
06408 ast_callerid_parse(cid, &name, &num);
06409 if (!name)
06410 name = num;
06411 } else
06412 name = "Unknown Caller";
06413
06414
06415
06416 if (vms->deleted[vms->curmsg])
06417 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06418
06419
06420 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06421 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
06422 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
06423 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
06424
06425 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06426 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06427 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
06428 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
06429 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06430 bytes += ast_adsi_set_keys(buf + bytes, keys);
06431 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06432
06433 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06434 }
06435
06436 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
06437 {
06438 int bytes = 0;
06439 unsigned char buf[256];
06440 unsigned char keys[8];
06441
06442 int x;
06443
06444 if (!ast_adsi_available(chan))
06445 return;
06446
06447
06448 for (x = 0; x < 5; x++)
06449 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06450
06451 keys[6] = 0x0;
06452 keys[7] = 0x0;
06453
06454 if (!vms->curmsg) {
06455
06456 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06457 }
06458 if (vms->curmsg >= vms->lastmsg) {
06459
06460 if (vms->curmsg) {
06461
06462 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06463 } else {
06464
06465 keys[3] = 1;
06466 }
06467 }
06468
06469
06470 if (vms->deleted[vms->curmsg])
06471 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06472
06473
06474 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06475 bytes += ast_adsi_set_keys(buf + bytes, keys);
06476 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06477
06478 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06479 }
06480
06481 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
06482 {
06483 unsigned char buf[256] = "";
06484 char buf1[256] = "", buf2[256] = "";
06485 int bytes = 0;
06486 unsigned char keys[8];
06487 int x;
06488
06489 char *newm = (vms->newmessages == 1) ? "message" : "messages";
06490 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
06491 if (!ast_adsi_available(chan))
06492 return;
06493 if (vms->newmessages) {
06494 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
06495 if (vms->oldmessages) {
06496 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
06497 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
06498 } else {
06499 snprintf(buf2, sizeof(buf2), "%s.", newm);
06500 }
06501 } else if (vms->oldmessages) {
06502 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
06503 snprintf(buf2, sizeof(buf2), "%s.", oldm);
06504 } else {
06505 strcpy(buf1, "You have no messages.");
06506 buf2[0] = ' ';
06507 buf2[1] = '\0';
06508 }
06509 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06510 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06511 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06512
06513 for (x = 0; x < 6; x++)
06514 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06515 keys[6] = 0;
06516 keys[7] = 0;
06517
06518
06519 if (vms->lastmsg < 0)
06520 keys[0] = 1;
06521 bytes += ast_adsi_set_keys(buf + bytes, keys);
06522
06523 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06524
06525 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06526 }
06527
06528 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
06529 {
06530 unsigned char buf[256] = "";
06531 char buf1[256] = "", buf2[256] = "";
06532 int bytes = 0;
06533 unsigned char keys[8];
06534 int x;
06535
06536 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
06537
06538 if (!ast_adsi_available(chan))
06539 return;
06540
06541
06542 for (x = 0; x < 6; x++)
06543 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06544
06545 keys[6] = 0;
06546 keys[7] = 0;
06547
06548 if ((vms->lastmsg + 1) < 1)
06549 keys[0] = 0;
06550
06551 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
06552 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
06553
06554 if (vms->lastmsg + 1)
06555 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
06556 else
06557 strcpy(buf2, "no messages.");
06558 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06559 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06560 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
06561 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06562 bytes += ast_adsi_set_keys(buf + bytes, keys);
06563
06564 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06565
06566 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06567
06568 }
06569
06570
06571
06572
06573
06574
06575
06576
06577
06578
06579
06580
06581
06582
06583
06584 static void adsi_goodbye(struct ast_channel *chan)
06585 {
06586 unsigned char buf[256];
06587 int bytes = 0;
06588
06589 if (!ast_adsi_available(chan))
06590 return;
06591 bytes += adsi_logo(buf + bytes);
06592 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
06593 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
06594 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06595 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06596
06597 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06598 }
06599
06600
06601
06602
06603
06604 static int get_folder(struct ast_channel *chan, int start)
06605 {
06606 int x;
06607 int d;
06608 char fn[PATH_MAX];
06609 d = ast_play_and_wait(chan, "vm-press");
06610 if (d)
06611 return d;
06612 for (x = start; x < 5; x++) {
06613 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, NULL)))
06614 return d;
06615 d = ast_play_and_wait(chan, "vm-for");
06616 if (d)
06617 return d;
06618 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x));
06619 d = vm_play_folder_name(chan, fn);
06620 if (d)
06621 return d;
06622 d = ast_waitfordigit(chan, 500);
06623 if (d)
06624 return d;
06625 }
06626 d = ast_play_and_wait(chan, "vm-tocancel");
06627 if (d)
06628 return d;
06629 d = ast_waitfordigit(chan, 4000);
06630 return d;
06631 }
06632
06633
06634
06635
06636
06637
06638
06639
06640
06641
06642
06643
06644
06645 static int get_folder2(struct ast_channel *chan, char *fn, int start)
06646 {
06647 int res = 0;
06648 int loops = 0;
06649 res = ast_play_and_wait(chan, fn);
06650 while (((res < '0') || (res > '9')) &&
06651 (res != '#') && (res >= 0) &&
06652 loops < 4) {
06653 res = get_folder(chan, 0);
06654 loops++;
06655 }
06656 if (loops == 4) {
06657 return '#';
06658 }
06659 return res;
06660 }
06661
06662
06663
06664
06665
06666
06667
06668
06669
06670
06671
06672
06673
06674
06675
06676
06677
06678
06679
06680 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts,
06681 char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
06682 {
06683 #ifdef IMAP_STORAGE
06684 int res;
06685 #endif
06686 int cmd = 0;
06687 int retries = 0, prepend_duration = 0, already_recorded = 0;
06688 char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06689 char textfile[PATH_MAX];
06690 struct ast_config *msg_cfg;
06691 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06692 #ifndef IMAP_STORAGE
06693 signed char zero_gain = 0;
06694 #endif
06695 const char *duration_str;
06696
06697
06698 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06699 strcpy(textfile, msgfile);
06700 strcpy(backup, msgfile);
06701 strcpy(backup_textfile, msgfile);
06702 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
06703 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
06704 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
06705
06706 if ((msg_cfg = ast_config_load(textfile, config_flags)) && msg_cfg != CONFIG_STATUS_FILEINVALID && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
06707 *duration = atoi(duration_str);
06708 } else {
06709 *duration = 0;
06710 }
06711
06712 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
06713 if (cmd)
06714 retries = 0;
06715 switch (cmd) {
06716 case '1':
06717
06718 #ifdef IMAP_STORAGE
06719
06720 make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
06721 strncat(vms->introfn, "intro", sizeof(vms->introfn));
06722 res = ast_play_and_wait(chan, INTRO);
06723 res = ast_play_and_wait(chan, "beep");
06724 res = play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, record_gain, vms, flag);
06725 cmd = 't';
06726 #else
06727
06728
06729
06730 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06731 strcpy(textfile, msgfile);
06732 strncat(textfile, ".txt", sizeof(textfile) - 1);
06733 *duration = 0;
06734
06735
06736 if (!msg_cfg) {
06737 cmd = 0;
06738 break;
06739 }
06740
06741
06742 if (already_recorded) {
06743 ast_filecopy(backup, msgfile, NULL);
06744 copy(backup_textfile, textfile);
06745 }
06746 else {
06747 ast_filecopy(msgfile, backup, NULL);
06748 copy(textfile,backup_textfile);
06749 }
06750 already_recorded = 1;
06751
06752 if (record_gain)
06753 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
06754
06755 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, 1, silencethreshold, maxsilence);
06756 if (cmd == 'S') {
06757 ast_filerename(backup, msgfile, NULL);
06758 }
06759
06760 if (record_gain)
06761 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
06762
06763
06764 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
06765 *duration = atoi(duration_str);
06766
06767 if (prepend_duration) {
06768 struct ast_category *msg_cat;
06769
06770 char duration_buf[12];
06771
06772 *duration += prepend_duration;
06773 msg_cat = ast_category_get(msg_cfg, "message");
06774 snprintf(duration_buf, 11, "%ld", *duration);
06775 if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
06776 ast_config_text_file_save(textfile, msg_cfg, "app_voicemail");
06777 }
06778 }
06779
06780 #endif
06781 break;
06782 case '2':
06783
06784 #ifdef IMAP_STORAGE
06785 *vms->introfn = '\0';
06786 #endif
06787 cmd = 't';
06788 break;
06789 case '*':
06790 cmd = '*';
06791 break;
06792 default:
06793 cmd = ast_play_and_wait(chan, "vm-forwardoptions");
06794
06795 if (!cmd)
06796 cmd = ast_play_and_wait(chan, "vm-starmain");
06797
06798 if (!cmd)
06799 cmd = ast_waitfordigit(chan, 6000);
06800 if (!cmd)
06801 retries++;
06802 if (retries > 3)
06803 cmd = 't';
06804 }
06805 }
06806
06807 if (msg_cfg)
06808 ast_config_destroy(msg_cfg);
06809 if (prepend_duration)
06810 *duration = prepend_duration;
06811
06812 if (already_recorded && cmd == -1) {
06813
06814 ast_filerename(backup, msgfile, NULL);
06815 rename(backup_textfile, textfile);
06816 }
06817
06818 if (cmd == 't' || cmd == 'S')
06819 cmd = 0;
06820 return cmd;
06821 }
06822
06823 static void queue_mwi_event(const char *box, int urgent, int new, int old)
06824 {
06825 struct ast_event *event;
06826 char *mailbox, *context;
06827
06828
06829 context = mailbox = ast_strdupa(box);
06830 strsep(&context, "@");
06831 if (ast_strlen_zero(context))
06832 context = "default";
06833
06834 if (!(event = ast_event_new(AST_EVENT_MWI,
06835 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
06836 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
06837 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
06838 AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
06839 AST_EVENT_IE_END))) {
06840 return;
06841 }
06842
06843 ast_event_queue_and_cache(event);
06844 }
06845
06846
06847
06848
06849
06850
06851
06852
06853
06854
06855
06856
06857
06858
06859
06860 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)
06861 {
06862 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
06863 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
06864 const char *category;
06865 char *myserveremail = serveremail;
06866
06867 ast_channel_lock(chan);
06868 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
06869 category = ast_strdupa(category);
06870 }
06871 ast_channel_unlock(chan);
06872
06873 #ifndef IMAP_STORAGE
06874 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag) && !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
06875 #else
06876 snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
06877 #endif
06878 make_file(fn, sizeof(fn), todir, msgnum);
06879 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
06880
06881 if (!ast_strlen_zero(vmu->attachfmt)) {
06882 if (strstr(fmt, vmu->attachfmt))
06883 fmt = vmu->attachfmt;
06884 else
06885 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);
06886 }
06887
06888
06889 fmt = ast_strdupa(fmt);
06890 stringp = fmt;
06891 strsep(&stringp, "|");
06892
06893 if (!ast_strlen_zero(vmu->serveremail))
06894 myserveremail = vmu->serveremail;
06895
06896 if (!ast_strlen_zero(vmu->email)) {
06897 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
06898
06899 if (attach_user_voicemail)
06900 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
06901
06902
06903 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag);
06904
06905 if (attach_user_voicemail)
06906 DISPOSE(todir, msgnum);
06907 }
06908
06909 if (!ast_strlen_zero(vmu->pager)) {
06910 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
06911 }
06912
06913 if (ast_test_flag(vmu, VM_DELETE))
06914 DELETE(todir, msgnum, fn, vmu);
06915
06916
06917 if (ast_app_has_voicemail(ext_context, NULL))
06918 ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
06919
06920 queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);
06921
06922 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);
06923 run_externnotify(vmu->context, vmu->mailbox, flag);
06924
06925 #ifdef IMAP_STORAGE
06926 vm_delete(fn);
06927 if (ast_test_flag(vmu, VM_DELETE)) {
06928 vm_imap_delete(NULL, vms->curmsg, vmu);
06929 vms->newmessages--;
06930 }
06931 #endif
06932
06933 return 0;
06934 }
06935
06936
06937
06938
06939
06940
06941
06942
06943
06944
06945
06946
06947
06948
06949
06950
06951
06952
06953
06954
06955
06956
06957
06958
06959
06960
06961
06962
06963 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)
06964 {
06965 #ifdef IMAP_STORAGE
06966 int todircount = 0;
06967 struct vm_state *dstvms;
06968 #endif
06969 char username[70]="";
06970 char fn[PATH_MAX];
06971 char ecodes[16] = "#";
06972 int res = 0, cmd = 0;
06973 struct ast_vm_user *receiver = NULL, *vmtmp;
06974 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
06975 char *stringp;
06976 const char *s;
06977 int saved_messages = 0;
06978 int valid_extensions = 0;
06979 char *dir;
06980 int curmsg;
06981 char urgent_str[7] = "";
06982 char tmptxtfile[PATH_MAX];
06983 int prompt_played = 0;
06984 #ifndef IMAP_STORAGE
06985 char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06986 #endif
06987 if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
06988 ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
06989 }
06990
06991 if (vms == NULL) return -1;
06992 dir = vms->curdir;
06993 curmsg = vms->curmsg;
06994
06995 tmptxtfile[0] = '\0';
06996 while (!res && !valid_extensions) {
06997 int use_directory = 0;
06998 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
06999 int done = 0;
07000 int retries = 0;
07001 cmd = 0;
07002 while ((cmd >= 0) && !done ){
07003 if (cmd)
07004 retries = 0;
07005 switch (cmd) {
07006 case '1':
07007 use_directory = 0;
07008 done = 1;
07009 break;
07010 case '2':
07011 use_directory = 1;
07012 done = 1;
07013 break;
07014 case '*':
07015 cmd = 't';
07016 done = 1;
07017 break;
07018 default:
07019
07020 cmd = ast_play_and_wait(chan, "vm-forward");
07021 if (!cmd)
07022 cmd = ast_waitfordigit(chan, 3000);
07023 if (!cmd)
07024 retries++;
07025 if (retries > 3) {
07026 cmd = 't';
07027 done = 1;
07028 }
07029
07030 }
07031 }
07032 if (cmd < 0 || cmd == 't')
07033 break;
07034 }
07035
07036 if (use_directory) {
07037
07038
07039 char old_context[sizeof(chan->context)];
07040 char old_exten[sizeof(chan->exten)];
07041 int old_priority;
07042 struct ast_app* directory_app;
07043
07044 directory_app = pbx_findapp("Directory");
07045 if (directory_app) {
07046 char vmcontext[256];
07047
07048 memcpy(old_context, chan->context, sizeof(chan->context));
07049 memcpy(old_exten, chan->exten, sizeof(chan->exten));
07050 old_priority = chan->priority;
07051
07052
07053 snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
07054 res = pbx_exec(chan, directory_app, vmcontext);
07055
07056 ast_copy_string(username, chan->exten, sizeof(username));
07057
07058
07059 memcpy(chan->context, old_context, sizeof(chan->context));
07060 memcpy(chan->exten, old_exten, sizeof(chan->exten));
07061 chan->priority = old_priority;
07062 } else {
07063 ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
07064 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
07065 }
07066 } else {
07067
07068 res = ast_streamfile(chan, "vm-extension", chan->language);
07069 prompt_played++;
07070 if (res || prompt_played > 4)
07071 break;
07072 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
07073 break;
07074 }
07075
07076
07077 if (ast_strlen_zero(username))
07078 continue;
07079 stringp = username;
07080 s = strsep(&stringp, "*");
07081
07082 valid_extensions = 1;
07083 while (s) {
07084 if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
07085 int oldmsgs;
07086 int newmsgs;
07087 int capacity;
07088 if (inboxcount(s, &newmsgs, &oldmsgs)) {
07089 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", s);
07090
07091 res = ast_play_and_wait(chan, "pbx-invalid");
07092 valid_extensions = 0;
07093 break;
07094 }
07095 capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
07096 if ((newmsgs + oldmsgs) >= capacity) {
07097 ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity);
07098 res = ast_play_and_wait(chan, "vm-mailboxfull");
07099 valid_extensions = 0;
07100 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07101 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07102 free_user(vmtmp);
07103 }
07104 inprocess_count(receiver->mailbox, receiver->context, -1);
07105 break;
07106 }
07107 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
07108 } else {
07109
07110
07111
07112
07113
07114 while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07115 free_user(receiver);
07116 }
07117 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
07118
07119 res = ast_play_and_wait(chan, "pbx-invalid");
07120 valid_extensions = 0;
07121 break;
07122 }
07123
07124
07125 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
07126 RETRIEVE(fn, -1, s, receiver->context);
07127 if (ast_fileexists(fn, NULL, NULL) > 0) {
07128 res = ast_stream_and_wait(chan, fn, ecodes);
07129 if (res) {
07130 DISPOSE(fn, -1);
07131 return res;
07132 }
07133 } else {
07134 res = ast_say_digit_str(chan, s, ecodes, chan->language);
07135 }
07136 DISPOSE(fn, -1);
07137
07138 s = strsep(&stringp, "*");
07139 }
07140
07141 if (valid_extensions)
07142 break;
07143 }
07144
07145 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
07146 return res;
07147 if (is_new_message == 1) {
07148 struct leave_vm_options leave_options;
07149 char mailbox[AST_MAX_EXTENSION * 2 + 2];
07150 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
07151
07152
07153 memset(&leave_options, 0, sizeof(leave_options));
07154 leave_options.record_gain = record_gain;
07155 cmd = leave_voicemail(chan, mailbox, &leave_options);
07156 } else {
07157
07158 long duration = 0;
07159 struct vm_state vmstmp;
07160 int copy_msg_result = 0;
07161 memcpy(&vmstmp, vms, sizeof(vmstmp));
07162
07163 RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
07164
07165 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
07166 if (!cmd) {
07167 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
07168 #ifdef IMAP_STORAGE
07169 int attach_user_voicemail;
07170 char *myserveremail = serveremail;
07171
07172
07173 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
07174 if (!dstvms) {
07175 dstvms = create_vm_state_from_user(vmtmp);
07176 }
07177 if (dstvms) {
07178 init_mailstream(dstvms, 0);
07179 if (!dstvms->mailstream) {
07180 ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
07181 } else {
07182 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str);
07183 run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str);
07184 }
07185 } else {
07186 ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
07187 }
07188 if (!ast_strlen_zero(vmtmp->serveremail))
07189 myserveremail = vmtmp->serveremail;
07190 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
07191
07192 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
07193 dstvms->curbox,
07194 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
07195 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
07196 vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
07197 NULL, urgent_str);
07198 #else
07199 copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
07200 #endif
07201 saved_messages++;
07202 AST_LIST_REMOVE_CURRENT(list);
07203 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07204 free_user(vmtmp);
07205 if (res)
07206 break;
07207 }
07208 AST_LIST_TRAVERSE_SAFE_END;
07209 if (saved_messages > 0 && !copy_msg_result) {
07210
07211
07212
07213
07214
07215
07216
07217
07218 #ifdef IMAP_STORAGE
07219
07220 if (ast_strlen_zero(vmstmp.introfn))
07221 #endif
07222 res = ast_play_and_wait(chan, "vm-msgsaved");
07223 }
07224 #ifndef IMAP_STORAGE
07225 else {
07226
07227 res = ast_play_and_wait(chan, "vm-mailboxfull");
07228 }
07229
07230 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07231 strcpy(textfile, msgfile);
07232 strcpy(backup, msgfile);
07233 strcpy(backup_textfile, msgfile);
07234 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07235 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
07236 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07237 if (ast_fileexists(backup, NULL, NULL) > 0) {
07238 ast_filerename(backup, msgfile, NULL);
07239 rename(backup_textfile, textfile);
07240 }
07241 #endif
07242 }
07243 DISPOSE(dir, curmsg);
07244 #ifndef IMAP_STORAGE
07245 if (cmd) {
07246 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07247 strcpy(textfile, msgfile);
07248 strcpy(backup_textfile, msgfile);
07249 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07250 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07251 rename(backup_textfile, textfile);
07252 }
07253 #endif
07254 }
07255
07256
07257 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07258 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07259 free_user(vmtmp);
07260 }
07261 return res ? res : cmd;
07262 }
07263
07264 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
07265 {
07266 int res;
07267 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
07268 ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file);
07269 return res;
07270 }
07271
07272 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
07273 {
07274 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);
07275 }
07276
07277 static int play_message_category(struct ast_channel *chan, const char *category)
07278 {
07279 int res = 0;
07280
07281 if (!ast_strlen_zero(category))
07282 res = ast_play_and_wait(chan, category);
07283
07284 if (res) {
07285 ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
07286 res = 0;
07287 }
07288
07289 return res;
07290 }
07291
07292 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
07293 {
07294 int res = 0;
07295 struct vm_zone *the_zone = NULL;
07296 time_t t;
07297
07298 if (ast_get_time_t(origtime, &t, 0, NULL)) {
07299 ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
07300 return 0;
07301 }
07302
07303
07304 if (!ast_strlen_zero(vmu->zonetag)) {
07305
07306 struct vm_zone *z;
07307 AST_LIST_LOCK(&zones);
07308 AST_LIST_TRAVERSE(&zones, z, list) {
07309 if (!strcmp(z->name, vmu->zonetag)) {
07310 the_zone = z;
07311 break;
07312 }
07313 }
07314 AST_LIST_UNLOCK(&zones);
07315 }
07316
07317
07318 #if 0
07319
07320 ast_localtime(&t, &time_now, NULL);
07321 tv_now = ast_tvnow();
07322 ast_localtime(&tv_now, &time_then, NULL);
07323
07324
07325 if (time_now.tm_year == time_then.tm_year)
07326 snprintf(temp, sizeof(temp), "%d", time_now.tm_yday);
07327 else
07328 snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
07329 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
07330
07331
07332 #endif
07333 if (the_zone) {
07334 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
07335 } else if (!strncasecmp(chan->language, "de", 2)) {
07336 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07337 } else if (!strncasecmp(chan->language, "gr", 2)) {
07338 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
07339 } else if (!strncasecmp(chan->language, "it", 2)) {
07340 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' 'digits/hours' k 'digits/e' M 'digits/minutes'", NULL);
07341 } else if (!strncasecmp(chan->language, "nl", 2)) {
07342 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
07343 } else if (!strncasecmp(chan->language, "no", 2)) {
07344 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07345 } else if (!strncasecmp(chan->language, "pl", 2)) {
07346 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
07347 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
07348 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Ad 'digits/pt-de' B 'digits/pt-de' Y 'digits/pt-as' HM ", NULL);
07349 } else if (!strncasecmp(chan->language, "se", 2)) {
07350 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
07351 } else if (!strncasecmp(chan->language, "zh", 2)) {
07352 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "qR 'vm-received'", NULL);
07353 } else if (!strncasecmp(chan->language, "vi", 2)) {
07354 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' A 'digits/day' dB 'digits/year' Y 'digits/at' k 'hours' M 'minutes'", NULL);
07355 } else {
07356 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
07357 }
07358 #if 0
07359 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
07360 #endif
07361 return res;
07362 }
07363
07364
07365
07366 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
07367 {
07368 int res = 0;
07369 int i;
07370 char *callerid, *name;
07371 char prefile[PATH_MAX] = "";
07372
07373
07374
07375
07376
07377
07378
07379
07380
07381 if ((cid == NULL)||(context == NULL))
07382 return res;
07383
07384
07385 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
07386 ast_callerid_parse(cid, &name, &callerid);
07387 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
07388
07389
07390 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
07391 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
07392 if ((strcmp(cidinternalcontexts[i], context) == 0))
07393 break;
07394 }
07395 if (i != MAX_NUM_CID_CONTEXTS){
07396 if (!res) {
07397 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
07398 if (!ast_strlen_zero(prefile)) {
07399
07400 if (ast_fileexists(prefile, NULL, NULL) > 0) {
07401 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
07402 if (!callback)
07403 res = wait_file2(chan, vms, "vm-from");
07404 res = ast_stream_and_wait(chan, prefile, "");
07405 } else {
07406 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
07407
07408 if (!callback)
07409 res = wait_file2(chan, vms, "vm-from-extension");
07410 res = ast_say_digit_str(chan, callerid, "", chan->language);
07411 }
07412 }
07413 }
07414 } else if (!res) {
07415 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
07416
07417 if (!callback)
07418 res = wait_file2(chan, vms, "vm-from-phonenumber");
07419 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
07420 }
07421 } else {
07422
07423 ast_debug(1, "VM-CID: From an unknown number\n");
07424
07425 res = wait_file2(chan, vms, "vm-unknown-caller");
07426 }
07427 return res;
07428 }
07429
07430 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
07431 {
07432 int res = 0;
07433 int durationm;
07434 int durations;
07435
07436 if (duration == NULL)
07437 return res;
07438
07439
07440 durations = atoi(duration);
07441 durationm = (durations / 60);
07442
07443 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
07444
07445 if ((!res) && (durationm >= minduration)) {
07446 res = wait_file2(chan, vms, "vm-duration");
07447
07448
07449 if (!strncasecmp(chan->language, "pl", 2)) {
07450 div_t num = div(durationm, 10);
07451
07452 if (durationm == 1) {
07453 res = ast_play_and_wait(chan, "digits/1z");
07454 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
07455 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
07456 if (num.rem == 2) {
07457 if (!num.quot) {
07458 res = ast_play_and_wait(chan, "digits/2-ie");
07459 } else {
07460 res = say_and_wait(chan, durationm - 2 , chan->language);
07461 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
07462 }
07463 } else {
07464 res = say_and_wait(chan, durationm, chan->language);
07465 }
07466 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
07467 } else {
07468 res = say_and_wait(chan, durationm, chan->language);
07469 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
07470 }
07471
07472 } else {
07473 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
07474 res = wait_file2(chan, vms, "vm-minutes");
07475 }
07476 }
07477 return res;
07478 }
07479
07480 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
07481 {
07482 int res = 0;
07483 char filename[256], *cid;
07484 const char *origtime, *context, *category, *duration, *flag;
07485 struct ast_config *msg_cfg;
07486 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
07487
07488 vms->starting = 0;
07489 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07490 adsi_message(chan, vms);
07491 if (!vms->curmsg)
07492 res = wait_file2(chan, vms, "vm-first");
07493 else if (vms->curmsg == vms->lastmsg)
07494 res = wait_file2(chan, vms, "vm-last");
07495
07496 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
07497 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
07498 msg_cfg = ast_config_load(filename, config_flags);
07499 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
07500 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07501 return 0;
07502 }
07503 flag = ast_variable_retrieve(msg_cfg, "message", "flag");
07504
07505
07506 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
07507 res = wait_file2(chan, vms, "vm-Urgent");
07508 }
07509
07510 if (!res) {
07511
07512
07513 if (!strncasecmp(chan->language, "pl", 2)) {
07514 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07515 int ten, one;
07516 char nextmsg[256];
07517 ten = (vms->curmsg + 1) / 10;
07518 one = (vms->curmsg + 1) % 10;
07519
07520 if (vms->curmsg < 20) {
07521 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
07522 res = wait_file2(chan, vms, nextmsg);
07523 } else {
07524 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
07525 res = wait_file2(chan, vms, nextmsg);
07526 if (one > 0) {
07527 if (!res) {
07528 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
07529 res = wait_file2(chan, vms, nextmsg);
07530 }
07531 }
07532 }
07533 }
07534 if (!res)
07535 res = wait_file2(chan, vms, "vm-message");
07536
07537 } else if (!strncasecmp(chan->language, "he", 2)) {
07538 if (!vms->curmsg) {
07539 res = wait_file2(chan, vms, "vm-message");
07540 res = wait_file2(chan, vms, "vm-first");
07541 } else if (vms->curmsg == vms->lastmsg) {
07542 res = wait_file2(chan, vms, "vm-message");
07543 res = wait_file2(chan, vms, "vm-last");
07544 } else {
07545 res = wait_file2(chan, vms, "vm-message");
07546 res = wait_file2(chan, vms, "vm-number");
07547 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07548 }
07549
07550 } else if (!strncasecmp(chan->language, "vi", 2)) {
07551 if (!vms->curmsg) {
07552 res = wait_file2(chan, vms, "vm-message");
07553 res = wait_file2(chan, vms, "vm-first");
07554 } else if (vms->curmsg == vms->lastmsg) {
07555 res = wait_file2(chan, vms, "vm-message");
07556 res = wait_file2(chan, vms, "vm-last");
07557 } else {
07558 res = wait_file2(chan, vms, "vm-message");
07559 res = wait_file2(chan, vms, "vm-number");
07560 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07561 }
07562 } else {
07563 if (!strncasecmp(chan->language, "se", 2)) {
07564 res = wait_file2(chan, vms, "vm-meddelandet");
07565 } else {
07566 res = wait_file2(chan, vms, "vm-message");
07567 }
07568 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07569 if (!res) {
07570 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
07571 }
07572 }
07573 }
07574 }
07575
07576 if (!msg_cfg) {
07577 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07578 return 0;
07579 }
07580
07581 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
07582 ast_log(AST_LOG_WARNING, "No origtime?!\n");
07583 DISPOSE(vms->curdir, vms->curmsg);
07584 ast_config_destroy(msg_cfg);
07585 return 0;
07586 }
07587
07588 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
07589 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
07590 category = ast_variable_retrieve(msg_cfg, "message", "category");
07591
07592 context = ast_variable_retrieve(msg_cfg, "message", "context");
07593 if (!strncasecmp("macro", context, 5))
07594 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
07595 if (!res) {
07596 res = play_message_category(chan, category);
07597 }
07598 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE)))
07599 res = play_message_datetime(chan, vmu, origtime, filename);
07600 if ((!res) && (ast_test_flag(vmu, VM_SAYCID)))
07601 res = play_message_callerid(chan, vms, cid, context, 0);
07602 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION)))
07603 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
07604
07605 if (res == '1')
07606 res = 0;
07607 ast_config_destroy(msg_cfg);
07608
07609 if (!res) {
07610 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07611 vms->heard[vms->curmsg] = 1;
07612 #ifdef IMAP_STORAGE
07613
07614
07615
07616 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
07617 wait_file(chan, vms, vms->introfn);
07618 }
07619 #endif
07620 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
07621 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
07622 res = 0;
07623 }
07624 }
07625 DISPOSE(vms->curdir, vms->curmsg);
07626 return res;
07627 }
07628
07629 #ifdef IMAP_STORAGE
07630 static int imap_remove_file(char *dir, int msgnum)
07631 {
07632 char fn[PATH_MAX];
07633 char full_fn[PATH_MAX];
07634 char intro[PATH_MAX] = {0,};
07635
07636 if (msgnum > -1) {
07637 make_file(fn, sizeof(fn), dir, msgnum);
07638 snprintf(intro, sizeof(intro), "%sintro", fn);
07639 } else
07640 ast_copy_string(fn, dir, sizeof(fn));
07641
07642 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
07643 ast_filedelete(fn, NULL);
07644 if (!ast_strlen_zero(intro)) {
07645 ast_filedelete(intro, NULL);
07646 }
07647 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
07648 unlink(full_fn);
07649 }
07650 return 0;
07651 }
07652
07653
07654
07655 static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
07656 {
07657 char *file, *filename;
07658 char *attachment;
07659 char arg[10];
07660 int i;
07661 BODY* body;
07662
07663 file = strrchr(ast_strdupa(dir), '/');
07664 if (file) {
07665 *file++ = '\0';
07666 } else {
07667 ast_log(AST_LOG_ERROR, "Failed to procure file name from directory passed. You should never see this.\n");
07668 return -1;
07669 }
07670
07671 ast_mutex_lock(&vms->lock);
07672 for (i = 0; i < vms->mailstream->nmsgs; i++) {
07673 mail_fetchstructure(vms->mailstream, i + 1, &body);
07674
07675 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
07676 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
07677 } else {
07678 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
07679 ast_mutex_unlock(&vms->lock);
07680 return -1;
07681 }
07682 filename = strsep(&attachment, ".");
07683 if (!strcmp(filename, file)) {
07684 sprintf(arg, "%d", i + 1);
07685 mail_setflag(vms->mailstream, arg, "\\DELETED");
07686 }
07687 }
07688 mail_expunge(vms->mailstream);
07689 ast_mutex_unlock(&vms->lock);
07690 return 0;
07691 }
07692
07693 #elif !defined(IMAP_STORAGE)
07694 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
07695 {
07696 int count_msg, last_msg;
07697
07698 ast_copy_string(vms->curbox, mbox(vmu, box), sizeof(vms->curbox));
07699
07700
07701
07702
07703 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
07704
07705
07706 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
07707
07708
07709 count_msg = count_messages(vmu, vms->curdir);
07710 if (count_msg < 0) {
07711 return count_msg;
07712 } else {
07713 vms->lastmsg = count_msg - 1;
07714 }
07715
07716 if (vm_allocate_dh(vms, vmu, count_msg)) {
07717 return -1;
07718 }
07719
07720
07721
07722
07723
07724
07725
07726
07727 if (vm_lock_path(vms->curdir)) {
07728 ast_log(AST_LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
07729 return ERROR_LOCK_PATH;
07730 }
07731
07732
07733 last_msg = last_message_index(vmu, vms->curdir);
07734 ast_unlock_path(vms->curdir);
07735
07736 if (last_msg < -1) {
07737 return last_msg;
07738 } else if (vms->lastmsg != last_msg) {
07739 ast_log(LOG_NOTICE, "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);
07740 }
07741
07742 return 0;
07743 }
07744 #endif
07745
07746 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
07747 {
07748 int x = 0;
07749 #ifndef IMAP_STORAGE
07750 int res = 0, nummsg;
07751 char fn2[PATH_MAX];
07752 #endif
07753
07754 if (vms->lastmsg <= -1) {
07755 goto done;
07756 }
07757
07758 vms->curmsg = -1;
07759 #ifndef IMAP_STORAGE
07760
07761 if (vm_lock_path(vms->curdir)) {
07762 return ERROR_LOCK_PATH;
07763 }
07764
07765
07766 for (x = 0; x < vms->lastmsg + 1; x++) {
07767 if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
07768
07769 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07770 if (!EXISTS(vms->curdir, x, vms->fn, NULL)) {
07771 break;
07772 }
07773 vms->curmsg++;
07774 make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
07775 if (strcmp(vms->fn, fn2)) {
07776 RENAME(vms->curdir, x, vmu->mailbox, vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
07777 }
07778 } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
07779
07780 res = save_to_folder(vmu, vms, x, 1);
07781 if (res == ERROR_LOCK_PATH) {
07782
07783 ast_log(AST_LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
07784 vms->deleted[x] = 0;
07785 vms->heard[x] = 0;
07786 --x;
07787 }
07788 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
07789
07790 res = save_to_folder(vmu, vms, x, 10);
07791 if (res == ERROR_LOCK_PATH) {
07792
07793 vms->deleted[x] = 0;
07794 vms->heard[x] = 0;
07795 --x;
07796 }
07797 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
07798
07799
07800 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07801 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
07802 DELETE(vms->curdir, x, vms->fn, vmu);
07803 }
07804 }
07805 }
07806
07807
07808 nummsg = x - 1;
07809 for (x = vms->curmsg + 1; x <= nummsg; x++) {
07810 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07811 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
07812 DELETE(vms->curdir, x, vms->fn, vmu);
07813 }
07814 }
07815 ast_unlock_path(vms->curdir);
07816 #else
07817 if (vms->deleted) {
07818
07819
07820 for (x = vms->dh_arraysize - 1; x >= 0; x--) {
07821 if (vms->deleted[x]) {
07822 ast_debug(3, "IMAP delete of %d\n", x);
07823 DELETE(vms->curdir, x, vms->fn, vmu);
07824 }
07825 }
07826 }
07827 #endif
07828
07829 done:
07830 if (vms->deleted && vmu->maxmsg) {
07831 memset(vms->deleted, 0, vms->dh_arraysize * sizeof(int));
07832 }
07833 if (vms->heard && vmu->maxmsg) {
07834 memset(vms->heard, 0, vms->dh_arraysize * sizeof(int));
07835 }
07836
07837 return 0;
07838 }
07839
07840
07841
07842
07843
07844
07845
07846 static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
07847 {
07848 int cmd;
07849 char *buf;
07850
07851 buf = alloca(strlen(box) + 2);
07852 strcpy(buf, box);
07853 strcat(buf, "s");
07854
07855 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
07856 cmd = ast_play_and_wait(chan, buf);
07857 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
07858 } else {
07859 cmd = ast_play_and_wait(chan, "vm-messages");
07860 return cmd ? cmd : ast_play_and_wait(chan, box);
07861 }
07862 }
07863
07864 static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
07865 {
07866 int cmd;
07867
07868 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
07869 if (!strcasecmp(box, "vm-INBOX"))
07870 cmd = ast_play_and_wait(chan, "vm-new-e");
07871 else
07872 cmd = ast_play_and_wait(chan, "vm-old-e");
07873 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
07874 } else {
07875 cmd = ast_play_and_wait(chan, "vm-messages");
07876 return cmd ? cmd : ast_play_and_wait(chan, box);
07877 }
07878 }
07879
07880 static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
07881 {
07882 int cmd;
07883
07884 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
07885 cmd = ast_play_and_wait(chan, "vm-messages");
07886 return cmd ? cmd : ast_play_and_wait(chan, box);
07887 } else {
07888 cmd = ast_play_and_wait(chan, box);
07889 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
07890 }
07891 }
07892
07893 static int vm_play_folder_name(struct ast_channel *chan, char *box)
07894 {
07895 int cmd;
07896
07897 if ( !strncasecmp(chan->language, "it", 2) ||
07898 !strncasecmp(chan->language, "es", 2) ||
07899 !strncasecmp(chan->language, "pt", 2)) {
07900 cmd = ast_play_and_wait(chan, "vm-messages");
07901 return cmd ? cmd : ast_play_and_wait(chan, box);
07902 } else if (!strncasecmp(chan->language, "gr", 2)) {
07903 return vm_play_folder_name_gr(chan, box);
07904 } else if (!strncasecmp(chan->language, "he", 2)) {
07905 return ast_play_and_wait(chan, box);
07906 } else if (!strncasecmp(chan->language, "pl", 2)) {
07907 return vm_play_folder_name_pl(chan, box);
07908 } else if (!strncasecmp(chan->language, "ua", 2)) {
07909 return vm_play_folder_name_ua(chan, box);
07910 } else if (!strncasecmp(chan->language, "vi", 2)) {
07911 return ast_play_and_wait(chan, box);
07912 } else {
07913 cmd = ast_play_and_wait(chan, box);
07914 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
07915 }
07916 }
07917
07918
07919
07920
07921
07922
07923
07924
07925
07926
07927
07928
07929
07930 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
07931 {
07932 int res = 0;
07933
07934 if (vms->newmessages) {
07935 res = ast_play_and_wait(chan, "vm-youhave");
07936 if (!res)
07937 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
07938 if (!res) {
07939 if ((vms->newmessages == 1)) {
07940 res = ast_play_and_wait(chan, "vm-INBOX");
07941 if (!res)
07942 res = ast_play_and_wait(chan, "vm-message");
07943 } else {
07944 res = ast_play_and_wait(chan, "vm-INBOXs");
07945 if (!res)
07946 res = ast_play_and_wait(chan, "vm-messages");
07947 }
07948 }
07949 } else if (vms->oldmessages){
07950 res = ast_play_and_wait(chan, "vm-youhave");
07951 if (!res)
07952 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
07953 if ((vms->oldmessages == 1)){
07954 res = ast_play_and_wait(chan, "vm-Old");
07955 if (!res)
07956 res = ast_play_and_wait(chan, "vm-message");
07957 } else {
07958 res = ast_play_and_wait(chan, "vm-Olds");
07959 if (!res)
07960 res = ast_play_and_wait(chan, "vm-messages");
07961 }
07962 } else if (!vms->oldmessages && !vms->newmessages)
07963 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
07964 return res;
07965 }
07966
07967
07968
07969
07970
07971
07972
07973
07974
07975
07976
07977
07978
07979
07980
07981
07982
07983
07984
07985
07986
07987
07988
07989
07990
07991
07992
07993
07994
07995
07996
07997
07998
07999
08000
08001
08002
08003
08004
08005
08006
08007
08008
08009
08010
08011
08012
08013
08014
08015
08016
08017
08018
08019
08020
08021
08022
08023
08024 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
08025 {
08026 int res;
08027 int lastnum = 0;
08028
08029 res = ast_play_and_wait(chan, "vm-youhave");
08030
08031 if (!res && vms->newmessages) {
08032 lastnum = vms->newmessages;
08033
08034 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08035 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
08036 }
08037
08038 if (!res && vms->oldmessages) {
08039 res = ast_play_and_wait(chan, "vm-and");
08040 }
08041 }
08042
08043 if (!res && vms->oldmessages) {
08044 lastnum = vms->oldmessages;
08045
08046 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08047 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
08048 }
08049 }
08050
08051 if (!res) {
08052 if (lastnum == 0) {
08053 res = ast_play_and_wait(chan, "vm-no");
08054 }
08055 if (!res) {
08056 res = ast_say_counted_noun(chan, lastnum, "vm-message");
08057 }
08058 }
08059
08060 return res;
08061 }
08062
08063
08064 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
08065 {
08066 int res = 0;
08067
08068
08069 if (!res) {
08070 if ((vms->newmessages) || (vms->oldmessages)) {
08071 res = ast_play_and_wait(chan, "vm-youhave");
08072 }
08073
08074
08075
08076
08077
08078 if (vms->newmessages) {
08079 if (!res) {
08080 if (vms->newmessages == 1) {
08081 res = ast_play_and_wait(chan, "vm-INBOX1");
08082 } else {
08083 if (vms->newmessages == 2) {
08084 res = ast_play_and_wait(chan, "vm-shtei");
08085 } else {
08086 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08087 }
08088 res = ast_play_and_wait(chan, "vm-INBOX");
08089 }
08090 }
08091 if (vms->oldmessages && !res) {
08092 res = ast_play_and_wait(chan, "vm-and");
08093 if (vms->oldmessages == 1) {
08094 res = ast_play_and_wait(chan, "vm-Old1");
08095 } else {
08096 if (vms->oldmessages == 2) {
08097 res = ast_play_and_wait(chan, "vm-shtei");
08098 } else {
08099 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08100 }
08101 res = ast_play_and_wait(chan, "vm-Old");
08102 }
08103 }
08104 }
08105 if (!res && vms->oldmessages && !vms->newmessages) {
08106 if (!res) {
08107 if (vms->oldmessages == 1) {
08108 res = ast_play_and_wait(chan, "vm-Old1");
08109 } else {
08110 if (vms->oldmessages == 2) {
08111 res = ast_play_and_wait(chan, "vm-shtei");
08112 } else {
08113 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08114 }
08115 res = ast_play_and_wait(chan, "vm-Old");
08116 }
08117 }
08118 }
08119 if (!res) {
08120 if (!vms->oldmessages && !vms->newmessages) {
08121 if (!res) {
08122 res = ast_play_and_wait(chan, "vm-nomessages");
08123 }
08124 }
08125 }
08126 }
08127 return res;
08128 }
08129
08130
08131 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
08132 {
08133 int res;
08134
08135
08136 res = ast_play_and_wait(chan, "vm-youhave");
08137 if (!res) {
08138 if (vms->urgentmessages) {
08139 res = say_and_wait(chan, vms->urgentmessages, chan->language);
08140 if (!res)
08141 res = ast_play_and_wait(chan, "vm-Urgent");
08142 if ((vms->oldmessages || vms->newmessages) && !res) {
08143 res = ast_play_and_wait(chan, "vm-and");
08144 } else if (!res) {
08145 if ((vms->urgentmessages == 1))
08146 res = ast_play_and_wait(chan, "vm-message");
08147 else
08148 res = ast_play_and_wait(chan, "vm-messages");
08149 }
08150 }
08151 if (vms->newmessages) {
08152 res = say_and_wait(chan, vms->newmessages, chan->language);
08153 if (!res)
08154 res = ast_play_and_wait(chan, "vm-INBOX");
08155 if (vms->oldmessages && !res)
08156 res = ast_play_and_wait(chan, "vm-and");
08157 else if (!res) {
08158 if ((vms->newmessages == 1))
08159 res = ast_play_and_wait(chan, "vm-message");
08160 else
08161 res = ast_play_and_wait(chan, "vm-messages");
08162 }
08163
08164 }
08165 if (!res && vms->oldmessages) {
08166 res = say_and_wait(chan, vms->oldmessages, chan->language);
08167 if (!res)
08168 res = ast_play_and_wait(chan, "vm-Old");
08169 if (!res) {
08170 if (vms->oldmessages == 1)
08171 res = ast_play_and_wait(chan, "vm-message");
08172 else
08173 res = ast_play_and_wait(chan, "vm-messages");
08174 }
08175 }
08176 if (!res) {
08177 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
08178 res = ast_play_and_wait(chan, "vm-no");
08179 if (!res)
08180 res = ast_play_and_wait(chan, "vm-messages");
08181 }
08182 }
08183 }
08184 return res;
08185 }
08186
08187
08188 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
08189 {
08190
08191 int res;
08192 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
08193 res = ast_play_and_wait(chan, "vm-no") ||
08194 ast_play_and_wait(chan, "vm-message");
08195 else
08196 res = ast_play_and_wait(chan, "vm-youhave");
08197 if (!res && vms->newmessages) {
08198 res = (vms->newmessages == 1) ?
08199 ast_play_and_wait(chan, "digits/un") ||
08200 ast_play_and_wait(chan, "vm-nuovo") ||
08201 ast_play_and_wait(chan, "vm-message") :
08202
08203 say_and_wait(chan, vms->newmessages, chan->language) ||
08204 ast_play_and_wait(chan, "vm-nuovi") ||
08205 ast_play_and_wait(chan, "vm-messages");
08206 if (!res && vms->oldmessages)
08207 res = ast_play_and_wait(chan, "vm-and");
08208 }
08209 if (!res && vms->oldmessages) {
08210 res = (vms->oldmessages == 1) ?
08211 ast_play_and_wait(chan, "digits/un") ||
08212 ast_play_and_wait(chan, "vm-vecchio") ||
08213 ast_play_and_wait(chan, "vm-message") :
08214
08215 say_and_wait(chan, vms->oldmessages, chan->language) ||
08216 ast_play_and_wait(chan, "vm-vecchi") ||
08217 ast_play_and_wait(chan, "vm-messages");
08218 }
08219 return res;
08220 }
08221
08222
08223 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
08224 {
08225
08226 int res;
08227 div_t num;
08228
08229 if (!vms->oldmessages && !vms->newmessages) {
08230 res = ast_play_and_wait(chan, "vm-no");
08231 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08232 return res;
08233 } else {
08234 res = ast_play_and_wait(chan, "vm-youhave");
08235 }
08236
08237 if (vms->newmessages) {
08238 num = div(vms->newmessages, 10);
08239 if (vms->newmessages == 1) {
08240 res = ast_play_and_wait(chan, "digits/1-a");
08241 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
08242 res = res ? res : ast_play_and_wait(chan, "vm-message");
08243 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08244 if (num.rem == 2) {
08245 if (!num.quot) {
08246 res = ast_play_and_wait(chan, "digits/2-ie");
08247 } else {
08248 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
08249 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08250 }
08251 } else {
08252 res = say_and_wait(chan, vms->newmessages, chan->language);
08253 }
08254 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
08255 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08256 } else {
08257 res = say_and_wait(chan, vms->newmessages, chan->language);
08258 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
08259 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08260 }
08261 if (!res && vms->oldmessages)
08262 res = ast_play_and_wait(chan, "vm-and");
08263 }
08264 if (!res && vms->oldmessages) {
08265 num = div(vms->oldmessages, 10);
08266 if (vms->oldmessages == 1) {
08267 res = ast_play_and_wait(chan, "digits/1-a");
08268 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
08269 res = res ? res : ast_play_and_wait(chan, "vm-message");
08270 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08271 if (num.rem == 2) {
08272 if (!num.quot) {
08273 res = ast_play_and_wait(chan, "digits/2-ie");
08274 } else {
08275 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
08276 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08277 }
08278 } else {
08279 res = say_and_wait(chan, vms->oldmessages, chan->language);
08280 }
08281 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
08282 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08283 } else {
08284 res = say_and_wait(chan, vms->oldmessages, chan->language);
08285 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
08286 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08287 }
08288 }
08289
08290 return res;
08291 }
08292
08293
08294 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
08295 {
08296
08297 int res;
08298
08299 res = ast_play_and_wait(chan, "vm-youhave");
08300 if (res)
08301 return res;
08302
08303 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08304 res = ast_play_and_wait(chan, "vm-no");
08305 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08306 return res;
08307 }
08308
08309 if (vms->newmessages) {
08310 if ((vms->newmessages == 1)) {
08311 res = ast_play_and_wait(chan, "digits/ett");
08312 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
08313 res = res ? res : ast_play_and_wait(chan, "vm-message");
08314 } else {
08315 res = say_and_wait(chan, vms->newmessages, chan->language);
08316 res = res ? res : ast_play_and_wait(chan, "vm-nya");
08317 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08318 }
08319 if (!res && vms->oldmessages)
08320 res = ast_play_and_wait(chan, "vm-and");
08321 }
08322 if (!res && vms->oldmessages) {
08323 if (vms->oldmessages == 1) {
08324 res = ast_play_and_wait(chan, "digits/ett");
08325 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
08326 res = res ? res : ast_play_and_wait(chan, "vm-message");
08327 } else {
08328 res = say_and_wait(chan, vms->oldmessages, chan->language);
08329 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
08330 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08331 }
08332 }
08333
08334 return res;
08335 }
08336
08337
08338 static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
08339 {
08340
08341 int res;
08342
08343 res = ast_play_and_wait(chan, "vm-youhave");
08344 if (res)
08345 return res;
08346
08347 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08348 res = ast_play_and_wait(chan, "vm-no");
08349 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08350 return res;
08351 }
08352
08353 if (vms->newmessages) {
08354 if ((vms->newmessages == 1)) {
08355 res = ast_play_and_wait(chan, "digits/1");
08356 res = res ? res : ast_play_and_wait(chan, "vm-ny");
08357 res = res ? res : ast_play_and_wait(chan, "vm-message");
08358 } else {
08359 res = say_and_wait(chan, vms->newmessages, chan->language);
08360 res = res ? res : ast_play_and_wait(chan, "vm-nye");
08361 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08362 }
08363 if (!res && vms->oldmessages)
08364 res = ast_play_and_wait(chan, "vm-and");
08365 }
08366 if (!res && vms->oldmessages) {
08367 if (vms->oldmessages == 1) {
08368 res = ast_play_and_wait(chan, "digits/1");
08369 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
08370 res = res ? res : ast_play_and_wait(chan, "vm-message");
08371 } else {
08372 res = say_and_wait(chan, vms->oldmessages, chan->language);
08373 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
08374 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08375 }
08376 }
08377
08378 return res;
08379 }
08380
08381
08382 static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
08383 {
08384
08385 int res;
08386 res = ast_play_and_wait(chan, "vm-youhave");
08387 if (!res) {
08388 if (vms->newmessages) {
08389 if ((vms->newmessages == 1))
08390 res = ast_play_and_wait(chan, "digits/1F");
08391 else
08392 res = say_and_wait(chan, vms->newmessages, chan->language);
08393 if (!res)
08394 res = ast_play_and_wait(chan, "vm-INBOX");
08395 if (vms->oldmessages && !res)
08396 res = ast_play_and_wait(chan, "vm-and");
08397 else if (!res) {
08398 if ((vms->newmessages == 1))
08399 res = ast_play_and_wait(chan, "vm-message");
08400 else
08401 res = ast_play_and_wait(chan, "vm-messages");
08402 }
08403
08404 }
08405 if (!res && vms->oldmessages) {
08406 if (vms->oldmessages == 1)
08407 res = ast_play_and_wait(chan, "digits/1F");
08408 else
08409 res = say_and_wait(chan, vms->oldmessages, chan->language);
08410 if (!res)
08411 res = ast_play_and_wait(chan, "vm-Old");
08412 if (!res) {
08413 if (vms->oldmessages == 1)
08414 res = ast_play_and_wait(chan, "vm-message");
08415 else
08416 res = ast_play_and_wait(chan, "vm-messages");
08417 }
08418 }
08419 if (!res) {
08420 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08421 res = ast_play_and_wait(chan, "vm-no");
08422 if (!res)
08423 res = ast_play_and_wait(chan, "vm-messages");
08424 }
08425 }
08426 }
08427 return res;
08428 }
08429
08430
08431 static int vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
08432 {
08433
08434 int res;
08435 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08436 res = ast_play_and_wait(chan, "vm-youhaveno");
08437 if (!res)
08438 res = ast_play_and_wait(chan, "vm-messages");
08439 } else {
08440 res = ast_play_and_wait(chan, "vm-youhave");
08441 }
08442 if (!res) {
08443 if (vms->newmessages) {
08444 if (!res) {
08445 if ((vms->newmessages == 1)) {
08446 res = ast_play_and_wait(chan, "digits/1M");
08447 if (!res)
08448 res = ast_play_and_wait(chan, "vm-message");
08449 if (!res)
08450 res = ast_play_and_wait(chan, "vm-INBOXs");
08451 } else {
08452 res = say_and_wait(chan, vms->newmessages, chan->language);
08453 if (!res)
08454 res = ast_play_and_wait(chan, "vm-messages");
08455 if (!res)
08456 res = ast_play_and_wait(chan, "vm-INBOX");
08457 }
08458 }
08459 if (vms->oldmessages && !res)
08460 res = ast_play_and_wait(chan, "vm-and");
08461 }
08462 if (vms->oldmessages) {
08463 if (!res) {
08464 if (vms->oldmessages == 1) {
08465 res = ast_play_and_wait(chan, "digits/1M");
08466 if (!res)
08467 res = ast_play_and_wait(chan, "vm-message");
08468 if (!res)
08469 res = ast_play_and_wait(chan, "vm-Olds");
08470 } else {
08471 res = say_and_wait(chan, vms->oldmessages, chan->language);
08472 if (!res)
08473 res = ast_play_and_wait(chan, "vm-messages");
08474 if (!res)
08475 res = ast_play_and_wait(chan, "vm-Old");
08476 }
08477 }
08478 }
08479 }
08480 return res;
08481 }
08482
08483
08484 static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms) {
08485
08486 int res;
08487 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08488 res = ast_play_and_wait(chan, "vm-nomessages");
08489 return res;
08490 } else {
08491 res = ast_play_and_wait(chan, "vm-youhave");
08492 }
08493 if (vms->newmessages) {
08494 if (!res)
08495 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08496 if ((vms->newmessages == 1)) {
08497 if (!res)
08498 res = ast_play_and_wait(chan, "vm-message");
08499 if (!res)
08500 res = ast_play_and_wait(chan, "vm-INBOXs");
08501 } else {
08502 if (!res)
08503 res = ast_play_and_wait(chan, "vm-messages");
08504 if (!res)
08505 res = ast_play_and_wait(chan, "vm-INBOX");
08506 }
08507 if (vms->oldmessages && !res)
08508 res = ast_play_and_wait(chan, "vm-and");
08509 }
08510 if (vms->oldmessages) {
08511 if (!res)
08512 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08513 if (vms->oldmessages == 1) {
08514 if (!res)
08515 res = ast_play_and_wait(chan, "vm-message");
08516 if (!res)
08517 res = ast_play_and_wait(chan, "vm-Olds");
08518 } else {
08519 if (!res)
08520 res = ast_play_and_wait(chan, "vm-messages");
08521 if (!res)
08522 res = ast_play_and_wait(chan, "vm-Old");
08523 }
08524 }
08525 return res;
08526 }
08527
08528
08529 static int vm_intro_fr(struct ast_channel *chan, struct vm_state *vms)
08530 {
08531
08532 int res;
08533 res = ast_play_and_wait(chan, "vm-youhave");
08534 if (!res) {
08535 if (vms->newmessages) {
08536 res = say_and_wait(chan, vms->newmessages, chan->language);
08537 if (!res)
08538 res = ast_play_and_wait(chan, "vm-INBOX");
08539 if (vms->oldmessages && !res)
08540 res = ast_play_and_wait(chan, "vm-and");
08541 else if (!res) {
08542 if ((vms->newmessages == 1))
08543 res = ast_play_and_wait(chan, "vm-message");
08544 else
08545 res = ast_play_and_wait(chan, "vm-messages");
08546 }
08547
08548 }
08549 if (!res && vms->oldmessages) {
08550 res = say_and_wait(chan, vms->oldmessages, chan->language);
08551 if (!res)
08552 res = ast_play_and_wait(chan, "vm-Old");
08553 if (!res) {
08554 if (vms->oldmessages == 1)
08555 res = ast_play_and_wait(chan, "vm-message");
08556 else
08557 res = ast_play_and_wait(chan, "vm-messages");
08558 }
08559 }
08560 if (!res) {
08561 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08562 res = ast_play_and_wait(chan, "vm-no");
08563 if (!res)
08564 res = ast_play_and_wait(chan, "vm-messages");
08565 }
08566 }
08567 }
08568 return res;
08569 }
08570
08571
08572 static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
08573 {
08574
08575 int res;
08576 res = ast_play_and_wait(chan, "vm-youhave");
08577 if (!res) {
08578 if (vms->newmessages) {
08579 res = say_and_wait(chan, vms->newmessages, chan->language);
08580 if (!res) {
08581 if (vms->newmessages == 1)
08582 res = ast_play_and_wait(chan, "vm-INBOXs");
08583 else
08584 res = ast_play_and_wait(chan, "vm-INBOX");
08585 }
08586 if (vms->oldmessages && !res)
08587 res = ast_play_and_wait(chan, "vm-and");
08588 else if (!res) {
08589 if ((vms->newmessages == 1))
08590 res = ast_play_and_wait(chan, "vm-message");
08591 else
08592 res = ast_play_and_wait(chan, "vm-messages");
08593 }
08594
08595 }
08596 if (!res && vms->oldmessages) {
08597 res = say_and_wait(chan, vms->oldmessages, chan->language);
08598 if (!res) {
08599 if (vms->oldmessages == 1)
08600 res = ast_play_and_wait(chan, "vm-Olds");
08601 else
08602 res = ast_play_and_wait(chan, "vm-Old");
08603 }
08604 if (!res) {
08605 if (vms->oldmessages == 1)
08606 res = ast_play_and_wait(chan, "vm-message");
08607 else
08608 res = ast_play_and_wait(chan, "vm-messages");
08609 }
08610 }
08611 if (!res) {
08612 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08613 res = ast_play_and_wait(chan, "vm-no");
08614 if (!res)
08615 res = ast_play_and_wait(chan, "vm-messages");
08616 }
08617 }
08618 }
08619 return res;
08620 }
08621
08622
08623 static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
08624 {
08625
08626 int res;
08627 res = ast_play_and_wait(chan, "vm-youhave");
08628 if (!res) {
08629 if (vms->newmessages) {
08630 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08631 if (!res) {
08632 if ((vms->newmessages == 1)) {
08633 res = ast_play_and_wait(chan, "vm-message");
08634 if (!res)
08635 res = ast_play_and_wait(chan, "vm-INBOXs");
08636 } else {
08637 res = ast_play_and_wait(chan, "vm-messages");
08638 if (!res)
08639 res = ast_play_and_wait(chan, "vm-INBOX");
08640 }
08641 }
08642 if (vms->oldmessages && !res)
08643 res = ast_play_and_wait(chan, "vm-and");
08644 }
08645 if (!res && vms->oldmessages) {
08646 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08647 if (!res) {
08648 if (vms->oldmessages == 1) {
08649 res = ast_play_and_wait(chan, "vm-message");
08650 if (!res)
08651 res = ast_play_and_wait(chan, "vm-Olds");
08652 } else {
08653 res = ast_play_and_wait(chan, "vm-messages");
08654 if (!res)
08655 res = ast_play_and_wait(chan, "vm-Old");
08656 }
08657 }
08658 }
08659 if (!res) {
08660 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08661 res = ast_play_and_wait(chan, "vm-no");
08662 if (!res)
08663 res = ast_play_and_wait(chan, "vm-messages");
08664 }
08665 }
08666 }
08667 return res;
08668 }
08669
08670
08671
08672
08673
08674
08675
08676
08677
08678
08679
08680
08681
08682
08683
08684
08685
08686 static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
08687 {
08688 int res;
08689 res = ast_play_and_wait(chan, "vm-youhave");
08690 if (!res) {
08691 if (vms->newmessages) {
08692 if (vms->newmessages == 1) {
08693 res = ast_play_and_wait(chan, "digits/jednu");
08694 } else {
08695 res = say_and_wait(chan, vms->newmessages, chan->language);
08696 }
08697 if (!res) {
08698 if ((vms->newmessages == 1))
08699 res = ast_play_and_wait(chan, "vm-novou");
08700 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08701 res = ast_play_and_wait(chan, "vm-nove");
08702 if (vms->newmessages > 4)
08703 res = ast_play_and_wait(chan, "vm-novych");
08704 }
08705 if (vms->oldmessages && !res)
08706 res = ast_play_and_wait(chan, "vm-and");
08707 else if (!res) {
08708 if ((vms->newmessages == 1))
08709 res = ast_play_and_wait(chan, "vm-zpravu");
08710 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08711 res = ast_play_and_wait(chan, "vm-zpravy");
08712 if (vms->newmessages > 4)
08713 res = ast_play_and_wait(chan, "vm-zprav");
08714 }
08715 }
08716 if (!res && vms->oldmessages) {
08717 res = say_and_wait(chan, vms->oldmessages, chan->language);
08718 if (!res) {
08719 if ((vms->oldmessages == 1))
08720 res = ast_play_and_wait(chan, "vm-starou");
08721 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08722 res = ast_play_and_wait(chan, "vm-stare");
08723 if (vms->oldmessages > 4)
08724 res = ast_play_and_wait(chan, "vm-starych");
08725 }
08726 if (!res) {
08727 if ((vms->oldmessages == 1))
08728 res = ast_play_and_wait(chan, "vm-zpravu");
08729 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08730 res = ast_play_and_wait(chan, "vm-zpravy");
08731 if (vms->oldmessages > 4)
08732 res = ast_play_and_wait(chan, "vm-zprav");
08733 }
08734 }
08735 if (!res) {
08736 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08737 res = ast_play_and_wait(chan, "vm-no");
08738 if (!res)
08739 res = ast_play_and_wait(chan, "vm-zpravy");
08740 }
08741 }
08742 }
08743 return res;
08744 }
08745
08746
08747 static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
08748 {
08749 int res;
08750
08751 res = ast_play_and_wait(chan, "vm-you");
08752
08753 if (!res && vms->newmessages) {
08754 res = ast_play_and_wait(chan, "vm-have");
08755 if (!res)
08756 res = say_and_wait(chan, vms->newmessages, chan->language);
08757 if (!res)
08758 res = ast_play_and_wait(chan, "vm-tong");
08759 if (!res)
08760 res = ast_play_and_wait(chan, "vm-INBOX");
08761 if (vms->oldmessages && !res)
08762 res = ast_play_and_wait(chan, "vm-and");
08763 else if (!res)
08764 res = ast_play_and_wait(chan, "vm-messages");
08765 }
08766 if (!res && vms->oldmessages) {
08767 res = ast_play_and_wait(chan, "vm-have");
08768 if (!res)
08769 res = say_and_wait(chan, vms->oldmessages, chan->language);
08770 if (!res)
08771 res = ast_play_and_wait(chan, "vm-tong");
08772 if (!res)
08773 res = ast_play_and_wait(chan, "vm-Old");
08774 if (!res)
08775 res = ast_play_and_wait(chan, "vm-messages");
08776 }
08777 if (!res && !vms->oldmessages && !vms->newmessages) {
08778 res = ast_play_and_wait(chan, "vm-haveno");
08779 if (!res)
08780 res = ast_play_and_wait(chan, "vm-messages");
08781 }
08782 return res;
08783 }
08784
08785
08786 static int vm_intro_vi(struct ast_channel *chan, struct vm_state *vms)
08787 {
08788 int res;
08789
08790
08791 res = ast_play_and_wait(chan, "vm-youhave");
08792 if (!res) {
08793 if (vms->newmessages) {
08794 res = say_and_wait(chan, vms->newmessages, chan->language);
08795 if (!res)
08796 res = ast_play_and_wait(chan, "vm-INBOX");
08797 if (vms->oldmessages && !res)
08798 res = ast_play_and_wait(chan, "vm-and");
08799 }
08800 if (!res && vms->oldmessages) {
08801 res = say_and_wait(chan, vms->oldmessages, chan->language);
08802 if (!res)
08803 res = ast_play_and_wait(chan, "vm-Old");
08804 }
08805 if (!res) {
08806 if (!vms->oldmessages && !vms->newmessages) {
08807 res = ast_play_and_wait(chan, "vm-no");
08808 if (!res)
08809 res = ast_play_and_wait(chan, "vm-message");
08810 }
08811 }
08812 }
08813 return res;
08814 }
08815
08816 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
08817 {
08818 char prefile[256];
08819
08820
08821 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
08822 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
08823 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
08824 if (ast_fileexists(prefile, NULL, NULL) > 0) {
08825 ast_play_and_wait(chan, "vm-tempgreetactive");
08826 }
08827 DISPOSE(prefile, -1);
08828 }
08829
08830
08831 if (0) {
08832 return 0;
08833 } else if (!strncasecmp(chan->language, "cs", 2)) {
08834 return vm_intro_cs(chan, vms);
08835 } else if (!strncasecmp(chan->language, "cz", 2)) {
08836 static int deprecation_warning = 0;
08837 if (deprecation_warning++ % 10 == 0) {
08838 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
08839 }
08840 return vm_intro_cs(chan, vms);
08841 } else if (!strncasecmp(chan->language, "de", 2)) {
08842 return vm_intro_de(chan, vms);
08843 } else if (!strncasecmp(chan->language, "es", 2)) {
08844 return vm_intro_es(chan, vms);
08845 } else if (!strncasecmp(chan->language, "fr", 2)) {
08846 return vm_intro_fr(chan, vms);
08847 } else if (!strncasecmp(chan->language, "gr", 2)) {
08848 return vm_intro_gr(chan, vms);
08849 } else if (!strncasecmp(chan->language, "he", 2)) {
08850 return vm_intro_he(chan, vms);
08851 } else if (!strncasecmp(chan->language, "it", 2)) {
08852 return vm_intro_it(chan, vms);
08853 } else if (!strncasecmp(chan->language, "nl", 2)) {
08854 return vm_intro_nl(chan, vms);
08855 } else if (!strncasecmp(chan->language, "no", 2)) {
08856 return vm_intro_no(chan, vms);
08857 } else if (!strncasecmp(chan->language, "pl", 2)) {
08858 return vm_intro_pl(chan, vms);
08859 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
08860 return vm_intro_pt_BR(chan, vms);
08861 } else if (!strncasecmp(chan->language, "pt", 2)) {
08862 return vm_intro_pt(chan, vms);
08863 } else if (!strncasecmp(chan->language, "ru", 2)) {
08864 return vm_intro_multilang(chan, vms, "n");
08865 } else if (!strncasecmp(chan->language, "se", 2)) {
08866 return vm_intro_se(chan, vms);
08867 } else if (!strncasecmp(chan->language, "ua", 2)) {
08868 return vm_intro_multilang(chan, vms, "n");
08869 } else if (!strncasecmp(chan->language, "vi", 2)) {
08870 return vm_intro_vi(chan, vms);
08871 } else if (!strncasecmp(chan->language, "zh", 2)) {
08872 return vm_intro_zh(chan, vms);
08873 } else {
08874 return vm_intro_en(chan, vms);
08875 }
08876 }
08877
08878 static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
08879 {
08880 int res = 0;
08881
08882 while (!res) {
08883 if (vms->starting) {
08884 if (vms->lastmsg > -1) {
08885 if (skipadvanced)
08886 res = ast_play_and_wait(chan, "vm-onefor-full");
08887 else
08888 res = ast_play_and_wait(chan, "vm-onefor");
08889 if (!res)
08890 res = vm_play_folder_name(chan, vms->vmbox);
08891 }
08892 if (!res) {
08893 if (skipadvanced)
08894 res = ast_play_and_wait(chan, "vm-opts-full");
08895 else
08896 res = ast_play_and_wait(chan, "vm-opts");
08897 }
08898 } else {
08899
08900 if (skipadvanced) {
08901 res = ast_play_and_wait(chan, "vm-onefor-full");
08902 if (!res)
08903 res = vm_play_folder_name(chan, vms->vmbox);
08904 res = ast_play_and_wait(chan, "vm-opts-full");
08905 }
08906
08907
08908
08909
08910
08911
08912 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
08913 res = ast_play_and_wait(chan, "vm-prev");
08914 }
08915 if (!res && !skipadvanced)
08916 res = ast_play_and_wait(chan, "vm-advopts");
08917 if (!res)
08918 res = ast_play_and_wait(chan, "vm-repeat");
08919
08920
08921
08922
08923
08924
08925 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
08926 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
08927 res = ast_play_and_wait(chan, "vm-next");
08928 }
08929 if (!res) {
08930 if (!vms->deleted[vms->curmsg])
08931 res = ast_play_and_wait(chan, "vm-delete");
08932 else
08933 res = ast_play_and_wait(chan, "vm-undelete");
08934 if (!res)
08935 res = ast_play_and_wait(chan, "vm-toforward");
08936 if (!res)
08937 res = ast_play_and_wait(chan, "vm-savemessage");
08938 }
08939 }
08940 if (!res) {
08941 res = ast_play_and_wait(chan, "vm-helpexit");
08942 }
08943 if (!res)
08944 res = ast_waitfordigit(chan, 6000);
08945 if (!res) {
08946 vms->repeats++;
08947 if (vms->repeats > 2) {
08948 res = 't';
08949 }
08950 }
08951 }
08952 return res;
08953 }
08954
08955 static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
08956 {
08957 int res = 0;
08958
08959 while (!res) {
08960 if (vms->lastmsg > -1) {
08961 res = ast_play_and_wait(chan, "vm-listen");
08962 if (!res)
08963 res = vm_play_folder_name(chan, vms->vmbox);
08964 if (!res)
08965 res = ast_play_and_wait(chan, "press");
08966 if (!res)
08967 res = ast_play_and_wait(chan, "digits/1");
08968 }
08969 if (!res)
08970 res = ast_play_and_wait(chan, "vm-opts");
08971 if (!res) {
08972 vms->starting = 0;
08973 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
08974 }
08975 }
08976 return res;
08977 }
08978
08979 static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
08980 {
08981 if (vms->starting && !strncasecmp(chan->language, "zh", 2)) {
08982 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
08983 } else {
08984 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
08985 }
08986 }
08987
08988
08989 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
08990 {
08991 int cmd = 0;
08992 int duration = 0;
08993 int tries = 0;
08994 char newpassword[80] = "";
08995 char newpassword2[80] = "";
08996 char prefile[PATH_MAX] = "";
08997 unsigned char buf[256];
08998 int bytes = 0;
08999
09000 if (ast_adsi_available(chan)) {
09001 bytes += adsi_logo(buf + bytes);
09002 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
09003 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09004 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09005 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09006 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09007 }
09008
09009
09010
09011 for (;;) {
09012 newpassword[1] = '\0';
09013 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09014 if (cmd == '#')
09015 newpassword[0] = '\0';
09016 if (cmd < 0 || cmd == 't' || cmd == '#')
09017 return cmd;
09018 cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
09019 if (cmd < 0 || cmd == 't' || cmd == '#')
09020 return cmd;
09021 cmd = check_password(vmu, newpassword);
09022 if (cmd != 0) {
09023 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09024 cmd = ast_play_and_wait(chan, vm_invalid_password);
09025 } else {
09026 newpassword2[1] = '\0';
09027 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09028 if (cmd == '#')
09029 newpassword2[0] = '\0';
09030 if (cmd < 0 || cmd == 't' || cmd == '#')
09031 return cmd;
09032 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
09033 if (cmd < 0 || cmd == 't' || cmd == '#')
09034 return cmd;
09035 if (!strcmp(newpassword, newpassword2))
09036 break;
09037 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09038 cmd = ast_play_and_wait(chan, vm_mismatch);
09039 }
09040 if (++tries == 3)
09041 return -1;
09042 if (cmd != 0) {
09043 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09044 }
09045 }
09046 if (pwdchange & PWDCHANGE_INTERNAL)
09047 vm_change_password(vmu, newpassword);
09048 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
09049 vm_change_password_shell(vmu, newpassword);
09050
09051 ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int) strlen(newpassword));
09052 cmd = ast_play_and_wait(chan, vm_passchanged);
09053
09054
09055 if (ast_test_flag(vmu, VM_FORCENAME)) {
09056 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09057 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09058 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09059 if (cmd < 0 || cmd == 't' || cmd == '#')
09060 return cmd;
09061 }
09062 }
09063
09064
09065 if (ast_test_flag(vmu, VM_FORCEGREET)) {
09066 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09067 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09068 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09069 if (cmd < 0 || cmd == 't' || cmd == '#')
09070 return cmd;
09071 }
09072
09073 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09074 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09075 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09076 if (cmd < 0 || cmd == 't' || cmd == '#')
09077 return cmd;
09078 }
09079 }
09080
09081 return cmd;
09082 }
09083
09084 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09085 {
09086 int cmd = 0;
09087 int retries = 0;
09088 int duration = 0;
09089 char newpassword[80] = "";
09090 char newpassword2[80] = "";
09091 char prefile[PATH_MAX] = "";
09092 unsigned char buf[256];
09093 int bytes = 0;
09094
09095 if (ast_adsi_available(chan)) {
09096 bytes += adsi_logo(buf + bytes);
09097 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
09098 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09099 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09100 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09101 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09102 }
09103 while ((cmd >= 0) && (cmd != 't')) {
09104 if (cmd)
09105 retries = 0;
09106 switch (cmd) {
09107 case '1':
09108 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09109 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09110 break;
09111 case '2':
09112 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09113 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09114 break;
09115 case '3':
09116 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09117 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09118 break;
09119 case '4':
09120 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
09121 break;
09122 case '5':
09123 if (vmu->password[0] == '-') {
09124 cmd = ast_play_and_wait(chan, "vm-no");
09125 break;
09126 }
09127 newpassword[1] = '\0';
09128 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09129 if (cmd == '#')
09130 newpassword[0] = '\0';
09131 else {
09132 if (cmd < 0)
09133 break;
09134 if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
09135 break;
09136 }
09137 }
09138 cmd = check_password(vmu, newpassword);
09139 if (cmd != 0) {
09140 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09141 cmd = ast_play_and_wait(chan, vm_invalid_password);
09142 if (!cmd) {
09143 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09144 }
09145 break;
09146 }
09147 newpassword2[1] = '\0';
09148 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09149 if (cmd == '#')
09150 newpassword2[0] = '\0';
09151 else {
09152 if (cmd < 0)
09153 break;
09154
09155 if ((cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#")) < 0) {
09156 break;
09157 }
09158 }
09159 if (strcmp(newpassword, newpassword2)) {
09160 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09161 cmd = ast_play_and_wait(chan, vm_mismatch);
09162 if (!cmd) {
09163 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09164 }
09165 break;
09166 }
09167 if (pwdchange & PWDCHANGE_INTERNAL)
09168 vm_change_password(vmu, newpassword);
09169 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
09170 vm_change_password_shell(vmu, newpassword);
09171
09172 ast_debug(1, "User %s set password to %s of length %d\n",
09173 vms->username, newpassword, (int) strlen(newpassword));
09174 cmd = ast_play_and_wait(chan, vm_passchanged);
09175 break;
09176 case '*':
09177 cmd = 't';
09178 break;
09179 default:
09180 cmd = 0;
09181 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09182 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09183 if (ast_fileexists(prefile, NULL, NULL)) {
09184 cmd = ast_play_and_wait(chan, "vm-tmpexists");
09185 }
09186 DISPOSE(prefile, -1);
09187 if (!cmd) {
09188 cmd = ast_play_and_wait(chan, "vm-options");
09189 }
09190 if (!cmd) {
09191 cmd = ast_waitfordigit(chan, 6000);
09192 }
09193 if (!cmd) {
09194 retries++;
09195 }
09196 if (retries > 3) {
09197 cmd = 't';
09198 }
09199 }
09200 }
09201 if (cmd == 't')
09202 cmd = 0;
09203 return cmd;
09204 }
09205
09206
09207
09208
09209
09210
09211
09212
09213
09214
09215
09216
09217
09218
09219
09220
09221
09222 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09223 {
09224 int cmd = 0;
09225 int retries = 0;
09226 int duration = 0;
09227 char prefile[PATH_MAX] = "";
09228 unsigned char buf[256];
09229 int bytes = 0;
09230
09231 if (ast_adsi_available(chan)) {
09232 bytes += adsi_logo(buf + bytes);
09233 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
09234 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09235 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09236 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09237 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09238 }
09239
09240 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09241 while ((cmd >= 0) && (cmd != 't')) {
09242 if (cmd)
09243 retries = 0;
09244 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09245 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
09246 play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09247 cmd = 't';
09248 } else {
09249 switch (cmd) {
09250 case '1':
09251 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09252 break;
09253 case '2':
09254 DELETE(prefile, -1, prefile, vmu);
09255 ast_play_and_wait(chan, "vm-tempremoved");
09256 cmd = 't';
09257 break;
09258 case '*':
09259 cmd = 't';
09260 break;
09261 default:
09262 cmd = ast_play_and_wait(chan,
09263 ast_fileexists(prefile, NULL, NULL) > 0 ?
09264 "vm-tempgreeting2" : "vm-tempgreeting");
09265 if (!cmd)
09266 cmd = ast_waitfordigit(chan, 6000);
09267 if (!cmd)
09268 retries++;
09269 if (retries > 3)
09270 cmd = 't';
09271 }
09272 }
09273 DISPOSE(prefile, -1);
09274 }
09275 if (cmd == 't')
09276 cmd = 0;
09277 return cmd;
09278 }
09279
09280
09281
09282
09283
09284
09285
09286
09287
09288 static int vm_browse_messages_gr(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09289 {
09290 int cmd = 0;
09291
09292 if (vms->lastmsg > -1) {
09293 cmd = play_message(chan, vmu, vms);
09294 } else {
09295 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09296 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
09297 if (!cmd) {
09298 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
09299 cmd = ast_play_and_wait(chan, vms->fn);
09300 }
09301 if (!cmd)
09302 cmd = ast_play_and_wait(chan, "vm-messages");
09303 } else {
09304 if (!cmd)
09305 cmd = ast_play_and_wait(chan, "vm-messages");
09306 if (!cmd) {
09307 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09308 cmd = ast_play_and_wait(chan, vms->fn);
09309 }
09310 }
09311 }
09312 return cmd;
09313 }
09314
09315
09316 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09317 {
09318 int cmd = 0;
09319
09320 if (vms->lastmsg > -1) {
09321 cmd = play_message(chan, vmu, vms);
09322 } else {
09323 if (!strcasecmp(vms->fn, "INBOX")) {
09324 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
09325 } else {
09326 cmd = ast_play_and_wait(chan, "vm-nomessages");
09327 }
09328 }
09329 return cmd;
09330 }
09331
09332
09333
09334
09335
09336
09337
09338
09339
09340 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09341 {
09342 int cmd = 0;
09343
09344 if (vms->lastmsg > -1) {
09345 cmd = play_message(chan, vmu, vms);
09346 } else {
09347 cmd = ast_play_and_wait(chan, "vm-youhave");
09348 if (!cmd)
09349 cmd = ast_play_and_wait(chan, "vm-no");
09350 if (!cmd) {
09351 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09352 cmd = ast_play_and_wait(chan, vms->fn);
09353 }
09354 if (!cmd)
09355 cmd = ast_play_and_wait(chan, "vm-messages");
09356 }
09357 return cmd;
09358 }
09359
09360
09361
09362
09363
09364
09365
09366
09367
09368 static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09369 {
09370 int cmd;
09371
09372 if (vms->lastmsg > -1) {
09373 cmd = play_message(chan, vmu, vms);
09374 } else {
09375 cmd = ast_play_and_wait(chan, "vm-no");
09376 if (!cmd)
09377 cmd = ast_play_and_wait(chan, "vm-message");
09378 if (!cmd) {
09379 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09380 cmd = ast_play_and_wait(chan, vms->fn);
09381 }
09382 }
09383 return cmd;
09384 }
09385
09386
09387
09388
09389
09390
09391
09392
09393
09394 static int vm_browse_messages_es(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09395 {
09396 int cmd;
09397
09398 if (vms->lastmsg > -1) {
09399 cmd = play_message(chan, vmu, vms);
09400 } else {
09401 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09402 if (!cmd)
09403 cmd = ast_play_and_wait(chan, "vm-messages");
09404 if (!cmd) {
09405 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09406 cmd = ast_play_and_wait(chan, vms->fn);
09407 }
09408 }
09409 return cmd;
09410 }
09411
09412
09413
09414
09415
09416
09417
09418
09419
09420 static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09421 {
09422 int cmd;
09423
09424 if (vms->lastmsg > -1) {
09425 cmd = play_message(chan, vmu, vms);
09426 } else {
09427 cmd = ast_play_and_wait(chan, "vm-no");
09428 if (!cmd) {
09429 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09430 cmd = ast_play_and_wait(chan, vms->fn);
09431 }
09432 if (!cmd)
09433 cmd = ast_play_and_wait(chan, "vm-messages");
09434 }
09435 return cmd;
09436 }
09437
09438
09439
09440
09441
09442
09443
09444
09445
09446 static int vm_browse_messages_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09447 {
09448 int cmd;
09449
09450 if (vms->lastmsg > -1) {
09451 cmd = play_message(chan, vmu, vms);
09452 } else {
09453 cmd = ast_play_and_wait(chan, "vm-you");
09454 if (!cmd)
09455 cmd = ast_play_and_wait(chan, "vm-haveno");
09456 if (!cmd)
09457 cmd = ast_play_and_wait(chan, "vm-messages");
09458 if (!cmd) {
09459 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09460 cmd = ast_play_and_wait(chan, vms->fn);
09461 }
09462 }
09463 return cmd;
09464 }
09465
09466
09467
09468
09469
09470
09471
09472
09473
09474 static int vm_browse_messages_vi(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09475 {
09476 int cmd = 0;
09477
09478 if (vms->lastmsg > -1) {
09479 cmd = play_message(chan, vmu, vms);
09480 } else {
09481 cmd = ast_play_and_wait(chan, "vm-no");
09482 if (!cmd) {
09483 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09484 cmd = ast_play_and_wait(chan, vms->fn);
09485 }
09486 }
09487 return cmd;
09488 }
09489
09490
09491
09492
09493
09494
09495
09496
09497
09498
09499
09500
09501 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09502 {
09503 if (!strncasecmp(chan->language, "es", 2)) {
09504 return vm_browse_messages_es(chan, vms, vmu);
09505 } else if (!strncasecmp(chan->language, "gr", 2)) {
09506 return vm_browse_messages_gr(chan, vms, vmu);
09507 } else if (!strncasecmp(chan->language, "he", 2)) {
09508 return vm_browse_messages_he(chan, vms, vmu);
09509 } else if (!strncasecmp(chan->language, "it", 2)) {
09510 return vm_browse_messages_it(chan, vms, vmu);
09511 } else if (!strncasecmp(chan->language, "pt", 2)) {
09512 return vm_browse_messages_pt(chan, vms, vmu);
09513 } else if (!strncasecmp(chan->language, "vi", 2)) {
09514 return vm_browse_messages_vi(chan, vms, vmu);
09515 } else if (!strncasecmp(chan->language, "zh", 2)) {
09516 return vm_browse_messages_zh(chan, vms, vmu);
09517 } else {
09518 return vm_browse_messages_en(chan, vms, vmu);
09519 }
09520 }
09521
09522 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
09523 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
09524 int skipuser, int max_logins, int silent)
09525 {
09526 int useadsi = 0, valid = 0, logretries = 0;
09527 char password[AST_MAX_EXTENSION]="", *passptr;
09528 struct ast_vm_user vmus, *vmu = NULL;
09529
09530
09531 adsi_begin(chan, &useadsi);
09532 if (!skipuser && useadsi)
09533 adsi_login(chan);
09534 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
09535 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
09536 return -1;
09537 }
09538
09539
09540
09541 while (!valid && (logretries < max_logins)) {
09542
09543 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
09544 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
09545 return -1;
09546 }
09547 if (ast_strlen_zero(mailbox)) {
09548 if (chan->caller.id.number.valid && chan->caller.id.number.str) {
09549 ast_copy_string(mailbox, chan->caller.id.number.str, mailbox_size);
09550 } else {
09551 ast_verb(3, "Username not entered\n");
09552 return -1;
09553 }
09554 } else if (mailbox[0] == '*') {
09555
09556 if (ast_exists_extension(chan, chan->context, "a", 1,
09557 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09558 return -1;
09559 }
09560 mailbox[0] = '\0';
09561 }
09562
09563 if (useadsi)
09564 adsi_password(chan);
09565
09566 if (!ast_strlen_zero(prefix)) {
09567 char fullusername[80] = "";
09568 ast_copy_string(fullusername, prefix, sizeof(fullusername));
09569 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
09570 ast_copy_string(mailbox, fullusername, mailbox_size);
09571 }
09572
09573 ast_debug(1, "Before find user for mailbox %s\n", mailbox);
09574 vmu = find_user(&vmus, context, mailbox);
09575 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
09576
09577 password[0] = '\0';
09578 } else {
09579 if (ast_streamfile(chan, vm_password, chan->language)) {
09580 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
09581 return -1;
09582 }
09583 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
09584 ast_log(AST_LOG_WARNING, "Unable to read password\n");
09585 return -1;
09586 } else if (password[0] == '*') {
09587
09588 if (ast_exists_extension(chan, chan->context, "a", 1,
09589 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09590 mailbox[0] = '*';
09591 return -1;
09592 }
09593 mailbox[0] = '\0';
09594 }
09595 }
09596
09597 if (vmu) {
09598 passptr = vmu->password;
09599 if (passptr[0] == '-') passptr++;
09600 }
09601 if (vmu && !strcmp(passptr, password))
09602 valid++;
09603 else {
09604 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
09605 if (!ast_strlen_zero(prefix))
09606 mailbox[0] = '\0';
09607 }
09608 logretries++;
09609 if (!valid) {
09610 if (skipuser || logretries >= max_logins) {
09611 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
09612 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
09613 return -1;
09614 }
09615 } else {
09616 if (useadsi)
09617 adsi_login(chan);
09618 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
09619 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
09620 return -1;
09621 }
09622 }
09623 if (ast_waitstream(chan, ""))
09624 return -1;
09625 }
09626 }
09627 if (!valid && (logretries >= max_logins)) {
09628 ast_stopstream(chan);
09629 ast_play_and_wait(chan, "vm-goodbye");
09630 return -1;
09631 }
09632 if (vmu && !skipuser) {
09633 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
09634 }
09635 return 0;
09636 }
09637
09638 static int vm_execmain(struct ast_channel *chan, const char *data)
09639 {
09640
09641
09642
09643 int res = -1;
09644 int cmd = 0;
09645 int valid = 0;
09646 char prefixstr[80] ="";
09647 char ext_context[256]="";
09648 int box;
09649 int useadsi = 0;
09650 int skipuser = 0;
09651 struct vm_state vms;
09652 struct ast_vm_user *vmu = NULL, vmus;
09653 char *context = NULL;
09654 int silentexit = 0;
09655 struct ast_flags flags = { 0 };
09656 signed char record_gain = 0;
09657 int play_auto = 0;
09658 int play_folder = 0;
09659 int in_urgent = 0;
09660 #ifdef IMAP_STORAGE
09661 int deleted = 0;
09662 #endif
09663
09664
09665 memset(&vms, 0, sizeof(vms));
09666
09667 vms.lastmsg = -1;
09668
09669 memset(&vmus, 0, sizeof(vmus));
09670
09671 if (chan->_state != AST_STATE_UP) {
09672 ast_debug(1, "Before ast_answer\n");
09673 ast_answer(chan);
09674 }
09675
09676 if (!ast_strlen_zero(data)) {
09677 char *opts[OPT_ARG_ARRAY_SIZE];
09678 char *parse;
09679 AST_DECLARE_APP_ARGS(args,
09680 AST_APP_ARG(argv0);
09681 AST_APP_ARG(argv1);
09682 );
09683
09684 parse = ast_strdupa(data);
09685
09686 AST_STANDARD_APP_ARGS(args, parse);
09687
09688 if (args.argc == 2) {
09689 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
09690 return -1;
09691 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
09692 int gain;
09693 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
09694 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
09695 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
09696 return -1;
09697 } else {
09698 record_gain = (signed char) gain;
09699 }
09700 } else {
09701 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
09702 }
09703 }
09704 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
09705 play_auto = 1;
09706 if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])) {
09707
09708 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
09709 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
09710 play_folder = -1;
09711 }
09712 } else {
09713 play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
09714 }
09715 } else {
09716 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
09717 }
09718 if (play_folder > 9 || play_folder < 0) {
09719 ast_log(AST_LOG_WARNING,
09720 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
09721 opts[OPT_ARG_PLAYFOLDER]);
09722 play_folder = 0;
09723 }
09724 }
09725 } else {
09726
09727 while (*(args.argv0)) {
09728 if (*(args.argv0) == 's')
09729 ast_set_flag(&flags, OPT_SILENT);
09730 else if (*(args.argv0) == 'p')
09731 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
09732 else
09733 break;
09734 (args.argv0)++;
09735 }
09736
09737 }
09738
09739 valid = ast_test_flag(&flags, OPT_SILENT);
09740
09741 if ((context = strchr(args.argv0, '@')))
09742 *context++ = '\0';
09743
09744 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
09745 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
09746 else
09747 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
09748
09749 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
09750 skipuser++;
09751 else
09752 valid = 0;
09753 }
09754
09755 if (!valid)
09756 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
09757
09758 ast_debug(1, "After vm_authenticate\n");
09759
09760 if (vms.username[0] == '*') {
09761 ast_debug(1, "user pressed * in context '%s'\n", chan->context);
09762
09763
09764 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
09765 res = 0;
09766 goto out;
09767 }
09768 }
09769
09770 if (!res) {
09771 valid = 1;
09772 if (!skipuser)
09773 vmu = &vmus;
09774 } else {
09775 res = 0;
09776 }
09777
09778
09779 adsi_begin(chan, &useadsi);
09780
09781 if (!valid) {
09782 goto out;
09783 }
09784
09785 #ifdef IMAP_STORAGE
09786 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
09787 pthread_setspecific(ts_vmstate.key, &vms);
09788
09789 vms.interactive = 1;
09790 vms.updated = 1;
09791 if (vmu)
09792 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
09793 vmstate_insert(&vms);
09794 init_vm_state(&vms);
09795 #endif
09796
09797 if (!(vms.deleted = ast_calloc(vmu->maxmsg ? vmu->maxmsg : 1, sizeof(int)))) {
09798 ast_log(AST_LOG_ERROR, "Could not allocate memory for deleted message storage!\n");
09799 cmd = ast_play_and_wait(chan, "an-error-has-occured");
09800 return -1;
09801 }
09802 if (!(vms.heard = ast_calloc(vmu->maxmsg ? vmu->maxmsg : 1, sizeof(int)))) {
09803 ast_log(AST_LOG_ERROR, "Could not allocate memory for heard message storage!\n");
09804 cmd = ast_play_and_wait(chan, "an-error-has-occured");
09805 return -1;
09806 }
09807
09808
09809 if (!ast_strlen_zero(vmu->language))
09810 ast_string_field_set(chan, language, vmu->language);
09811
09812
09813 ast_debug(1, "Before open_mailbox\n");
09814 res = open_mailbox(&vms, vmu, OLD_FOLDER);
09815 if (res < 0)
09816 goto out;
09817 vms.oldmessages = vms.lastmsg + 1;
09818 ast_debug(1, "Number of old messages: %d\n", vms.oldmessages);
09819
09820 res = open_mailbox(&vms, vmu, NEW_FOLDER);
09821 if (res < 0)
09822 goto out;
09823 vms.newmessages = vms.lastmsg + 1;
09824 ast_debug(1, "Number of new messages: %d\n", vms.newmessages);
09825
09826 in_urgent = 1;
09827 res = open_mailbox(&vms, vmu, 11);
09828 if (res < 0)
09829 goto out;
09830 vms.urgentmessages = vms.lastmsg + 1;
09831 ast_debug(1, "Number of urgent messages: %d\n", vms.urgentmessages);
09832
09833
09834 if (play_auto) {
09835 if (vms.urgentmessages) {
09836 in_urgent = 1;
09837 res = open_mailbox(&vms, vmu, 11);
09838 } else {
09839 in_urgent = 0;
09840 res = open_mailbox(&vms, vmu, play_folder);
09841 }
09842 if (res < 0)
09843 goto out;
09844
09845
09846 if (vms.lastmsg == -1) {
09847 in_urgent = 0;
09848 cmd = vm_browse_messages(chan, &vms, vmu);
09849 res = 0;
09850 goto out;
09851 }
09852 } else {
09853 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
09854
09855 res = open_mailbox(&vms, vmu, OLD_FOLDER);
09856 in_urgent = 0;
09857 play_folder = 1;
09858 if (res < 0)
09859 goto out;
09860 } else if (!vms.urgentmessages && vms.newmessages) {
09861
09862 in_urgent = 0;
09863 res = open_mailbox(&vms, vmu, NEW_FOLDER);
09864 if (res < 0)
09865 goto out;
09866 }
09867 }
09868
09869 if (useadsi)
09870 adsi_status(chan, &vms);
09871 res = 0;
09872
09873
09874 if (!strcasecmp(vmu->mailbox, vmu->password) &&
09875 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
09876 if (ast_play_and_wait(chan, "vm-newuser") == -1)
09877 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
09878 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
09879 if ((cmd == 't') || (cmd == '#')) {
09880
09881 res = 0;
09882 goto out;
09883 } else if (cmd < 0) {
09884
09885 res = -1;
09886 goto out;
09887 }
09888 }
09889 #ifdef IMAP_STORAGE
09890 ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
09891 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
09892 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
09893 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
09894 }
09895 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
09896 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
09897 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
09898 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
09899 }
09900 #endif
09901 if (play_auto) {
09902 cmd = '1';
09903 } else {
09904 cmd = vm_intro(chan, vmu, &vms);
09905 }
09906
09907 vms.repeats = 0;
09908 vms.starting = 1;
09909 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
09910
09911 switch (cmd) {
09912 case '1':
09913 vms.curmsg = 0;
09914
09915 case '5':
09916 cmd = vm_browse_messages(chan, &vms, vmu);
09917 break;
09918 case '2':
09919 if (useadsi)
09920 adsi_folders(chan, 0, "Change to folder...");
09921 cmd = get_folder2(chan, "vm-changeto", 0);
09922 if (cmd == '#') {
09923 cmd = 0;
09924 } else if (cmd > 0) {
09925 cmd = cmd - '0';
09926 res = close_mailbox(&vms, vmu);
09927 if (res == ERROR_LOCK_PATH)
09928 goto out;
09929
09930 if (cmd != 11) in_urgent = 0;
09931 res = open_mailbox(&vms, vmu, cmd);
09932 if (res < 0)
09933 goto out;
09934 play_folder = cmd;
09935 cmd = 0;
09936 }
09937 if (useadsi)
09938 adsi_status2(chan, &vms);
09939
09940 if (!cmd)
09941 cmd = vm_play_folder_name(chan, vms.vmbox);
09942
09943 vms.starting = 1;
09944 break;
09945 case '3':
09946 cmd = 0;
09947 vms.repeats = 0;
09948 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
09949 switch (cmd) {
09950 case '1':
09951 if (vms.lastmsg > -1 && !vms.starting) {
09952 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
09953 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
09954 res = cmd;
09955 goto out;
09956 }
09957 } else
09958 cmd = ast_play_and_wait(chan, "vm-sorry");
09959 cmd = 't';
09960 break;
09961 case '2':
09962 if (!vms.starting)
09963 ast_verb(3, "Callback Requested\n");
09964 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
09965 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
09966 if (cmd == 9) {
09967 silentexit = 1;
09968 goto out;
09969 } else if (cmd == ERROR_LOCK_PATH) {
09970 res = cmd;
09971 goto out;
09972 }
09973 } else
09974 cmd = ast_play_and_wait(chan, "vm-sorry");
09975 cmd = 't';
09976 break;
09977 case '3':
09978 if (vms.lastmsg > -1 && !vms.starting) {
09979 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
09980 if (cmd == ERROR_LOCK_PATH) {
09981 res = cmd;
09982 goto out;
09983 }
09984 } else
09985 cmd = ast_play_and_wait(chan, "vm-sorry");
09986 cmd = 't';
09987 break;
09988 case '4':
09989 if (!ast_strlen_zero(vmu->dialout)) {
09990 cmd = dialout(chan, vmu, NULL, vmu->dialout);
09991 if (cmd == 9) {
09992 silentexit = 1;
09993 goto out;
09994 }
09995 } else
09996 cmd = ast_play_and_wait(chan, "vm-sorry");
09997 cmd = 't';
09998 break;
09999
10000 case '5':
10001 if (ast_test_flag(vmu, VM_SVMAIL)) {
10002 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
10003 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10004 res = cmd;
10005 goto out;
10006 }
10007 } else
10008 cmd = ast_play_and_wait(chan, "vm-sorry");
10009 cmd = 't';
10010 break;
10011
10012 case '*':
10013 cmd = 't';
10014 break;
10015
10016 default:
10017 cmd = 0;
10018 if (!vms.starting) {
10019 cmd = ast_play_and_wait(chan, "vm-toreply");
10020 }
10021 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
10022 cmd = ast_play_and_wait(chan, "vm-tocallback");
10023 }
10024 if (!cmd && !vms.starting) {
10025 cmd = ast_play_and_wait(chan, "vm-tohearenv");
10026 }
10027 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
10028 cmd = ast_play_and_wait(chan, "vm-tomakecall");
10029 }
10030 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd)
10031 cmd = ast_play_and_wait(chan, "vm-leavemsg");
10032 if (!cmd)
10033 cmd = ast_play_and_wait(chan, "vm-starmain");
10034 if (!cmd)
10035 cmd = ast_waitfordigit(chan, 6000);
10036 if (!cmd)
10037 vms.repeats++;
10038 if (vms.repeats > 3)
10039 cmd = 't';
10040 }
10041 }
10042 if (cmd == 't') {
10043 cmd = 0;
10044 vms.repeats = 0;
10045 }
10046 break;
10047 case '4':
10048 if (vms.curmsg > 0) {
10049 vms.curmsg--;
10050 cmd = play_message(chan, vmu, &vms);
10051 } else {
10052
10053
10054
10055
10056 if (in_urgent == 0 && vms.urgentmessages > 0) {
10057
10058 in_urgent = 1;
10059 res = close_mailbox(&vms, vmu);
10060 if (res == ERROR_LOCK_PATH)
10061 goto out;
10062 res = open_mailbox(&vms, vmu, 11);
10063 if (res < 0)
10064 goto out;
10065 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1);
10066 vms.curmsg = vms.lastmsg;
10067 if (vms.lastmsg < 0)
10068 cmd = ast_play_and_wait(chan, "vm-nomore");
10069 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10070 vms.curmsg = vms.lastmsg;
10071 cmd = play_message(chan, vmu, &vms);
10072 } else {
10073 cmd = ast_play_and_wait(chan, "vm-nomore");
10074 }
10075 }
10076 break;
10077 case '6':
10078 if (vms.curmsg < vms.lastmsg) {
10079 vms.curmsg++;
10080 cmd = play_message(chan, vmu, &vms);
10081 } else {
10082 if (in_urgent && vms.newmessages > 0) {
10083
10084
10085
10086
10087 in_urgent = 0;
10088 res = close_mailbox(&vms, vmu);
10089 if (res == ERROR_LOCK_PATH)
10090 goto out;
10091 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10092 if (res < 0)
10093 goto out;
10094 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10095 vms.curmsg = -1;
10096 if (vms.lastmsg < 0) {
10097 cmd = ast_play_and_wait(chan, "vm-nomore");
10098 }
10099 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10100 vms.curmsg = 0;
10101 cmd = play_message(chan, vmu, &vms);
10102 } else {
10103 cmd = ast_play_and_wait(chan, "vm-nomore");
10104 }
10105 }
10106 break;
10107 case '7':
10108 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
10109 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
10110 if (useadsi)
10111 adsi_delete(chan, &vms);
10112 if (vms.deleted[vms.curmsg]) {
10113 if (play_folder == 0) {
10114 if (in_urgent) {
10115 vms.urgentmessages--;
10116 } else {
10117 vms.newmessages--;
10118 }
10119 }
10120 else if (play_folder == 1)
10121 vms.oldmessages--;
10122 cmd = ast_play_and_wait(chan, "vm-deleted");
10123 } else {
10124 if (play_folder == 0) {
10125 if (in_urgent) {
10126 vms.urgentmessages++;
10127 } else {
10128 vms.newmessages++;
10129 }
10130 }
10131 else if (play_folder == 1)
10132 vms.oldmessages++;
10133 cmd = ast_play_and_wait(chan, "vm-undeleted");
10134 }
10135 if (ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10136 if (vms.curmsg < vms.lastmsg) {
10137 vms.curmsg++;
10138 cmd = play_message(chan, vmu, &vms);
10139 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10140 vms.curmsg = 0;
10141 cmd = play_message(chan, vmu, &vms);
10142 } else {
10143
10144
10145
10146
10147 if (in_urgent == 1) {
10148
10149 in_urgent = 0;
10150 res = close_mailbox(&vms, vmu);
10151 if (res == ERROR_LOCK_PATH)
10152 goto out;
10153 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10154 if (res < 0)
10155 goto out;
10156 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10157 vms.curmsg = -1;
10158 if (vms.lastmsg < 0)
10159 cmd = ast_play_and_wait(chan, "vm-nomore");
10160 } else {
10161 cmd = ast_play_and_wait(chan, "vm-nomore");
10162 }
10163 }
10164 }
10165 } else
10166 cmd = 0;
10167 #ifdef IMAP_STORAGE
10168 deleted = 1;
10169 #endif
10170 break;
10171
10172 case '8':
10173 if (vms.lastmsg > -1) {
10174 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
10175 if (cmd == ERROR_LOCK_PATH) {
10176 res = cmd;
10177 goto out;
10178 }
10179 } else {
10180
10181
10182
10183
10184 if (in_urgent == 1 && vms.newmessages > 0) {
10185
10186 in_urgent = 0;
10187 res = close_mailbox(&vms, vmu);
10188 if (res == ERROR_LOCK_PATH)
10189 goto out;
10190 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10191 if (res < 0)
10192 goto out;
10193 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10194 vms.curmsg = -1;
10195 if (vms.lastmsg < 0)
10196 cmd = ast_play_and_wait(chan, "vm-nomore");
10197 } else {
10198 cmd = ast_play_and_wait(chan, "vm-nomore");
10199 }
10200 }
10201 break;
10202 case '9':
10203 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
10204
10205 cmd = 0;
10206 break;
10207 }
10208 if (useadsi)
10209 adsi_folders(chan, 1, "Save to folder...");
10210 cmd = get_folder2(chan, "vm-savefolder", 1);
10211 box = 0;
10212 if (cmd == '#') {
10213 cmd = 0;
10214 break;
10215 } else if (cmd > 0) {
10216 box = cmd = cmd - '0';
10217 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
10218 if (cmd == ERROR_LOCK_PATH) {
10219 res = cmd;
10220 goto out;
10221 #ifndef IMAP_STORAGE
10222 } else if (!cmd) {
10223 vms.deleted[vms.curmsg] = 1;
10224 #endif
10225 } else {
10226 vms.deleted[vms.curmsg] = 0;
10227 vms.heard[vms.curmsg] = 0;
10228 }
10229 }
10230 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
10231 if (useadsi)
10232 adsi_message(chan, &vms);
10233 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(vmu, box));
10234 if (!cmd) {
10235 cmd = ast_play_and_wait(chan, "vm-message");
10236 if (!cmd)
10237 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
10238 if (!cmd)
10239 cmd = ast_play_and_wait(chan, "vm-savedto");
10240 if (!cmd)
10241 cmd = vm_play_folder_name(chan, vms.fn);
10242 } else {
10243 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10244 }
10245 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
10246 if (vms.curmsg < vms.lastmsg) {
10247 vms.curmsg++;
10248 cmd = play_message(chan, vmu, &vms);
10249 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10250 vms.curmsg = 0;
10251 cmd = play_message(chan, vmu, &vms);
10252 } else {
10253
10254
10255
10256
10257 if (in_urgent == 1 && vms.newmessages > 0) {
10258
10259 in_urgent = 0;
10260 res = close_mailbox(&vms, vmu);
10261 if (res == ERROR_LOCK_PATH)
10262 goto out;
10263 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10264 if (res < 0)
10265 goto out;
10266 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10267 vms.curmsg = -1;
10268 if (vms.lastmsg < 0)
10269 cmd = ast_play_and_wait(chan, "vm-nomore");
10270 } else {
10271 cmd = ast_play_and_wait(chan, "vm-nomore");
10272 }
10273 }
10274 }
10275 break;
10276 case '*':
10277 if (!vms.starting) {
10278 cmd = ast_play_and_wait(chan, "vm-onefor");
10279 if (!strncasecmp(chan->language, "he", 2)) {
10280 cmd = ast_play_and_wait(chan, "vm-for");
10281 }
10282 if (!cmd)
10283 cmd = vm_play_folder_name(chan, vms.vmbox);
10284 if (!cmd)
10285 cmd = ast_play_and_wait(chan, "vm-opts");
10286 if (!cmd)
10287 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
10288 } else
10289 cmd = 0;
10290 break;
10291 case '0':
10292 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
10293 if (useadsi)
10294 adsi_status(chan, &vms);
10295 break;
10296 default:
10297 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
10298 break;
10299 }
10300 }
10301 if ((cmd == 't') || (cmd == '#')) {
10302
10303 res = 0;
10304 } else {
10305
10306 res = -1;
10307 }
10308
10309 out:
10310 if (res > -1) {
10311 ast_stopstream(chan);
10312 adsi_goodbye(chan);
10313 if (valid && res != OPERATOR_EXIT) {
10314 if (silentexit)
10315 res = ast_play_and_wait(chan, "vm-dialout");
10316 else
10317 res = ast_play_and_wait(chan, "vm-goodbye");
10318 }
10319 if ((valid && res > 0) || res == OPERATOR_EXIT) {
10320 res = 0;
10321 }
10322 if (useadsi)
10323 ast_adsi_unload_session(chan);
10324 }
10325 if (vmu)
10326 close_mailbox(&vms, vmu);
10327 if (valid) {
10328 int new = 0, old = 0, urgent = 0;
10329 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
10330 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
10331
10332 run_externnotify(vmu->context, vmu->mailbox, NULL);
10333 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
10334 queue_mwi_event(ext_context, urgent, new, old);
10335 }
10336 #ifdef IMAP_STORAGE
10337
10338 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
10339 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
10340 ast_mutex_lock(&vms.lock);
10341 #ifdef HAVE_IMAP_TK2006
10342 if (LEVELUIDPLUS (vms.mailstream)) {
10343 mail_expunge_full(vms.mailstream, NIL, EX_UID);
10344 } else
10345 #endif
10346 mail_expunge(vms.mailstream);
10347 ast_mutex_unlock(&vms.lock);
10348 }
10349
10350
10351 if (vmu) {
10352 vmstate_delete(&vms);
10353 }
10354 #endif
10355 if (vmu)
10356 free_user(vmu);
10357 if (vms.deleted)
10358 ast_free(vms.deleted);
10359 if (vms.heard)
10360 ast_free(vms.heard);
10361
10362 #ifdef IMAP_STORAGE
10363 pthread_setspecific(ts_vmstate.key, NULL);
10364 #endif
10365 return res;
10366 }
10367
10368 static int vm_exec(struct ast_channel *chan, const char *data)
10369 {
10370 int res = 0;
10371 char *tmp;
10372 struct leave_vm_options leave_options;
10373 struct ast_flags flags = { 0 };
10374 char *opts[OPT_ARG_ARRAY_SIZE];
10375 AST_DECLARE_APP_ARGS(args,
10376 AST_APP_ARG(argv0);
10377 AST_APP_ARG(argv1);
10378 );
10379
10380 memset(&leave_options, 0, sizeof(leave_options));
10381
10382 if (chan->_state != AST_STATE_UP)
10383 ast_answer(chan);
10384
10385 if (!ast_strlen_zero(data)) {
10386 tmp = ast_strdupa(data);
10387 AST_STANDARD_APP_ARGS(args, tmp);
10388 if (args.argc == 2) {
10389 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
10390 return -1;
10391 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
10392 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
10393 int gain;
10394
10395 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
10396 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10397 return -1;
10398 } else {
10399 leave_options.record_gain = (signed char) gain;
10400 }
10401 }
10402 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
10403 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
10404 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
10405 }
10406 }
10407 } else {
10408 char temp[256];
10409 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
10410 if (res < 0)
10411 return res;
10412 if (ast_strlen_zero(temp))
10413 return 0;
10414 args.argv0 = ast_strdupa(temp);
10415 }
10416
10417 res = leave_voicemail(chan, args.argv0, &leave_options);
10418 if (res == 't') {
10419 ast_play_and_wait(chan, "vm-goodbye");
10420 res = 0;
10421 }
10422
10423 if (res == OPERATOR_EXIT) {
10424 res = 0;
10425 }
10426
10427 if (res == ERROR_LOCK_PATH) {
10428 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
10429 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
10430 res = 0;
10431 }
10432
10433 return res;
10434 }
10435
10436 static struct ast_vm_user *find_or_create(const char *context, const char *box)
10437 {
10438 struct ast_vm_user *vmu;
10439
10440 AST_LIST_TRAVERSE(&users, vmu, list) {
10441 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
10442 if (strcasecmp(vmu->context, context)) {
10443 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
10444 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
10445 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
10446 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
10447 }
10448 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
10449 return NULL;
10450 }
10451 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
10452 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
10453 return NULL;
10454 }
10455 }
10456
10457 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
10458 return NULL;
10459
10460 ast_copy_string(vmu->context, context, sizeof(vmu->context));
10461 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
10462
10463 AST_LIST_INSERT_TAIL(&users, vmu, list);
10464
10465 return vmu;
10466 }
10467
10468 static int append_mailbox(const char *context, const char *box, const char *data)
10469 {
10470
10471 char *tmp;
10472 char *stringp;
10473 char *s;
10474 struct ast_vm_user *vmu;
10475 char *mailbox_full;
10476 int new = 0, old = 0, urgent = 0;
10477 char secretfn[PATH_MAX] = "";
10478
10479 tmp = ast_strdupa(data);
10480
10481 if (!(vmu = find_or_create(context, box)))
10482 return -1;
10483
10484 populate_defaults(vmu);
10485
10486 stringp = tmp;
10487 if ((s = strsep(&stringp, ","))) {
10488 ast_copy_string(vmu->password, s, sizeof(vmu->password));
10489 }
10490 if (stringp && (s = strsep(&stringp, ","))) {
10491 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
10492 }
10493 if (stringp && (s = strsep(&stringp, ","))) {
10494 ast_copy_string(vmu->email, s, sizeof(vmu->email));
10495 }
10496 if (stringp && (s = strsep(&stringp, ","))) {
10497 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
10498 }
10499 if (stringp && (s = strsep(&stringp, ","))) {
10500 apply_options(vmu, s);
10501 }
10502
10503 switch (vmu->passwordlocation) {
10504 case OPT_PWLOC_SPOOLDIR:
10505 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
10506 read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
10507 }
10508
10509 mailbox_full = alloca(strlen(box) + strlen(context) + 1);
10510 strcpy(mailbox_full, box);
10511 strcat(mailbox_full, "@");
10512 strcat(mailbox_full, context);
10513
10514 inboxcount2(mailbox_full, &urgent, &new, &old);
10515 queue_mwi_event(mailbox_full, urgent, new, old);
10516
10517 return 0;
10518 }
10519
10520 AST_TEST_DEFINE(test_voicemail_vmuser)
10521 {
10522 int res = 0;
10523 struct ast_vm_user *vmu;
10524
10525 static const char options_string[] = "attach=yes|attachfmt=wav49|"
10526 "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|"
10527 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|"
10528 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
10529 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
10530 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
10531 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir";
10532 #ifdef IMAP_STORAGE
10533 static const char option_string2[] = "imapuser=imapuser|imappassword=imappasswd|"
10534 "imapfolder=INBOX|imapvmshareid=6000";
10535 #endif
10536
10537 switch (cmd) {
10538 case TEST_INIT:
10539 info->name = "vmuser";
10540 info->category = "/apps/app_voicemail/";
10541 info->summary = "Vmuser unit test";
10542 info->description =
10543 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
10544 return AST_TEST_NOT_RUN;
10545 case TEST_EXECUTE:
10546 break;
10547 }
10548
10549 if (!(vmu = ast_calloc(1, sizeof(*vmu)))) {
10550 return AST_TEST_NOT_RUN;
10551 }
10552 ast_set_flag(vmu, VM_ALLOCED);
10553
10554 apply_options(vmu, options_string);
10555
10556 if (!ast_test_flag(vmu, VM_ATTACH)) {
10557 ast_test_status_update(test, "Parse failure for attach option\n");
10558 res = 1;
10559 }
10560 if (strcasecmp(vmu->attachfmt, "wav49")) {
10561 ast_test_status_update(test, "Parse failure for attachftm option\n");
10562 res = 1;
10563 }
10564 if (strcasecmp(vmu->serveremail, "someguy@digium.com")) {
10565 ast_test_status_update(test, "Parse failure for serveremail option\n");
10566 res = 1;
10567 }
10568 if (strcasecmp(vmu->zonetag, "central")) {
10569 ast_test_status_update(test, "Parse failure for tz option\n");
10570 res = 1;
10571 }
10572 if (!ast_test_flag(vmu, VM_DELETE)) {
10573 ast_test_status_update(test, "Parse failure for delete option\n");
10574 res = 1;
10575 }
10576 if (!ast_test_flag(vmu, VM_SAYCID)) {
10577 ast_test_status_update(test, "Parse failure for saycid option\n");
10578 res = 1;
10579 }
10580 if (!ast_test_flag(vmu, VM_SVMAIL)) {
10581 ast_test_status_update(test, "Parse failure for sendvoicemail option\n");
10582 res = 1;
10583 }
10584 if (!ast_test_flag(vmu, VM_REVIEW)) {
10585 ast_test_status_update(test, "Parse failure for review option\n");
10586 res = 1;
10587 }
10588 if (!ast_test_flag(vmu, VM_TEMPGREETWARN)) {
10589 ast_test_status_update(test, "Parse failure for tempgreetwarm option\n");
10590 res = 1;
10591 }
10592 if (!ast_test_flag(vmu, VM_MESSAGEWRAP)) {
10593 ast_test_status_update(test, "Parse failure for messagewrap option\n");
10594 res = 1;
10595 }
10596 if (!ast_test_flag(vmu, VM_OPERATOR)) {
10597 ast_test_status_update(test, "Parse failure for operator option\n");
10598 res = 1;
10599 }
10600 if (!ast_test_flag(vmu, VM_ENVELOPE)) {
10601 ast_test_status_update(test, "Parse failure for envelope option\n");
10602 res = 1;
10603 }
10604 if (!ast_test_flag(vmu, VM_MOVEHEARD)) {
10605 ast_test_status_update(test, "Parse failure for moveheard option\n");
10606 res = 1;
10607 }
10608 if (!ast_test_flag(vmu, VM_SAYDURATION)) {
10609 ast_test_status_update(test, "Parse failure for sayduration option\n");
10610 res = 1;
10611 }
10612 if (vmu->saydurationm != 5) {
10613 ast_test_status_update(test, "Parse failure for saydurationm option\n");
10614 res = 1;
10615 }
10616 if (!ast_test_flag(vmu, VM_FORCENAME)) {
10617 ast_test_status_update(test, "Parse failure for forcename option\n");
10618 res = 1;
10619 }
10620 if (!ast_test_flag(vmu, VM_FORCEGREET)) {
10621 ast_test_status_update(test, "Parse failure for forcegreetings option\n");
10622 res = 1;
10623 }
10624 if (strcasecmp(vmu->callback, "somecontext")) {
10625 ast_test_status_update(test, "Parse failure for callbacks option\n");
10626 res = 1;
10627 }
10628 if (strcasecmp(vmu->dialout, "somecontext2")) {
10629 ast_test_status_update(test, "Parse failure for dialout option\n");
10630 res = 1;
10631 }
10632 if (strcasecmp(vmu->exit, "somecontext3")) {
10633 ast_test_status_update(test, "Parse failure for exitcontext option\n");
10634 res = 1;
10635 }
10636 if (vmu->minsecs != 10) {
10637 ast_test_status_update(test, "Parse failure for minsecs option\n");
10638 res = 1;
10639 }
10640 if (vmu->maxsecs != 100) {
10641 ast_test_status_update(test, "Parse failure for maxsecs option\n");
10642 res = 1;
10643 }
10644 if (!ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10645 ast_test_status_update(test, "Parse failure for nextaftercmd option\n");
10646 res = 1;
10647 }
10648 if (vmu->maxdeletedmsg != 50) {
10649 ast_test_status_update(test, "Parse failure for backupdeleted option\n");
10650 res = 1;
10651 }
10652 if (vmu->volgain != 1.3) {
10653 ast_test_status_update(test, "Parse failure for volgain option\n");
10654 res = 1;
10655 }
10656 if (vmu->passwordlocation != OPT_PWLOC_SPOOLDIR) {
10657 ast_test_status_update(test, "Parse failure for passwordlocation option\n");
10658 res = 1;
10659 }
10660 #ifdef IMAP_STORAGE
10661 apply_options(vmu, option_string2);
10662
10663 if (strcasecmp(vmu->imapuser, "imapuser")) {
10664 ast_test_status_update(test, "Parse failure for imapuser option\n");
10665 res = 1;
10666 }
10667 if (strcasecmp(vmu->imappassword, "imappasswd")) {
10668 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10669 res = 1;
10670 }
10671 if (strcasecmp(vmu->imapfolder, "INBOX")) {
10672 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10673 res = 1;
10674 }
10675 if (strcasecmp(vmu->imapvmshareid, "6000")) {
10676 ast_test_status_update(test, "Parse failure for imapvmshareid option\n");
10677 res = 1;
10678 }
10679 #endif
10680
10681 free_user(vmu);
10682 return res ? AST_TEST_FAIL : AST_TEST_PASS;
10683 }
10684
10685 static int vm_box_exists(struct ast_channel *chan, const char *data)
10686 {
10687 struct ast_vm_user svm;
10688 char *context, *box;
10689 AST_DECLARE_APP_ARGS(args,
10690 AST_APP_ARG(mbox);
10691 AST_APP_ARG(options);
10692 );
10693 static int dep_warning = 0;
10694
10695 if (ast_strlen_zero(data)) {
10696 ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
10697 return -1;
10698 }
10699
10700 if (!dep_warning) {
10701 dep_warning = 1;
10702 ast_log(AST_LOG_WARNING, "MailboxExists is deprecated. Please use ${MAILBOX_EXISTS(%s)} instead.\n", (char *) data);
10703 }
10704
10705 box = ast_strdupa(data);
10706
10707 AST_STANDARD_APP_ARGS(args, box);
10708
10709 if (args.options) {
10710 }
10711
10712 if ((context = strchr(args.mbox, '@'))) {
10713 *context = '\0';
10714 context++;
10715 }
10716
10717 if (find_user(&svm, context, args.mbox)) {
10718 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
10719 } else
10720 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
10721
10722 return 0;
10723 }
10724
10725 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
10726 {
10727 struct ast_vm_user svm;
10728 AST_DECLARE_APP_ARGS(arg,
10729 AST_APP_ARG(mbox);
10730 AST_APP_ARG(context);
10731 );
10732
10733 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
10734
10735 if (ast_strlen_zero(arg.mbox)) {
10736 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
10737 return -1;
10738 }
10739
10740 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
10741 return 0;
10742 }
10743
10744 static struct ast_custom_function mailbox_exists_acf = {
10745 .name = "MAILBOX_EXISTS",
10746 .read = acf_mailbox_exists,
10747 };
10748
10749 static int vmauthenticate(struct ast_channel *chan, const char *data)
10750 {
10751 char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
10752 struct ast_vm_user vmus;
10753 char *options = NULL;
10754 int silent = 0, skipuser = 0;
10755 int res = -1;
10756
10757 if (data) {
10758 s = ast_strdupa(data);
10759 user = strsep(&s, ",");
10760 options = strsep(&s, ",");
10761 if (user) {
10762 s = user;
10763 user = strsep(&s, "@");
10764 context = strsep(&s, "");
10765 if (!ast_strlen_zero(user))
10766 skipuser++;
10767 ast_copy_string(mailbox, user, sizeof(mailbox));
10768 }
10769 }
10770
10771 if (options) {
10772 silent = (strchr(options, 's')) != NULL;
10773 }
10774
10775 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
10776 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
10777 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
10778 ast_play_and_wait(chan, "auth-thankyou");
10779 res = 0;
10780 } else if (mailbox[0] == '*') {
10781
10782 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
10783 res = 0;
10784 }
10785 }
10786
10787 return res;
10788 }
10789
10790 static char *show_users_realtime(int fd, const char *context)
10791 {
10792 struct ast_config *cfg;
10793 const char *cat = NULL;
10794
10795 if (!(cfg = ast_load_realtime_multientry("voicemail",
10796 "context", context, SENTINEL))) {
10797 return CLI_FAILURE;
10798 }
10799
10800 ast_cli(fd,
10801 "\n"
10802 "=============================================================\n"
10803 "=== Configured Voicemail Users ==============================\n"
10804 "=============================================================\n"
10805 "===\n");
10806
10807 while ((cat = ast_category_browse(cfg, cat))) {
10808 struct ast_variable *var = NULL;
10809 ast_cli(fd,
10810 "=== Mailbox ...\n"
10811 "===\n");
10812 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
10813 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
10814 ast_cli(fd,
10815 "===\n"
10816 "=== ---------------------------------------------------------\n"
10817 "===\n");
10818 }
10819
10820 ast_cli(fd,
10821 "=============================================================\n"
10822 "\n");
10823
10824 ast_config_destroy(cfg);
10825
10826 return CLI_SUCCESS;
10827 }
10828
10829 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
10830 {
10831 int which = 0;
10832 int wordlen;
10833 struct ast_vm_user *vmu;
10834 const char *context = "";
10835
10836
10837 if (pos > 4)
10838 return NULL;
10839 if (pos == 3)
10840 return (state == 0) ? ast_strdup("for") : NULL;
10841 wordlen = strlen(word);
10842 AST_LIST_TRAVERSE(&users, vmu, list) {
10843 if (!strncasecmp(word, vmu->context, wordlen)) {
10844 if (context && strcmp(context, vmu->context) && ++which > state)
10845 return ast_strdup(vmu->context);
10846
10847 context = vmu->context;
10848 }
10849 }
10850 return NULL;
10851 }
10852
10853
10854 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
10855 {
10856 struct ast_vm_user *vmu;
10857 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
10858 const char *context = NULL;
10859 int users_counter = 0;
10860
10861 switch (cmd) {
10862 case CLI_INIT:
10863 e->command = "voicemail show users";
10864 e->usage =
10865 "Usage: voicemail show users [for <context>]\n"
10866 " Lists all mailboxes currently set up\n";
10867 return NULL;
10868 case CLI_GENERATE:
10869 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
10870 }
10871
10872 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
10873 return CLI_SHOWUSAGE;
10874 if (a->argc == 5) {
10875 if (strcmp(a->argv[3],"for"))
10876 return CLI_SHOWUSAGE;
10877 context = a->argv[4];
10878 }
10879
10880 if (ast_check_realtime("voicemail")) {
10881 if (!context) {
10882 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
10883 return CLI_SHOWUSAGE;
10884 }
10885 return show_users_realtime(a->fd, context);
10886 }
10887
10888 AST_LIST_LOCK(&users);
10889 if (AST_LIST_EMPTY(&users)) {
10890 ast_cli(a->fd, "There are no voicemail users currently defined\n");
10891 AST_LIST_UNLOCK(&users);
10892 return CLI_FAILURE;
10893 }
10894 if (a->argc == 3)
10895 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
10896 else {
10897 int count = 0;
10898 AST_LIST_TRAVERSE(&users, vmu, list) {
10899 if (!strcmp(context, vmu->context))
10900 count++;
10901 }
10902 if (count) {
10903 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
10904 } else {
10905 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
10906 AST_LIST_UNLOCK(&users);
10907 return CLI_FAILURE;
10908 }
10909 }
10910 AST_LIST_TRAVERSE(&users, vmu, list) {
10911 int newmsgs = 0, oldmsgs = 0;
10912 char count[12], tmp[256] = "";
10913
10914 if ((a->argc == 3) || ((a->argc == 5) && !strcmp(context, vmu->context))) {
10915 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
10916 inboxcount(tmp, &newmsgs, &oldmsgs);
10917 snprintf(count, sizeof(count), "%d", newmsgs);
10918 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
10919 users_counter++;
10920 }
10921 }
10922 AST_LIST_UNLOCK(&users);
10923 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
10924 return CLI_SUCCESS;
10925 }
10926
10927
10928 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
10929 {
10930 struct vm_zone *zone;
10931 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
10932 char *res = CLI_SUCCESS;
10933
10934 switch (cmd) {
10935 case CLI_INIT:
10936 e->command = "voicemail show zones";
10937 e->usage =
10938 "Usage: voicemail show zones\n"
10939 " Lists zone message formats\n";
10940 return NULL;
10941 case CLI_GENERATE:
10942 return NULL;
10943 }
10944
10945 if (a->argc != 3)
10946 return CLI_SHOWUSAGE;
10947
10948 AST_LIST_LOCK(&zones);
10949 if (!AST_LIST_EMPTY(&zones)) {
10950 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
10951 AST_LIST_TRAVERSE(&zones, zone, list) {
10952 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
10953 }
10954 } else {
10955 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
10956 res = CLI_FAILURE;
10957 }
10958 AST_LIST_UNLOCK(&zones);
10959
10960 return res;
10961 }
10962
10963
10964 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
10965 {
10966 switch (cmd) {
10967 case CLI_INIT:
10968 e->command = "voicemail reload";
10969 e->usage =
10970 "Usage: voicemail reload\n"
10971 " Reload voicemail configuration\n";
10972 return NULL;
10973 case CLI_GENERATE:
10974 return NULL;
10975 }
10976
10977 if (a->argc != 2)
10978 return CLI_SHOWUSAGE;
10979
10980 ast_cli(a->fd, "Reloading voicemail configuration...\n");
10981 load_config(1);
10982
10983 return CLI_SUCCESS;
10984 }
10985
10986 static struct ast_cli_entry cli_voicemail[] = {
10987 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
10988 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
10989 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
10990 };
10991
10992 #ifdef IMAP_STORAGE
10993 #define DATA_EXPORT_VM_USERS(USER) \
10994 USER(ast_vm_user, context, AST_DATA_STRING) \
10995 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
10996 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
10997 USER(ast_vm_user, fullname, AST_DATA_STRING) \
10998 USER(ast_vm_user, email, AST_DATA_STRING) \
10999 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11000 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11001 USER(ast_vm_user, pager, AST_DATA_STRING) \
11002 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11003 USER(ast_vm_user, mailcmd, AST_DATA_STRING) \
11004 USER(ast_vm_user, language, AST_DATA_STRING) \
11005 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11006 USER(ast_vm_user, callback, AST_DATA_STRING) \
11007 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11008 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11009 USER(ast_vm_user, exit, AST_DATA_STRING) \
11010 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11011 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11012 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11013 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11014 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11015 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11016 USER(ast_vm_user, imapuser, AST_DATA_STRING) \
11017 USER(ast_vm_user, imappassword, AST_DATA_STRING) \
11018 USER(ast_vm_user, imapvmshareid, AST_DATA_STRING) \
11019 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11020 #else
11021 #define DATA_EXPORT_VM_USERS(USER) \
11022 USER(ast_vm_user, context, AST_DATA_STRING) \
11023 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11024 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11025 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11026 USER(ast_vm_user, email, AST_DATA_STRING) \
11027 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11028 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11029 USER(ast_vm_user, pager, AST_DATA_STRING) \
11030 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11031 USER(ast_vm_user, mailcmd, AST_DATA_STRING) \
11032 USER(ast_vm_user, language, AST_DATA_STRING) \
11033 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11034 USER(ast_vm_user, callback, AST_DATA_STRING) \
11035 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11036 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11037 USER(ast_vm_user, exit, AST_DATA_STRING) \
11038 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11039 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11040 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11041 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11042 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11043 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11044 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11045 #endif
11046
11047 AST_DATA_STRUCTURE(ast_vm_user, DATA_EXPORT_VM_USERS);
11048
11049 #define DATA_EXPORT_VM_ZONES(ZONE) \
11050 ZONE(vm_zone, name, AST_DATA_STRING) \
11051 ZONE(vm_zone, timezone, AST_DATA_STRING) \
11052 ZONE(vm_zone, msg_format, AST_DATA_STRING)
11053
11054 AST_DATA_STRUCTURE(vm_zone, DATA_EXPORT_VM_ZONES);
11055
11056
11057
11058
11059
11060
11061
11062
11063 static int vm_users_data_provider_get_helper(const struct ast_data_search *search,
11064 struct ast_data *data_root, struct ast_vm_user *user)
11065 {
11066 struct ast_data *data_user, *data_zone;
11067 struct ast_data *data_state;
11068 struct vm_zone *zone = NULL;
11069 int urgentmsg = 0, newmsg = 0, oldmsg = 0;
11070 char ext_context[256] = "";
11071
11072 data_user = ast_data_add_node(data_root, "user");
11073 if (!data_user) {
11074 return -1;
11075 }
11076
11077 ast_data_add_structure(ast_vm_user, data_user, user);
11078
11079 AST_LIST_LOCK(&zones);
11080 AST_LIST_TRAVERSE(&zones, zone, list) {
11081 if (!strcmp(zone->name, user->zonetag)) {
11082 break;
11083 }
11084 }
11085 AST_LIST_UNLOCK(&zones);
11086
11087
11088 data_state = ast_data_add_node(data_user, "state");
11089 if (!data_state) {
11090 return -1;
11091 }
11092 snprintf(ext_context, sizeof(ext_context), "%s@%s", user->mailbox, user->context);
11093 inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg);
11094 ast_data_add_int(data_state, "urgentmsg", urgentmsg);
11095 ast_data_add_int(data_state, "newmsg", newmsg);
11096 ast_data_add_int(data_state, "oldmsg", oldmsg);
11097
11098 if (zone) {
11099 data_zone = ast_data_add_node(data_user, "zone");
11100 ast_data_add_structure(vm_zone, data_zone, zone);
11101 }
11102
11103 if (!ast_data_search_match(search, data_user)) {
11104 ast_data_remove_node(data_root, data_user);
11105 }
11106
11107 return 0;
11108 }
11109
11110 static int vm_users_data_provider_get(const struct ast_data_search *search,
11111 struct ast_data *data_root)
11112 {
11113 struct ast_vm_user *user;
11114
11115 AST_LIST_LOCK(&users);
11116 AST_LIST_TRAVERSE(&users, user, list) {
11117 vm_users_data_provider_get_helper(search, data_root, user);
11118 }
11119 AST_LIST_UNLOCK(&users);
11120
11121 return 0;
11122 }
11123
11124 static const struct ast_data_handler vm_users_data_provider = {
11125 .version = AST_DATA_HANDLER_VERSION,
11126 .get = vm_users_data_provider_get
11127 };
11128
11129 static const struct ast_data_entry vm_data_providers[] = {
11130 AST_DATA_ENTRY("asterisk/application/voicemail/list", &vm_users_data_provider)
11131 };
11132
11133 static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
11134 {
11135 int new = 0, old = 0, urgent = 0;
11136
11137 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
11138
11139 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
11140 mwi_sub->old_urgent = urgent;
11141 mwi_sub->old_new = new;
11142 mwi_sub->old_old = old;
11143 queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
11144 run_externnotify(NULL, mwi_sub->mailbox, NULL);
11145 }
11146 }
11147
11148 static void poll_subscribed_mailboxes(void)
11149 {
11150 struct mwi_sub *mwi_sub;
11151
11152 AST_RWLIST_RDLOCK(&mwi_subs);
11153 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
11154 if (!ast_strlen_zero(mwi_sub->mailbox)) {
11155 poll_subscribed_mailbox(mwi_sub);
11156 }
11157 }
11158 AST_RWLIST_UNLOCK(&mwi_subs);
11159 }
11160
11161 static void *mb_poll_thread(void *data)
11162 {
11163 while (poll_thread_run) {
11164 struct timespec ts = { 0, };
11165 struct timeval wait;
11166
11167 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
11168 ts.tv_sec = wait.tv_sec;
11169 ts.tv_nsec = wait.tv_usec * 1000;
11170
11171 ast_mutex_lock(&poll_lock);
11172 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
11173 ast_mutex_unlock(&poll_lock);
11174
11175 if (!poll_thread_run)
11176 break;
11177
11178 poll_subscribed_mailboxes();
11179 }
11180
11181 return NULL;
11182 }
11183
11184 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
11185 {
11186 ast_free(mwi_sub);
11187 }
11188
11189 static int handle_unsubscribe(void *datap)
11190 {
11191 struct mwi_sub *mwi_sub;
11192 uint32_t *uniqueid = datap;
11193
11194 AST_RWLIST_WRLOCK(&mwi_subs);
11195 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
11196 if (mwi_sub->uniqueid == *uniqueid) {
11197 AST_LIST_REMOVE_CURRENT(entry);
11198 break;
11199 }
11200 }
11201 AST_RWLIST_TRAVERSE_SAFE_END
11202 AST_RWLIST_UNLOCK(&mwi_subs);
11203
11204 if (mwi_sub)
11205 mwi_sub_destroy(mwi_sub);
11206
11207 ast_free(uniqueid);
11208 return 0;
11209 }
11210
11211 static int handle_subscribe(void *datap)
11212 {
11213 unsigned int len;
11214 struct mwi_sub *mwi_sub;
11215 struct mwi_sub_task *p = datap;
11216
11217 len = sizeof(*mwi_sub);
11218 if (!ast_strlen_zero(p->mailbox))
11219 len += strlen(p->mailbox);
11220
11221 if (!ast_strlen_zero(p->context))
11222 len += strlen(p->context) + 1;
11223
11224 if (!(mwi_sub = ast_calloc(1, len)))
11225 return -1;
11226
11227 mwi_sub->uniqueid = p->uniqueid;
11228 if (!ast_strlen_zero(p->mailbox))
11229 strcpy(mwi_sub->mailbox, p->mailbox);
11230
11231 if (!ast_strlen_zero(p->context)) {
11232 strcat(mwi_sub->mailbox, "@");
11233 strcat(mwi_sub->mailbox, p->context);
11234 }
11235
11236 AST_RWLIST_WRLOCK(&mwi_subs);
11237 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
11238 AST_RWLIST_UNLOCK(&mwi_subs);
11239 ast_free((void *) p->mailbox);
11240 ast_free((void *) p->context);
11241 ast_free(p);
11242 poll_subscribed_mailbox(mwi_sub);
11243 return 0;
11244 }
11245
11246 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
11247 {
11248 uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
11249 if (ast_event_get_type(event) != AST_EVENT_UNSUB)
11250 return;
11251
11252 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11253 return;
11254
11255 u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11256 *uniqueid = u;
11257 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
11258 ast_free(uniqueid);
11259 }
11260 }
11261
11262 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
11263 {
11264 struct mwi_sub_task *mwist;
11265
11266 if (ast_event_get_type(event) != AST_EVENT_SUB)
11267 return;
11268
11269 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11270 return;
11271
11272 if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
11273 ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
11274 return;
11275 }
11276 mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
11277 mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
11278 mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11279
11280 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
11281 ast_free(mwist);
11282 }
11283 }
11284
11285 static void start_poll_thread(void)
11286 {
11287 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, "Voicemail MWI subscription", NULL,
11288 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11289 AST_EVENT_IE_END);
11290
11291 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, "Voicemail MWI subscription", NULL,
11292 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11293 AST_EVENT_IE_END);
11294
11295 if (mwi_sub_sub)
11296 ast_event_report_subs(mwi_sub_sub);
11297
11298 poll_thread_run = 1;
11299
11300 ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL);
11301 }
11302
11303 static void stop_poll_thread(void)
11304 {
11305 poll_thread_run = 0;
11306
11307 if (mwi_sub_sub) {
11308 ast_event_unsubscribe(mwi_sub_sub);
11309 mwi_sub_sub = NULL;
11310 }
11311
11312 if (mwi_unsub_sub) {
11313 ast_event_unsubscribe(mwi_unsub_sub);
11314 mwi_unsub_sub = NULL;
11315 }
11316
11317 ast_mutex_lock(&poll_lock);
11318 ast_cond_signal(&poll_cond);
11319 ast_mutex_unlock(&poll_lock);
11320
11321 pthread_join(poll_thread, NULL);
11322
11323 poll_thread = AST_PTHREADT_NULL;
11324 }
11325
11326
11327 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
11328 {
11329 struct ast_vm_user *vmu = NULL;
11330 const char *id = astman_get_header(m, "ActionID");
11331 char actionid[128] = "";
11332
11333 if (!ast_strlen_zero(id))
11334 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
11335
11336 AST_LIST_LOCK(&users);
11337
11338 if (AST_LIST_EMPTY(&users)) {
11339 astman_send_ack(s, m, "There are no voicemail users currently defined.");
11340 AST_LIST_UNLOCK(&users);
11341 return RESULT_SUCCESS;
11342 }
11343
11344 astman_send_ack(s, m, "Voicemail user list will follow");
11345
11346 AST_LIST_TRAVERSE(&users, vmu, list) {
11347 char dirname[256];
11348
11349 #ifdef IMAP_STORAGE
11350 int new, old;
11351 inboxcount(vmu->mailbox, &new, &old);
11352 #endif
11353
11354 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
11355 astman_append(s,
11356 "%s"
11357 "Event: VoicemailUserEntry\r\n"
11358 "VMContext: %s\r\n"
11359 "VoiceMailbox: %s\r\n"
11360 "Fullname: %s\r\n"
11361 "Email: %s\r\n"
11362 "Pager: %s\r\n"
11363 "ServerEmail: %s\r\n"
11364 "MailCommand: %s\r\n"
11365 "Language: %s\r\n"
11366 "TimeZone: %s\r\n"
11367 "Callback: %s\r\n"
11368 "Dialout: %s\r\n"
11369 "UniqueID: %s\r\n"
11370 "ExitContext: %s\r\n"
11371 "SayDurationMinimum: %d\r\n"
11372 "SayEnvelope: %s\r\n"
11373 "SayCID: %s\r\n"
11374 "AttachMessage: %s\r\n"
11375 "AttachmentFormat: %s\r\n"
11376 "DeleteMessage: %s\r\n"
11377 "VolumeGain: %.2f\r\n"
11378 "CanReview: %s\r\n"
11379 "CallOperator: %s\r\n"
11380 "MaxMessageCount: %d\r\n"
11381 "MaxMessageLength: %d\r\n"
11382 "NewMessageCount: %d\r\n"
11383 #ifdef IMAP_STORAGE
11384 "OldMessageCount: %d\r\n"
11385 "IMAPUser: %s\r\n"
11386 #endif
11387 "\r\n",
11388 actionid,
11389 vmu->context,
11390 vmu->mailbox,
11391 vmu->fullname,
11392 vmu->email,
11393 vmu->pager,
11394 vmu->serveremail,
11395 vmu->mailcmd,
11396 vmu->language,
11397 vmu->zonetag,
11398 vmu->callback,
11399 vmu->dialout,
11400 vmu->uniqueid,
11401 vmu->exit,
11402 vmu->saydurationm,
11403 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
11404 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
11405 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
11406 vmu->attachfmt,
11407 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
11408 vmu->volgain,
11409 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
11410 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
11411 vmu->maxmsg,
11412 vmu->maxsecs,
11413 #ifdef IMAP_STORAGE
11414 new, old, vmu->imapuser
11415 #else
11416 count_messages(vmu, dirname)
11417 #endif
11418 );
11419 }
11420 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
11421
11422 AST_LIST_UNLOCK(&users);
11423
11424 return RESULT_SUCCESS;
11425 }
11426
11427
11428 static void free_vm_users(void)
11429 {
11430 struct ast_vm_user *current;
11431 AST_LIST_LOCK(&users);
11432 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
11433 ast_set_flag(current, VM_ALLOCED);
11434 free_user(current);
11435 }
11436 AST_LIST_UNLOCK(&users);
11437 }
11438
11439
11440 static void free_vm_zones(void)
11441 {
11442 struct vm_zone *zcur;
11443 AST_LIST_LOCK(&zones);
11444 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
11445 free_zone(zcur);
11446 AST_LIST_UNLOCK(&zones);
11447 }
11448
11449 static const char *substitute_escapes(const char *value)
11450 {
11451 char *current;
11452
11453
11454 struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
11455
11456 ast_str_reset(str);
11457
11458
11459 for (current = (char *) value; *current; current++) {
11460 if (*current == '\\') {
11461 current++;
11462 if (!*current) {
11463 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
11464 break;
11465 }
11466 switch (*current) {
11467 case 'r':
11468 ast_str_append(&str, 0, "\r");
11469 break;
11470 case 'n':
11471 #ifdef IMAP_STORAGE
11472 if (!str->used || str->str[str->used - 1] != '\r') {
11473 ast_str_append(&str, 0, "\r");
11474 }
11475 #endif
11476 ast_str_append(&str, 0, "\n");
11477 break;
11478 case 't':
11479 ast_str_append(&str, 0, "\t");
11480 break;
11481 default:
11482 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
11483 break;
11484 }
11485 } else {
11486 ast_str_append(&str, 0, "%c", *current);
11487 }
11488 }
11489
11490 return ast_str_buffer(str);
11491 }
11492
11493 static int load_config(int reload)
11494 {
11495 struct ast_vm_user *current;
11496 struct ast_config *cfg, *ucfg;
11497 char *cat;
11498 struct ast_variable *var;
11499 const char *val;
11500 char *q, *stringp, *tmp;
11501 int x;
11502 int tmpadsi[4];
11503 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
11504 char secretfn[PATH_MAX] = "";
11505
11506 ast_unload_realtime("voicemail");
11507 ast_unload_realtime("voicemail_data");
11508
11509 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11510 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11511 return 0;
11512 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
11513 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11514 ucfg = NULL;
11515 }
11516 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11517 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
11518 ast_config_destroy(ucfg);
11519 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11520 return 0;
11521 }
11522 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
11523 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11524 return 0;
11525 } else {
11526 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11527 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
11528 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11529 ucfg = NULL;
11530 }
11531 }
11532 #ifdef IMAP_STORAGE
11533 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
11534 #endif
11535
11536 strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
11537 strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
11538 strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
11539 strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
11540 strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);
11541
11542
11543 free_vm_users();
11544
11545
11546 free_vm_zones();
11547
11548 AST_LIST_LOCK(&users);
11549
11550 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
11551 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
11552
11553 if (cfg) {
11554
11555
11556 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
11557 val = "default";
11558 ast_copy_string(userscontext, val, sizeof(userscontext));
11559
11560 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
11561 val = "yes";
11562 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
11563
11564 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
11565 val = "no";
11566 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
11567
11568 volgain = 0.0;
11569 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
11570 sscanf(val, "%30lf", &volgain);
11571
11572 #ifdef ODBC_STORAGE
11573 strcpy(odbc_database, "asterisk");
11574 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
11575 ast_copy_string(odbc_database, val, sizeof(odbc_database));
11576 }
11577 strcpy(odbc_table, "voicemessages");
11578 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
11579 ast_copy_string(odbc_table, val, sizeof(odbc_table));
11580 }
11581 #endif
11582
11583 strcpy(mailcmd, SENDMAIL);
11584 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
11585 ast_copy_string(mailcmd, val, sizeof(mailcmd));
11586
11587 maxsilence = 0;
11588 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
11589 maxsilence = atoi(val);
11590 if (maxsilence > 0)
11591 maxsilence *= 1000;
11592 }
11593
11594 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
11595 maxmsg = MAXMSG;
11596 } else {
11597 maxmsg = atoi(val);
11598 if (maxmsg < 0) {
11599 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
11600 maxmsg = MAXMSG;
11601 } else if (maxmsg > MAXMSGLIMIT) {
11602 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11603 maxmsg = MAXMSGLIMIT;
11604 }
11605 }
11606
11607 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
11608 maxdeletedmsg = 0;
11609 } else {
11610 if (sscanf(val, "%30d", &x) == 1)
11611 maxdeletedmsg = x;
11612 else if (ast_true(val))
11613 maxdeletedmsg = MAXMSG;
11614 else
11615 maxdeletedmsg = 0;
11616
11617 if (maxdeletedmsg < 0) {
11618 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
11619 maxdeletedmsg = MAXMSG;
11620 } else if (maxdeletedmsg > MAXMSGLIMIT) {
11621 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11622 maxdeletedmsg = MAXMSGLIMIT;
11623 }
11624 }
11625
11626
11627 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
11628 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
11629 }
11630
11631
11632 if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
11633 ast_copy_string(pagerdateformat, val, sizeof(pagerdateformat));
11634 }
11635
11636
11637 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
11638 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11639 pwdchange = PWDCHANGE_EXTERNAL;
11640 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
11641 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11642 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
11643 }
11644
11645
11646 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
11647 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
11648 ast_log(AST_LOG_DEBUG, "found externpasscheck: %s\n", ext_pass_check_cmd);
11649 }
11650
11651 #ifdef IMAP_STORAGE
11652
11653 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
11654 ast_copy_string(imapserver, val, sizeof(imapserver));
11655 } else {
11656 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
11657 }
11658
11659 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
11660 ast_copy_string(imapport, val, sizeof(imapport));
11661 } else {
11662 ast_copy_string(imapport, "143", sizeof(imapport));
11663 }
11664
11665 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
11666 ast_copy_string(imapflags, val, sizeof(imapflags));
11667 }
11668
11669 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
11670 ast_copy_string(authuser, val, sizeof(authuser));
11671 }
11672
11673 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
11674 ast_copy_string(authpassword, val, sizeof(authpassword));
11675 }
11676
11677 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
11678 if (ast_false(val))
11679 expungeonhangup = 0;
11680 else
11681 expungeonhangup = 1;
11682 } else {
11683 expungeonhangup = 1;
11684 }
11685
11686 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
11687 ast_copy_string(imapfolder, val, sizeof(imapfolder));
11688 } else {
11689 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
11690 }
11691 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
11692 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
11693 }
11694 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
11695 imapgreetings = ast_true(val);
11696 } else {
11697 imapgreetings = 0;
11698 }
11699 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
11700 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
11701 } else {
11702 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
11703 }
11704
11705
11706
11707
11708
11709 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
11710 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
11711 } else {
11712 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
11713 }
11714
11715 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
11716 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
11717 } else {
11718 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
11719 }
11720
11721 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
11722 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
11723 } else {
11724 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
11725 }
11726
11727 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
11728 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
11729 } else {
11730 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
11731 }
11732
11733
11734 imapversion++;
11735 #endif
11736
11737 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
11738 ast_copy_string(externnotify, val, sizeof(externnotify));
11739 ast_debug(1, "found externnotify: %s\n", externnotify);
11740 } else {
11741 externnotify[0] = '\0';
11742 }
11743
11744
11745 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
11746 ast_debug(1, "Enabled SMDI voicemail notification\n");
11747 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
11748 smdi_iface = ast_smdi_interface_find(val);
11749 } else {
11750 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
11751 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
11752 }
11753 if (!smdi_iface) {
11754 ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
11755 }
11756 }
11757
11758
11759 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
11760 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
11761 silencethreshold = atoi(val);
11762
11763 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
11764 val = ASTERISK_USERNAME;
11765 ast_copy_string(serveremail, val, sizeof(serveremail));
11766
11767 vmmaxsecs = 0;
11768 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
11769 if (sscanf(val, "%30d", &x) == 1) {
11770 vmmaxsecs = x;
11771 } else {
11772 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
11773 }
11774 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
11775 static int maxmessage_deprecate = 0;
11776 if (maxmessage_deprecate == 0) {
11777 maxmessage_deprecate = 1;
11778 ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
11779 }
11780 if (sscanf(val, "%30d", &x) == 1) {
11781 vmmaxsecs = x;
11782 } else {
11783 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
11784 }
11785 }
11786
11787 vmminsecs = 0;
11788 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
11789 if (sscanf(val, "%30d", &x) == 1) {
11790 vmminsecs = x;
11791 if (maxsilence / 1000 >= vmminsecs) {
11792 ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
11793 }
11794 } else {
11795 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
11796 }
11797 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
11798 static int maxmessage_deprecate = 0;
11799 if (maxmessage_deprecate == 0) {
11800 maxmessage_deprecate = 1;
11801 ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
11802 }
11803 if (sscanf(val, "%30d", &x) == 1) {
11804 vmminsecs = x;
11805 if (maxsilence / 1000 >= vmminsecs) {
11806 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
11807 }
11808 } else {
11809 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
11810 }
11811 }
11812
11813 val = ast_variable_retrieve(cfg, "general", "format");
11814 if (!val) {
11815 val = "wav";
11816 } else {
11817 tmp = ast_strdupa(val);
11818 val = ast_format_str_reduce(tmp);
11819 if (!val) {
11820 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
11821 val = "wav";
11822 }
11823 }
11824 ast_copy_string(vmfmts, val, sizeof(vmfmts));
11825
11826 skipms = 3000;
11827 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
11828 if (sscanf(val, "%30d", &x) == 1) {
11829 maxgreet = x;
11830 } else {
11831 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
11832 }
11833 }
11834
11835 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
11836 if (sscanf(val, "%30d", &x) == 1) {
11837 skipms = x;
11838 } else {
11839 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
11840 }
11841 }
11842
11843 maxlogins = 3;
11844 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
11845 if (sscanf(val, "%30d", &x) == 1) {
11846 maxlogins = x;
11847 } else {
11848 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
11849 }
11850 }
11851
11852 minpassword = MINPASSWORD;
11853 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
11854 if (sscanf(val, "%30d", &x) == 1) {
11855 minpassword = x;
11856 } else {
11857 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
11858 }
11859 }
11860
11861
11862 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
11863 val = "no";
11864 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
11865
11866
11867 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
11868 val = "no";
11869 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
11870
11871 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
11872 ast_debug(1, "VM_CID Internal context string: %s\n", val);
11873 stringp = ast_strdupa(val);
11874 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
11875 if (!ast_strlen_zero(stringp)) {
11876 q = strsep(&stringp, ",");
11877 while ((*q == ' ')||(*q == '\t'))
11878 q++;
11879 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
11880 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
11881 } else {
11882 cidinternalcontexts[x][0] = '\0';
11883 }
11884 }
11885 }
11886 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
11887 ast_debug(1, "VM Review Option disabled globally\n");
11888 val = "no";
11889 }
11890 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
11891
11892
11893 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
11894 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
11895 val = "no";
11896 } else {
11897 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
11898 }
11899 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
11900 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
11901 ast_debug(1, "VM next message wrap disabled globally\n");
11902 val = "no";
11903 }
11904 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);
11905
11906 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
11907 ast_debug(1, "VM Operator break disabled globally\n");
11908 val = "no";
11909 }
11910 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
11911
11912 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
11913 ast_debug(1, "VM CID Info before msg disabled globally\n");
11914 val = "no";
11915 }
11916 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
11917
11918 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
11919 ast_debug(1, "Send Voicemail msg disabled globally\n");
11920 val = "no";
11921 }
11922 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
11923
11924 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
11925 ast_debug(1, "ENVELOPE before msg enabled globally\n");
11926 val = "yes";
11927 }
11928 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
11929
11930 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
11931 ast_debug(1, "Move Heard enabled globally\n");
11932 val = "yes";
11933 }
11934 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
11935
11936 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
11937 ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
11938 val = "no";
11939 }
11940 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);
11941
11942 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
11943 ast_debug(1, "Duration info before msg enabled globally\n");
11944 val = "yes";
11945 }
11946 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
11947
11948 saydurationminfo = 2;
11949 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
11950 if (sscanf(val, "%30d", &x) == 1) {
11951 saydurationminfo = x;
11952 } else {
11953 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
11954 }
11955 }
11956
11957 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
11958 ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
11959 val = "no";
11960 }
11961 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
11962
11963 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
11964 ast_copy_string(dialcontext, val, sizeof(dialcontext));
11965 ast_debug(1, "found dialout context: %s\n", dialcontext);
11966 } else {
11967 dialcontext[0] = '\0';
11968 }
11969
11970 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
11971 ast_copy_string(callcontext, val, sizeof(callcontext));
11972 ast_debug(1, "found callback context: %s\n", callcontext);
11973 } else {
11974 callcontext[0] = '\0';
11975 }
11976
11977 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
11978 ast_copy_string(exitcontext, val, sizeof(exitcontext));
11979 ast_debug(1, "found operator context: %s\n", exitcontext);
11980 } else {
11981 exitcontext[0] = '\0';
11982 }
11983
11984
11985 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
11986 ast_copy_string(vm_password, val, sizeof(vm_password));
11987 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
11988 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
11989 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
11990 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
11991 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
11992 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
11993 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
11994 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
11995 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
11996 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
11997 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
11998 ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
11999 }
12000
12001 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
12002 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
12003 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
12004 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
12005 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
12006 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
12007 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
12008 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
12009 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
12010 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
12011
12012 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
12013 val = "no";
12014 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
12015
12016 if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
12017 val = "voicemail.conf";
12018 }
12019 if (!(strcmp(val, "spooldir"))) {
12020 passwordlocation = OPT_PWLOC_SPOOLDIR;
12021 } else {
12022 passwordlocation = OPT_PWLOC_VOICEMAILCONF;
12023 }
12024
12025 poll_freq = DEFAULT_POLL_FREQ;
12026 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
12027 if (sscanf(val, "%30u", &poll_freq) != 1) {
12028 poll_freq = DEFAULT_POLL_FREQ;
12029 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
12030 }
12031 }
12032
12033 poll_mailboxes = 0;
12034 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
12035 poll_mailboxes = ast_true(val);
12036
12037 if (ucfg) {
12038 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
12039 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
12040 continue;
12041 if ((current = find_or_create(userscontext, cat))) {
12042 populate_defaults(current);
12043 apply_options_full(current, ast_variable_browse(ucfg, cat));
12044 ast_copy_string(current->context, userscontext, sizeof(current->context));
12045 if (!ast_strlen_zero(current->password) && current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
12046 current->passwordlocation = OPT_PWLOC_USERSCONF;
12047 }
12048
12049 switch (current->passwordlocation) {
12050 case OPT_PWLOC_SPOOLDIR:
12051 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
12052 read_password_from_file(secretfn, current->password, sizeof(current->password));
12053 }
12054 }
12055 }
12056 ast_config_destroy(ucfg);
12057 }
12058 cat = ast_category_browse(cfg, NULL);
12059 while (cat) {
12060 if (strcasecmp(cat, "general")) {
12061 var = ast_variable_browse(cfg, cat);
12062 if (strcasecmp(cat, "zonemessages")) {
12063
12064 while (var) {
12065 append_mailbox(cat, var->name, var->value);
12066 var = var->next;
12067 }
12068 } else {
12069
12070 while (var) {
12071 struct vm_zone *z;
12072 if ((z = ast_malloc(sizeof(*z)))) {
12073 char *msg_format, *tzone;
12074 msg_format = ast_strdupa(var->value);
12075 tzone = strsep(&msg_format, "|,");
12076 if (msg_format) {
12077 ast_copy_string(z->name, var->name, sizeof(z->name));
12078 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
12079 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
12080 AST_LIST_LOCK(&zones);
12081 AST_LIST_INSERT_HEAD(&zones, z, list);
12082 AST_LIST_UNLOCK(&zones);
12083 } else {
12084 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
12085 ast_free(z);
12086 }
12087 } else {
12088 AST_LIST_UNLOCK(&users);
12089 ast_config_destroy(cfg);
12090 return -1;
12091 }
12092 var = var->next;
12093 }
12094 }
12095 }
12096 cat = ast_category_browse(cfg, cat);
12097 }
12098 memset(fromstring, 0, sizeof(fromstring));
12099 memset(pagerfromstring, 0, sizeof(pagerfromstring));
12100 strcpy(charset, "ISO-8859-1");
12101 if (emailbody) {
12102 ast_free(emailbody);
12103 emailbody = NULL;
12104 }
12105 if (emailsubject) {
12106 ast_free(emailsubject);
12107 emailsubject = NULL;
12108 }
12109 if (pagerbody) {
12110 ast_free(pagerbody);
12111 pagerbody = NULL;
12112 }
12113 if (pagersubject) {
12114 ast_free(pagersubject);
12115 pagersubject = NULL;
12116 }
12117 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
12118 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
12119 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
12120 ast_copy_string(fromstring, val, sizeof(fromstring));
12121 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
12122 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
12123 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
12124 ast_copy_string(charset, val, sizeof(charset));
12125 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
12126 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12127 for (x = 0; x < 4; x++) {
12128 memcpy(&adsifdn[x], &tmpadsi[x], 1);
12129 }
12130 }
12131 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
12132 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12133 for (x = 0; x < 4; x++) {
12134 memcpy(&adsisec[x], &tmpadsi[x], 1);
12135 }
12136 }
12137 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
12138 if (atoi(val)) {
12139 adsiver = atoi(val);
12140 }
12141 }
12142 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
12143 ast_copy_string(zonetag, val, sizeof(zonetag));
12144 }
12145 if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
12146 ast_copy_string(locale, val, sizeof(locale));
12147 }
12148 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
12149 emailsubject = ast_strdup(val);
12150 }
12151 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
12152 emailbody = ast_strdup(substitute_escapes(val));
12153 }
12154 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
12155 pagersubject = ast_strdup(val);
12156 }
12157 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
12158 pagerbody = ast_strdup(substitute_escapes(val));
12159 }
12160 AST_LIST_UNLOCK(&users);
12161 ast_config_destroy(cfg);
12162
12163 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
12164 start_poll_thread();
12165 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
12166 stop_poll_thread();;
12167
12168 return 0;
12169 } else {
12170 AST_LIST_UNLOCK(&users);
12171 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
12172 if (ucfg)
12173 ast_config_destroy(ucfg);
12174 return 0;
12175 }
12176 }
12177
12178 static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
12179 {
12180 int res = -1;
12181 char dir[PATH_MAX];
12182 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
12183 ast_debug(2, "About to try retrieving name file %s\n", dir);
12184 RETRIEVE(dir, -1, mailbox, context);
12185 if (ast_fileexists(dir, NULL, NULL)) {
12186 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
12187 }
12188 DISPOSE(dir, -1);
12189 return res;
12190 }
12191
12192 static void read_password_from_file(const char *secretfn, char *password, int passwordlen) {
12193 struct ast_config *pwconf;
12194 struct ast_flags config_flags = { 0 };
12195
12196 pwconf = ast_config_load(secretfn, config_flags);
12197 if (pwconf) {
12198 const char *val = ast_variable_retrieve(pwconf, "general", "password");
12199 if (val) {
12200 ast_copy_string(password, val, passwordlen);
12201 return;
12202 }
12203 }
12204 ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
12205 }
12206
12207 static int write_password_to_file(const char *secretfn, const char *password) {
12208 struct ast_config *conf;
12209 struct ast_category *cat;
12210 struct ast_variable *var;
12211
12212 if (!(conf=ast_config_new())) {
12213 ast_log(LOG_ERROR, "Error creating new config structure\n");
12214 return -1;
12215 }
12216 if (!(cat=ast_category_new("general","",1))) {
12217 ast_log(LOG_ERROR, "Error creating new category structure\n");
12218 return -1;
12219 }
12220 if (!(var=ast_variable_new("password",password,""))) {
12221 ast_log(LOG_ERROR, "Error creating new variable structure\n");
12222 return -1;
12223 }
12224 ast_category_append(conf,cat);
12225 ast_variable_append(cat,var);
12226 if (ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
12227 ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn);
12228 return -1;
12229 }
12230 return 0;
12231 }
12232
12233 static int vmsayname_exec(struct ast_channel *chan, const char *data)
12234 {
12235 char *context;
12236 char *args_copy;
12237 int res;
12238
12239 if (ast_strlen_zero(data)) {
12240 ast_log(LOG_WARNING, "VMSayName requires argument mailbox@context");
12241 return -1;
12242 }
12243
12244 args_copy = ast_strdupa(data);
12245 if ((context = strchr(args_copy, '@'))) {
12246 *context++ = '\0';
12247 } else {
12248 context = "default";
12249 }
12250
12251 if ((res = sayname(chan, args_copy, context) < 0)) {
12252 ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context);
12253 res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
12254 if (!res) {
12255 res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, chan->language);
12256 }
12257 }
12258
12259 return res;
12260 }
12261
12262 #ifdef TEST_FRAMEWORK
12263 static int fake_write(struct ast_channel *ast, struct ast_frame *frame)
12264 {
12265 return 0;
12266 }
12267
12268 static struct ast_frame *fake_read(struct ast_channel *ast)
12269 {
12270 return &ast_null_frame;
12271 }
12272
12273 AST_TEST_DEFINE(test_voicemail_vmsayname)
12274 {
12275 char dir[PATH_MAX];
12276 char dir2[PATH_MAX];
12277 static const char TEST_CONTEXT[] = "very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
12278 static const char TEST_EXTENSION[] = "1234";
12279
12280 struct ast_channel *test_channel1 = NULL;
12281 int res = -1;
12282
12283 static const struct ast_channel_tech fake_tech = {
12284 .write = fake_write,
12285 .read = fake_read,
12286 };
12287
12288 switch (cmd) {
12289 case TEST_INIT:
12290 info->name = "vmsayname_exec";
12291 info->category = "/apps/app_voicemail/";
12292 info->summary = "Vmsayname unit test";
12293 info->description =
12294 "This tests passing various parameters to vmsayname";
12295 return AST_TEST_NOT_RUN;
12296 case TEST_EXECUTE:
12297 break;
12298 }
12299
12300 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
12301 NULL, NULL, 0, 0, "TestChannel1"))) {
12302 goto exit_vmsayname_test;
12303 }
12304
12305
12306 test_channel1->nativeformats = AST_FORMAT_GSM;
12307 test_channel1->writeformat = AST_FORMAT_GSM;
12308 test_channel1->rawwriteformat = AST_FORMAT_GSM;
12309 test_channel1->readformat = AST_FORMAT_GSM;
12310 test_channel1->rawreadformat = AST_FORMAT_GSM;
12311 test_channel1->tech = &fake_tech;
12312
12313 ast_test_status_update(test, "Test playing of extension when greeting is not available...\n");
12314 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12315 if (!(res = vmsayname_exec(test_channel1, dir))) {
12316 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12317 if (ast_fileexists(dir, NULL, NULL)) {
12318 ast_test_status_update(test, "This should not happen, most likely means clean up from previous test failed\n");
12319 res = -1;
12320 goto exit_vmsayname_test;
12321 } else {
12322
12323 if ((res = create_dirpath(dir, sizeof(dir), TEST_CONTEXT, TEST_EXTENSION, ""))) {
12324 ast_log(AST_LOG_WARNING, "Failed to make test directory\n");
12325 goto exit_vmsayname_test;
12326 }
12327 snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_VAR_DIR);
12328 snprintf(dir2, sizeof(dir2), "%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12329
12330 if ((res = symlink(dir, dir2))) {
12331 ast_log(LOG_WARNING, "Symlink reported %s\n", strerror(errno));
12332 goto exit_vmsayname_test;
12333 }
12334 ast_test_status_update(test, "Test playing created mailbox greeting...\n");
12335 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12336 res = vmsayname_exec(test_channel1, dir);
12337
12338
12339 unlink(dir2);
12340 snprintf(dir2, sizeof(dir2), "%s%s/%s", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12341 rmdir(dir2);
12342 snprintf(dir2, sizeof(dir2), "%s%s", VM_SPOOL_DIR, TEST_CONTEXT);
12343 rmdir(dir2);
12344 }
12345 }
12346
12347 exit_vmsayname_test:
12348
12349 if (test_channel1) {
12350 ast_hangup(test_channel1);
12351 }
12352
12353 return res ? AST_TEST_FAIL : AST_TEST_PASS;
12354 }
12355
12356 AST_TEST_DEFINE(test_voicemail_msgcount)
12357 {
12358 int i, j, res = AST_TEST_PASS, syserr;
12359 struct ast_vm_user *vmu;
12360 struct vm_state vms;
12361 #ifdef IMAP_STORAGE
12362 struct ast_channel *chan = NULL;
12363 #endif
12364 struct {
12365 char dir[256];
12366 char file[256];
12367 char txtfile[256];
12368 } tmp[3];
12369 char syscmd[256];
12370 const char origweasels[] = "tt-weasels";
12371 const char testcontext[] = "test";
12372 const char testmailbox[] = "00000000";
12373 const char testspec[] = "00000000@test";
12374 FILE *txt;
12375 int new, old, urgent;
12376 const char *folders[3] = { "Old", "Urgent", "INBOX" };
12377 const int folder2mbox[3] = { 1, 11, 0 };
12378 const int expected_results[3][12] = {
12379
12380 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
12381 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
12382 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
12383 };
12384
12385 switch (cmd) {
12386 case TEST_INIT:
12387 info->name = "test_voicemail_msgcount";
12388 info->category = "/apps/app_voicemail/";
12389 info->summary = "Test Voicemail status checks";
12390 info->description =
12391 "Verify that message counts are correct when retrieved through the public API";
12392 return AST_TEST_NOT_RUN;
12393 case TEST_EXECUTE:
12394 break;
12395 }
12396
12397
12398 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12399 if ((syserr = ast_safe_system(syscmd))) {
12400 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12401 syserr > 0 ? strerror(syserr) : "unable to fork()");
12402 return AST_TEST_FAIL;
12403 }
12404
12405 #ifdef IMAP_STORAGE
12406 if (!(chan = ast_dummy_channel_alloc())) {
12407 ast_test_status_update(test, "Unable to create dummy channel\n");
12408 return AST_TEST_FAIL;
12409 }
12410 #endif
12411
12412 if (!(vmu = find_user(NULL, testcontext, testmailbox)) &&
12413 !(vmu = find_or_create(testcontext, testmailbox))) {
12414 ast_test_status_update(test, "Cannot create vmu structure\n");
12415 ast_unreplace_sigchld();
12416 return AST_TEST_FAIL;
12417 }
12418
12419 populate_defaults(vmu);
12420 memset(&vms, 0, sizeof(vms));
12421
12422
12423 for (i = 0; i < 3; i++) {
12424 create_dirpath(tmp[i].dir, sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
12425 make_file(tmp[i].file, sizeof(tmp[i].file), tmp[i].dir, 0);
12426 snprintf(tmp[i].txtfile, sizeof(tmp[i].txtfile), "%s.txt", tmp[i].file);
12427
12428 if (ast_fileexists(origweasels, "gsm", "en") > 0) {
12429 snprintf(syscmd, sizeof(syscmd), "cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"", ast_config_AST_DATA_DIR, origweasels,
12430 VM_SPOOL_DIR, testcontext, testmailbox, folders[i]);
12431 if ((syserr = ast_safe_system(syscmd))) {
12432 ast_test_status_update(test, "Unable to create test voicemail: %s\n",
12433 syserr > 0 ? strerror(syserr) : "unable to fork()");
12434 ast_unreplace_sigchld();
12435 return AST_TEST_FAIL;
12436 }
12437 }
12438
12439 if ((txt = fopen(tmp[i].txtfile, "w+"))) {
12440 fprintf(txt, "; just a stub\n[message]\nflag=%s\n", strcmp(folders[i], "Urgent") ? "" : "Urgent");
12441 fclose(txt);
12442 } else {
12443 ast_test_status_update(test, "Unable to write message file '%s'\n", tmp[i].txtfile);
12444 res = AST_TEST_FAIL;
12445 break;
12446 }
12447 open_mailbox(&vms, vmu, folder2mbox[i]);
12448 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu, "gsm", 600, &vms, strcmp(folders[i], "Urgent") ? "" : "Urgent");
12449
12450
12451 for (j = 0; j < 3; j++) {
12452
12453 if (ast_app_has_voicemail(testspec, (j==2 ? NULL : folders[j])) != expected_results[i][0 + j]) {
12454 ast_test_status_update(test, "has_voicemail(%s, %s) returned %d and we expected %d\n",
12455 testspec, folders[j], ast_app_has_voicemail(testspec, folders[j]), expected_results[i][0 + j]);
12456 res = AST_TEST_FAIL;
12457 }
12458 }
12459
12460 new = old = urgent = 0;
12461 if (ast_app_inboxcount(testspec, &new, &old)) {
12462 ast_test_status_update(test, "inboxcount returned failure\n");
12463 res = AST_TEST_FAIL;
12464 } else if (old != expected_results[i][3 + 0] || new != expected_results[i][3 + 2]) {
12465 ast_test_status_update(test, "inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n",
12466 testspec, old, expected_results[i][3 + 0], new, expected_results[i][3 + 2]);
12467 res = AST_TEST_FAIL;
12468 }
12469
12470 new = old = urgent = 0;
12471 if (ast_app_inboxcount2(testspec, &urgent, &new, &old)) {
12472 ast_test_status_update(test, "inboxcount2 returned failure\n");
12473 res = AST_TEST_FAIL;
12474 } else if (old != expected_results[i][6 + 0] ||
12475 urgent != expected_results[i][6 + 1] ||
12476 new != expected_results[i][6 + 2] ) {
12477 ast_test_status_update(test, "inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
12478 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1], new, expected_results[i][6 + 2]);
12479 res = AST_TEST_FAIL;
12480 }
12481
12482 new = old = urgent = 0;
12483 for (j = 0; j < 3; j++) {
12484 if (ast_app_messagecount(testcontext, testmailbox, folders[j]) != expected_results[i][9 + j]) {
12485 ast_test_status_update(test, "messagecount(%s, %s) returned %d and we expected %d\n",
12486 testspec, folders[j], ast_app_messagecount(testcontext, testmailbox, folders[j]), expected_results[i][9 + j]);
12487 res = AST_TEST_FAIL;
12488 }
12489 }
12490 }
12491
12492 for (i = 0; i < 3; i++) {
12493
12494
12495
12496 DELETE(tmp[i].dir, 0, tmp[i].file, vmu);
12497 DISPOSE(tmp[i].dir, 0);
12498 }
12499
12500 if (vms.deleted) {
12501 ast_free(vms.deleted);
12502 }
12503 if (vms.heard) {
12504 ast_free(vms.heard);
12505 }
12506
12507 #ifdef IMAP_STORAGE
12508 chan = ast_channel_release(chan);
12509 #endif
12510
12511
12512 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12513 if ((syserr = ast_safe_system(syscmd))) {
12514 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12515 syserr > 0 ? strerror(syserr) : "unable to fork()");
12516 }
12517
12518 return res;
12519 }
12520
12521 AST_TEST_DEFINE(test_voicemail_notify_endl)
12522 {
12523 int res = AST_TEST_PASS;
12524 char testcontext[] = "test";
12525 char testmailbox[] = "00000000";
12526 char from[] = "test@example.net", cidnum[] = "1234", cidname[] = "Mark Spencer", format[] = "gsm";
12527 char attach[256], attach2[256];
12528 char buf[256] = "";
12529 struct ast_channel *chan = NULL;
12530 struct ast_vm_user *vmu, vmus = {
12531 .flags = 0,
12532 };
12533 FILE *file;
12534 struct {
12535 char *name;
12536 enum { INT, FLAGVAL, STATIC, STRPTR } type;
12537 void *location;
12538 union {
12539 int intval;
12540 char *strval;
12541 } u;
12542 } test_items[] = {
12543 { "plain jane config", STATIC, vmus.password, .u.strval = "1234" },
12544 { "emailsubject", STRPTR, vmus.emailsubject, .u.strval = "Oogly boogly\xf8koogly with what appears to be UTF-8" },
12545 { "emailbody", STRPTR, vmus.emailbody, .u.strval = "This is a test\n\twith multiple\nlines\nwithin\n" },
12546 { "serveremail", STATIC, vmus.serveremail, .u.strval = "\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
12547 { "attachment flag", FLAGVAL, &vmus.flags, .u.intval = VM_ATTACH },
12548 { "attach2", STRPTR, attach2, .u.strval = "" },
12549 { "attach", STRPTR, attach, .u.strval = "" },
12550 };
12551 int which;
12552
12553 switch (cmd) {
12554 case TEST_INIT:
12555 info->name = "test_voicemail_notify_endl";
12556 info->category = "/apps/app_voicemail/";
12557 info->summary = "Test Voicemail notification end-of-line";
12558 info->description =
12559 "Verify that notification emails use a consistent end-of-line character";
12560 return AST_TEST_NOT_RUN;
12561 case TEST_EXECUTE:
12562 break;
12563 }
12564
12565 snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_VAR_DIR);
12566 snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_VAR_DIR);
12567
12568 if (!(vmu = find_user(&vmus, testcontext, testmailbox)) &&
12569 !(vmu = find_or_create(testcontext, testmailbox))) {
12570 ast_test_status_update(test, "Cannot create vmu structure\n");
12571 return AST_TEST_NOT_RUN;
12572 }
12573
12574 if (vmu != &vmus && !(vmu = find_user(&vmus, testcontext, testmailbox))) {
12575 ast_test_status_update(test, "Cannot find vmu structure?!!\n");
12576 return AST_TEST_NOT_RUN;
12577 }
12578
12579 populate_defaults(vmu);
12580 ast_copy_string(vmu->email, "test2@example.net", sizeof(vmu->email));
12581 #ifdef IMAP_STORAGE
12582
12583 #endif
12584
12585 file = tmpfile();
12586 for (which = 0; which < ARRAY_LEN(test_items); which++) {
12587
12588 rewind(file);
12589 if (ftruncate(fileno(file), 0)) {
12590 ast_test_status_update(test, "Cannot truncate test output file: %s\n", strerror(errno));
12591 res = AST_TEST_FAIL;
12592 break;
12593 }
12594
12595
12596 if (test_items[which].type == INT) {
12597 *((int *) test_items[which].location) = test_items[which].u.intval;
12598 } else if (test_items[which].type == FLAGVAL) {
12599 if (ast_test_flag(vmu, test_items[which].u.intval)) {
12600 ast_clear_flag(vmu, test_items[which].u.intval);
12601 } else {
12602 ast_set_flag(vmu, test_items[which].u.intval);
12603 }
12604 } else if (test_items[which].type == STATIC) {
12605 strcpy(test_items[which].location, test_items[which].u.strval);
12606 } else if (test_items[which].type == STRPTR) {
12607 test_items[which].location = test_items[which].u.strval;
12608 }
12609
12610 make_email_file(file, from, vmu, 0, testcontext, testmailbox, "INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan, NULL, 0, NULL);
12611 rewind(file);
12612 while (fgets(buf, sizeof(buf), file)) {
12613 if (
12614 #ifdef IMAP_STORAGE
12615 buf[strlen(buf) - 2] != '\r'
12616 #else
12617 buf[strlen(buf) - 2] == '\r'
12618 #endif
12619 || buf[strlen(buf) - 1] != '\n') {
12620 res = AST_TEST_FAIL;
12621 }
12622 }
12623 }
12624 fclose(file);
12625 return res;
12626 }
12627 #endif
12628
12629 static int reload(void)
12630 {
12631 return load_config(1);
12632 }
12633
12634 static int unload_module(void)
12635 {
12636 int res;
12637
12638 res = ast_unregister_application(app);
12639 res |= ast_unregister_application(app2);
12640 res |= ast_unregister_application(app3);
12641 res |= ast_unregister_application(app4);
12642 res |= ast_unregister_application(sayname_app);
12643 res |= ast_custom_function_unregister(&mailbox_exists_acf);
12644 res |= ast_manager_unregister("VoicemailUsersList");
12645 res |= ast_data_unregister(NULL);
12646 #ifdef TEST_FRAMEWORK
12647 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
12648 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
12649 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
12650 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
12651 #endif
12652 ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
12653 ast_uninstall_vm_functions();
12654 ao2_ref(inprocess_container, -1);
12655
12656 if (poll_thread != AST_PTHREADT_NULL)
12657 stop_poll_thread();
12658
12659 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
12660 ast_unload_realtime("voicemail");
12661 ast_unload_realtime("voicemail_data");
12662
12663 free_vm_users();
12664 free_vm_zones();
12665 return res;
12666 }
12667
12668 static int load_module(void)
12669 {
12670 int res;
12671 my_umask = umask(0);
12672 umask(my_umask);
12673
12674 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
12675 return AST_MODULE_LOAD_DECLINE;
12676 }
12677
12678
12679 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
12680
12681 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
12682 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
12683 }
12684
12685 if ((res = load_config(0)))
12686 return res;
12687
12688 res = ast_register_application_xml(app, vm_exec);
12689 res |= ast_register_application_xml(app2, vm_execmain);
12690 res |= ast_register_application_xml(app3, vm_box_exists);
12691 res |= ast_register_application_xml(app4, vmauthenticate);
12692 res |= ast_register_application_xml(sayname_app, vmsayname_exec);
12693 res |= ast_custom_function_register(&mailbox_exists_acf);
12694 res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
12695 #ifdef TEST_FRAMEWORK
12696 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
12697 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
12698 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
12699 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
12700 #endif
12701
12702 if (res)
12703 return res;
12704
12705 ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
12706 ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));
12707
12708 ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
12709 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
12710 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
12711
12712 return res;
12713 }
12714
12715 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
12716 {
12717 int cmd = 0;
12718 char destination[80] = "";
12719 int retries = 0;
12720
12721 if (!num) {
12722 ast_verb(3, "Destination number will be entered manually\n");
12723 while (retries < 3 && cmd != 't') {
12724 destination[1] = '\0';
12725 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
12726 if (!cmd)
12727 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
12728 if (!cmd)
12729 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
12730 if (!cmd) {
12731 cmd = ast_waitfordigit(chan, 6000);
12732 if (cmd)
12733 destination[0] = cmd;
12734 }
12735 if (!cmd) {
12736 retries++;
12737 } else {
12738
12739 if (cmd < 0)
12740 return 0;
12741 if (cmd == '*') {
12742 ast_verb(3, "User hit '*' to cancel outgoing call\n");
12743 return 0;
12744 }
12745 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0)
12746 retries++;
12747 else
12748 cmd = 't';
12749 }
12750 }
12751 if (retries >= 3) {
12752 return 0;
12753 }
12754
12755 } else {
12756 if (option_verbose > 2)
12757 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
12758 ast_copy_string(destination, num, sizeof(destination));
12759 }
12760
12761 if (!ast_strlen_zero(destination)) {
12762 if (destination[strlen(destination) -1 ] == '*')
12763 return 0;
12764 if (option_verbose > 2)
12765 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
12766 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
12767 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
12768 chan->priority = 0;
12769 return 9;
12770 }
12771 return 0;
12772 }
12773
12774
12775
12776
12777
12778
12779
12780
12781
12782
12783
12784
12785
12786
12787 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)
12788 {
12789 int res = 0;
12790 char filename[PATH_MAX];
12791 struct ast_config *msg_cfg = NULL;
12792 const char *origtime, *context;
12793 char *name, *num;
12794 int retries = 0;
12795 char *cid;
12796 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
12797
12798 vms->starting = 0;
12799
12800 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
12801
12802
12803 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
12804 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
12805 msg_cfg = ast_config_load(filename, config_flags);
12806 DISPOSE(vms->curdir, vms->curmsg);
12807 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
12808 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
12809 return 0;
12810 }
12811
12812 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
12813 ast_config_destroy(msg_cfg);
12814 return 0;
12815 }
12816
12817 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
12818
12819 context = ast_variable_retrieve(msg_cfg, "message", "context");
12820 if (!strncasecmp("macro", context, 5))
12821 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
12822 switch (option) {
12823 case 3:
12824 if (!res)
12825 res = play_message_datetime(chan, vmu, origtime, filename);
12826 if (!res)
12827 res = play_message_callerid(chan, vms, cid, context, 0);
12828
12829 res = 't';
12830 break;
12831
12832 case 2:
12833
12834 if (ast_strlen_zero(cid))
12835 break;
12836
12837 ast_callerid_parse(cid, &name, &num);
12838 while ((res > -1) && (res != 't')) {
12839 switch (res) {
12840 case '1':
12841 if (num) {
12842
12843 res = dialout(chan, vmu, num, vmu->callback);
12844 if (res) {
12845 ast_config_destroy(msg_cfg);
12846 return 9;
12847 }
12848 } else {
12849 res = '2';
12850 }
12851 break;
12852
12853 case '2':
12854
12855 if (!ast_strlen_zero(vmu->dialout)) {
12856 res = dialout(chan, vmu, NULL, vmu->dialout);
12857 if (res) {
12858 ast_config_destroy(msg_cfg);
12859 return 9;
12860 }
12861 } else {
12862 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
12863 res = ast_play_and_wait(chan, "vm-sorry");
12864 }
12865 ast_config_destroy(msg_cfg);
12866 return res;
12867 case '*':
12868 res = 't';
12869 break;
12870 case '3':
12871 case '4':
12872 case '5':
12873 case '6':
12874 case '7':
12875 case '8':
12876 case '9':
12877 case '0':
12878
12879 res = ast_play_and_wait(chan, "vm-sorry");
12880 retries++;
12881 break;
12882 default:
12883 if (num) {
12884 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
12885 res = ast_play_and_wait(chan, "vm-num-i-have");
12886 if (!res)
12887 res = play_message_callerid(chan, vms, num, vmu->context, 1);
12888 if (!res)
12889 res = ast_play_and_wait(chan, "vm-tocallnum");
12890
12891 if (!ast_strlen_zero(vmu->dialout)) {
12892 if (!res)
12893 res = ast_play_and_wait(chan, "vm-calldiffnum");
12894 }
12895 } else {
12896 res = ast_play_and_wait(chan, "vm-nonumber");
12897 if (!ast_strlen_zero(vmu->dialout)) {
12898 if (!res)
12899 res = ast_play_and_wait(chan, "vm-toenternumber");
12900 }
12901 }
12902 if (!res)
12903 res = ast_play_and_wait(chan, "vm-star-cancel");
12904 if (!res)
12905 res = ast_waitfordigit(chan, 6000);
12906 if (!res) {
12907 retries++;
12908 if (retries > 3)
12909 res = 't';
12910 }
12911 break;
12912
12913 }
12914 if (res == 't')
12915 res = 0;
12916 else if (res == '*')
12917 res = -1;
12918 }
12919 break;
12920
12921 case 1:
12922
12923 if (ast_strlen_zero(cid))
12924 break;
12925
12926 ast_callerid_parse(cid, &name, &num);
12927 if (!num) {
12928 ast_verb(3, "No CID number available, no reply sent\n");
12929 if (!res)
12930 res = ast_play_and_wait(chan, "vm-nonumber");
12931 ast_config_destroy(msg_cfg);
12932 return res;
12933 } else {
12934 struct ast_vm_user vmu2;
12935 if (find_user(&vmu2, vmu->context, num)) {
12936 struct leave_vm_options leave_options;
12937 char mailbox[AST_MAX_EXTENSION * 2 + 2];
12938 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
12939
12940 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
12941
12942 memset(&leave_options, 0, sizeof(leave_options));
12943 leave_options.record_gain = record_gain;
12944 res = leave_voicemail(chan, mailbox, &leave_options);
12945 if (!res)
12946 res = 't';
12947 ast_config_destroy(msg_cfg);
12948 return res;
12949 } else {
12950
12951 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
12952 ast_play_and_wait(chan, "vm-nobox");
12953 res = 't';
12954 ast_config_destroy(msg_cfg);
12955 return res;
12956 }
12957 }
12958 res = 0;
12959
12960 break;
12961 }
12962
12963 #ifndef IMAP_STORAGE
12964 ast_config_destroy(msg_cfg);
12965
12966 if (!res) {
12967 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
12968 vms->heard[msg] = 1;
12969 res = wait_file(chan, vms, vms->fn);
12970 }
12971 #endif
12972 return res;
12973 }
12974
12975 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
12976 int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
12977 signed char record_gain, struct vm_state *vms, char *flag)
12978 {
12979
12980 int res = 0;
12981 int cmd = 0;
12982 int max_attempts = 3;
12983 int attempts = 0;
12984 int recorded = 0;
12985 int msg_exists = 0;
12986 signed char zero_gain = 0;
12987 char tempfile[PATH_MAX];
12988 char *acceptdtmf = "#";
12989 char *canceldtmf = "";
12990 int canceleddtmf = 0;
12991
12992
12993
12994
12995 if (duration == NULL) {
12996 ast_log(AST_LOG_WARNING, "Error play_record_review called without duration pointer\n");
12997 return -1;
12998 }
12999
13000 if (!outsidecaller)
13001 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
13002 else
13003 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
13004
13005 cmd = '3';
13006
13007 while ((cmd >= 0) && (cmd != 't')) {
13008 switch (cmd) {
13009 case '1':
13010 if (!msg_exists) {
13011
13012 cmd = '3';
13013 break;
13014 } else {
13015
13016 ast_verb(3, "Saving message as is\n");
13017 if (!outsidecaller)
13018 ast_filerename(tempfile, recordfile, NULL);
13019 ast_stream_and_wait(chan, "vm-msgsaved", "");
13020 if (!outsidecaller) {
13021
13022 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag);
13023 DISPOSE(recordfile, -1);
13024 }
13025 cmd = 't';
13026 return res;
13027 }
13028 case '2':
13029
13030 ast_verb(3, "Reviewing the message\n");
13031 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
13032 break;
13033 case '3':
13034 msg_exists = 0;
13035
13036 if (recorded == 1)
13037 ast_verb(3, "Re-recording the message\n");
13038 else
13039 ast_verb(3, "Recording the message\n");
13040
13041 if (recorded && outsidecaller) {
13042 cmd = ast_play_and_wait(chan, INTRO);
13043 cmd = ast_play_and_wait(chan, "beep");
13044 }
13045 recorded = 1;
13046
13047 if (record_gain)
13048 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
13049 if (ast_test_flag(vmu, VM_OPERATOR))
13050 canceldtmf = "0";
13051 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
13052 if (strchr(canceldtmf, cmd)) {
13053
13054 canceleddtmf = 1;
13055 }
13056 if (record_gain)
13057 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
13058 if (cmd == -1) {
13059
13060 if (!outsidecaller) {
13061
13062 ast_filedelete(tempfile, NULL);
13063 }
13064 return cmd;
13065 }
13066 if (cmd == '0') {
13067 break;
13068 } else if (cmd == '*') {
13069 break;
13070 #if 0
13071 } else if (vmu->review && (*duration < 5)) {
13072
13073 ast_verb(3, "Message too short\n");
13074 cmd = ast_play_and_wait(chan, "vm-tooshort");
13075 cmd = ast_filedelete(tempfile, NULL);
13076 break;
13077 } else if (vmu->review && (cmd == 2 && *duration < (maxsilence + 3))) {
13078
13079 ast_verb(3, "Nothing recorded\n");
13080 cmd = ast_filedelete(tempfile, NULL);
13081 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
13082 if (!cmd)
13083 cmd = ast_play_and_wait(chan, "vm-speakup");
13084 break;
13085 #endif
13086 } else {
13087
13088 msg_exists = 1;
13089 cmd = 0;
13090 }
13091 break;
13092 case '4':
13093 if (outsidecaller) {
13094
13095 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13096 ast_verbose(VERBOSE_PREFIX_3 "marking message as Urgent\n");
13097 res = ast_play_and_wait(chan, "vm-marked-urgent");
13098 strcpy(flag, "Urgent");
13099 } else if (flag) {
13100 ast_verbose(VERBOSE_PREFIX_3 "UNmarking message as Urgent\n");
13101 res = ast_play_and_wait(chan, "vm-urgent-removed");
13102 strcpy(flag, "");
13103 } else {
13104 ast_play_and_wait(chan, "vm-sorry");
13105 }
13106 cmd = 0;
13107 } else {
13108 cmd = ast_play_and_wait(chan, "vm-sorry");
13109 }
13110 break;
13111 case '5':
13112 case '6':
13113 case '7':
13114 case '8':
13115 case '9':
13116 case '*':
13117 case '#':
13118 cmd = ast_play_and_wait(chan, "vm-sorry");
13119 break;
13120 #if 0
13121
13122
13123 case '*':
13124
13125 cmd = ast_play_and_wait(chan, "vm-deleted");
13126 cmd = ast_filedelete(tempfile, NULL);
13127 if (outsidecaller) {
13128 res = vm_exec(chan, NULL);
13129 return res;
13130 }
13131 else
13132 return 1;
13133 #endif
13134 case '0':
13135 if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
13136 cmd = ast_play_and_wait(chan, "vm-sorry");
13137 break;
13138 }
13139 if (msg_exists || recorded) {
13140 cmd = ast_play_and_wait(chan, "vm-saveoper");
13141 if (!cmd)
13142 cmd = ast_waitfordigit(chan, 3000);
13143 if (cmd == '1') {
13144 ast_filerename(tempfile, recordfile, NULL);
13145 ast_play_and_wait(chan, "vm-msgsaved");
13146 cmd = '0';
13147 } else if (cmd == '4') {
13148 if (flag) {
13149 ast_play_and_wait(chan, "vm-marked-urgent");
13150 strcpy(flag, "Urgent");
13151 }
13152 ast_play_and_wait(chan, "vm-msgsaved");
13153 cmd = '0';
13154 } else {
13155 ast_play_and_wait(chan, "vm-deleted");
13156 DELETE(tempfile, -1, tempfile, vmu);
13157 cmd = '0';
13158 }
13159 }
13160 return cmd;
13161 default:
13162
13163
13164
13165 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
13166 return cmd;
13167 if (msg_exists) {
13168 cmd = ast_play_and_wait(chan, "vm-review");
13169 if (!cmd && outsidecaller) {
13170 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13171 cmd = ast_play_and_wait(chan, "vm-review-urgent");
13172 } else if (flag) {
13173 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
13174 }
13175 }
13176 } else {
13177 cmd = ast_play_and_wait(chan, "vm-torerecord");
13178 if (!cmd)
13179 cmd = ast_waitfordigit(chan, 600);
13180 }
13181
13182 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
13183 cmd = ast_play_and_wait(chan, "vm-reachoper");
13184 if (!cmd)
13185 cmd = ast_waitfordigit(chan, 600);
13186 }
13187 #if 0
13188 if (!cmd)
13189 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
13190 #endif
13191 if (!cmd)
13192 cmd = ast_waitfordigit(chan, 6000);
13193 if (!cmd) {
13194 attempts++;
13195 }
13196 if (attempts > max_attempts) {
13197 cmd = 't';
13198 }
13199 }
13200 }
13201 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
13202
13203 ast_filedelete(tempfile, NULL);
13204 }
13205
13206 if (cmd != 't' && outsidecaller)
13207 ast_play_and_wait(chan, "vm-goodbye");
13208
13209 return cmd;
13210 }
13211
13212
13213
13214
13215
13216 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
13217 .load = load_module,
13218 .unload = unload_module,
13219 .reload = reload,
13220 .nonoptreq = "res_adsi,res_smdi",
13221 );