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 #include "asterisk.h"
00054
00055 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 118416 $")
00056
00057 #include <stdlib.h>
00058 #include <errno.h>
00059 #include <unistd.h>
00060 #include <string.h>
00061 #include <stdlib.h>
00062 #include <stdio.h>
00063 #include <sys/time.h>
00064 #include <sys/stat.h>
00065 #include <sys/types.h>
00066 #include <sys/mman.h>
00067 #include <time.h>
00068 #include <dirent.h>
00069 #ifdef IMAP_STORAGE
00070 #include <ctype.h>
00071 #include <signal.h>
00072 #include <pwd.h>
00073 #ifdef USE_SYSTEM_IMAP
00074 #include <imap/c-client.h>
00075 #include <imap/imap4r1.h>
00076 #include <imap/linkage.h>
00077 #elif defined (USE_SYSTEM_CCLIENT)
00078 #include <c-client/c-client.h>
00079 #include <c-client/imap4r1.h>
00080 #include <c-client/linkage.h>
00081 #else
00082 #include "c-client.h"
00083 #include "imap4r1.h"
00084 #include "linkage.h"
00085 #endif
00086 #endif
00087 #include "asterisk/lock.h"
00088 #include "asterisk/file.h"
00089 #include "asterisk/logger.h"
00090 #include "asterisk/channel.h"
00091 #include "asterisk/pbx.h"
00092 #include "asterisk/options.h"
00093 #include "asterisk/config.h"
00094 #include "asterisk/say.h"
00095 #include "asterisk/module.h"
00096 #include "asterisk/adsi.h"
00097 #include "asterisk/app.h"
00098 #include "asterisk/manager.h"
00099 #include "asterisk/dsp.h"
00100 #include "asterisk/localtime.h"
00101 #include "asterisk/cli.h"
00102 #include "asterisk/utils.h"
00103 #include "asterisk/stringfields.h"
00104 #include "asterisk/smdi.h"
00105 #ifdef ODBC_STORAGE
00106 #include "asterisk/res_odbc.h"
00107 #endif
00108
00109 #ifdef IMAP_STORAGE
00110 AST_MUTEX_DEFINE_STATIC(imaptemp_lock);
00111 static char imaptemp[1024];
00112
00113 static char imapserver[48];
00114 static char imapport[8];
00115 static char imapflags[128];
00116 static char imapfolder[64];
00117 static char authuser[32];
00118 static char authpassword[42];
00119
00120 static int expungeonhangup = 1;
00121 static char delimiter = '\0';
00122
00123 struct vm_state;
00124 struct ast_vm_user;
00125
00126 static int init_mailstream (struct vm_state *vms, int box);
00127 static void write_file (char *filename, char *buffer, unsigned long len);
00128
00129 static char *get_header_by_tag(char *header, char *tag);
00130 static void vm_imap_delete(int msgnum, struct vm_state *vms);
00131 static char *get_user_by_mailbox(char *mailbox);
00132 static struct vm_state *get_vm_state_by_imapuser(char *user, int interactive);
00133 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, int interactive);
00134 static void vmstate_insert(struct vm_state *vms);
00135 static void vmstate_delete(struct vm_state *vms);
00136 static void set_update(MAILSTREAM * stream);
00137 static void init_vm_state(struct vm_state *vms);
00138 static void check_msgArray(struct vm_state *vms);
00139 static void copy_msgArray(struct vm_state *dst, struct vm_state *src);
00140 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format);
00141 static int make_gsm_file(char *dest, size_t len, char *imapuser, char *dir, int num);
00142 static void get_mailbox_delimiter(MAILSTREAM *stream);
00143 static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
00144 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
00145 static int imap_store_file(char *dir, char *mailboxuser, char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms);
00146 static void check_quota(struct vm_state *vms, char *mailbox);
00147 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box);
00148 struct vmstate {
00149 struct vm_state *vms;
00150 struct vmstate *next;
00151 };
00152 AST_MUTEX_DEFINE_STATIC(vmstate_lock);
00153 static struct vmstate *vmstates = NULL;
00154 #endif
00155
00156 #define SMDI_MWI_WAIT_TIMEOUT 1000
00157
00158 #define COMMAND_TIMEOUT 5000
00159
00160 #define VOICEMAIL_DIR_MODE 0777
00161 #define VOICEMAIL_FILE_MODE 0666
00162 #define CHUNKSIZE 65536
00163
00164 #define VOICEMAIL_CONFIG "voicemail.conf"
00165 #define ASTERISK_USERNAME "asterisk"
00166
00167
00168
00169 #define SENDMAIL "/usr/sbin/sendmail -t"
00170
00171 #define INTRO "vm-intro"
00172
00173 #define MAXMSG 100
00174 #ifndef IMAP_STORAGE
00175 #define MAXMSGLIMIT 9999
00176 #else
00177 #define MAXMSGLIMIT 255
00178 #endif
00179
00180 #define BASEMAXINLINE 256
00181 #define BASELINELEN 72
00182 #define BASEMAXINLINE 256
00183 #define eol "\r\n"
00184
00185 #define MAX_DATETIME_FORMAT 512
00186 #define MAX_NUM_CID_CONTEXTS 10
00187
00188 #define VM_REVIEW (1 << 0)
00189 #define VM_OPERATOR (1 << 1)
00190 #define VM_SAYCID (1 << 2)
00191 #define VM_SVMAIL (1 << 3)
00192 #define VM_ENVELOPE (1 << 4)
00193 #define VM_SAYDURATION (1 << 5)
00194 #define VM_SKIPAFTERCMD (1 << 6)
00195 #define VM_FORCENAME (1 << 7)
00196 #define VM_FORCEGREET (1 << 8)
00197 #define VM_PBXSKIP (1 << 9)
00198 #define VM_DIRECFORWARD (1 << 10)
00199 #define VM_ATTACH (1 << 11)
00200 #define VM_DELETE (1 << 12)
00201 #define VM_ALLOCED (1 << 13)
00202 #define VM_SEARCH (1 << 14)
00203 #define VM_TEMPGREETWARN (1 << 15)
00204 #define ERROR_LOCK_PATH -100
00205 #define ERROR_MAILBOX_FULL -200
00206
00207
00208 enum {
00209 OPT_SILENT = (1 << 0),
00210 OPT_BUSY_GREETING = (1 << 1),
00211 OPT_UNAVAIL_GREETING = (1 << 2),
00212 OPT_RECORDGAIN = (1 << 3),
00213 OPT_PREPEND_MAILBOX = (1 << 4),
00214 OPT_PRIORITY_JUMP = (1 << 5),
00215 OPT_AUTOPLAY = (1 << 6),
00216 } vm_option_flags;
00217
00218 enum {
00219 OPT_ARG_RECORDGAIN = 0,
00220 OPT_ARG_PLAYFOLDER = 1,
00221
00222 OPT_ARG_ARRAY_SIZE = 2,
00223 } vm_option_args;
00224
00225 AST_APP_OPTIONS(vm_app_options, {
00226 AST_APP_OPTION('s', OPT_SILENT),
00227 AST_APP_OPTION('b', OPT_BUSY_GREETING),
00228 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
00229 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
00230 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
00231 AST_APP_OPTION('j', OPT_PRIORITY_JUMP),
00232 AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
00233 });
00234
00235 static int load_config(void);
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 struct baseio {
00317 int iocp;
00318 int iolen;
00319 int linelength;
00320 int ateof;
00321 unsigned char iobuf[BASEMAXINLINE];
00322 };
00323
00324
00325 struct ast_vm_user {
00326 char context[AST_MAX_CONTEXT];
00327 char mailbox[AST_MAX_EXTENSION];
00328 char password[80];
00329 char fullname[80];
00330 char email[80];
00331 char pager[80];
00332 char serveremail[80];
00333 char mailcmd[160];
00334 char language[MAX_LANGUAGE];
00335 char zonetag[80];
00336 char callback[80];
00337 char dialout[80];
00338 char uniqueid[80];
00339 char exit[80];
00340 char attachfmt[20];
00341 unsigned int flags;
00342 int saydurationm;
00343 int maxmsg;
00344 #ifdef IMAP_STORAGE
00345 char imapuser[80];
00346 char imappassword[80];
00347 #endif
00348 double volgain;
00349 AST_LIST_ENTRY(ast_vm_user) list;
00350 };
00351
00352 struct vm_zone {
00353 AST_LIST_ENTRY(vm_zone) list;
00354 char name[80];
00355 char timezone[80];
00356 char msg_format[512];
00357 };
00358
00359 struct vm_state {
00360 char curbox[80];
00361 char username[80];
00362 char curdir[PATH_MAX];
00363 char vmbox[PATH_MAX];
00364 char fn[PATH_MAX];
00365 char fn2[PATH_MAX];
00366 int *deleted;
00367 int *heard;
00368 int curmsg;
00369 int lastmsg;
00370 int newmessages;
00371 int oldmessages;
00372 int starting;
00373 int repeats;
00374 #ifdef IMAP_STORAGE
00375 ast_mutex_t lock;
00376 int updated;
00377 long msgArray[256];
00378 MAILSTREAM *mailstream;
00379 int vmArrayIndex;
00380 char imapuser[80];
00381 int interactive;
00382 unsigned int quota_limit;
00383 unsigned int quota_usage;
00384 struct vm_state *persist_vms;
00385 #endif
00386 };
00387 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);
00388 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
00389 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
00390 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
00391 signed char record_gain, struct vm_state *vms);
00392 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
00393 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
00394 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *cidnum, char *cidname);
00395 static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, char *attach, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap);
00396 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
00397 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
00398 #endif
00399 static void apply_options(struct ast_vm_user *vmu, const char *options);
00400
00401 #ifdef ODBC_STORAGE
00402 static char odbc_database[80];
00403 static char odbc_table[80];
00404 #define RETRIEVE(a,b) retrieve_file(a,b)
00405 #define DISPOSE(a,b) remove_file(a,b)
00406 #define STORE(a,b,c,d,e,f,g,h,i) store_file(a,b,c,d)
00407 #define EXISTS(a,b,c,d) (message_exists(a,b))
00408 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
00409 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
00410 #define DELETE(a,b,c) (delete_file(a,b))
00411 #else
00412 #ifdef IMAP_STORAGE
00413 #define RETRIEVE(a,b)
00414 #define DISPOSE(a,b)
00415 #define STORE(a,b,c,d,e,f,g,h,i) (imap_store_file(a,b,c,d,e,f,g,h,i))
00416 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00417 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00418 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
00419 #define IMAP_DELETE(a,b,c,d) (vm_imap_delete(b,d))
00420 #define DELETE(a,b,c) (vm_delete(c))
00421 #else
00422 #define RETRIEVE(a,b)
00423 #define DISPOSE(a,b)
00424 #define STORE(a,b,c,d,e,f,g,h,i)
00425 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00426 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00427 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
00428 #define DELETE(a,b,c) (vm_delete(c))
00429 #endif
00430 #endif
00431
00432 static char VM_SPOOL_DIR[PATH_MAX];
00433
00434 static char ext_pass_cmd[128];
00435
00436 int my_umask;
00437
00438 #if ODBC_STORAGE
00439 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
00440 #elif IMAP_STORAGE
00441 #define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
00442 #else
00443 #define tdesc "Comedian Mail (Voicemail System)"
00444 #endif
00445
00446 static char userscontext[AST_MAX_EXTENSION] = "default";
00447
00448 static char *addesc = "Comedian Mail";
00449
00450 static char *synopsis_vm =
00451 "Leave a Voicemail message";
00452
00453 static char *descrip_vm =
00454 " VoiceMail(mailbox[@context][&mailbox[@context]][...][|options]): This\n"
00455 "application allows the calling party to leave a message for the specified\n"
00456 "list of mailboxes. When multiple mailboxes are specified, the greeting will\n"
00457 "be taken from the first mailbox specified. Dialplan execution will stop if the\n"
00458 "specified mailbox does not exist.\n"
00459 " The Voicemail application will exit if any of the following DTMF digits are\n"
00460 "received:\n"
00461 " 0 - Jump to the 'o' extension in the current dialplan context.\n"
00462 " * - Jump to the 'a' extension in the current dialplan context.\n"
00463 " This application will set the following channel variable upon completion:\n"
00464 " VMSTATUS - This indicates the status of the execution of the VoiceMail\n"
00465 " application. The possible values are:\n"
00466 " SUCCESS | USEREXIT | FAILED\n\n"
00467 " Options:\n"
00468 " b - Play the 'busy' greeting to the calling party.\n"
00469 " g(#) - Use the specified amount of gain when recording the voicemail\n"
00470 " message. The units are whole-number decibels (dB).\n"
00471 " Only works on supported technologies, which is Zap only.\n"
00472 " s - Skip the playback of instructions for leaving a message to the\n"
00473 " calling party.\n"
00474 " u - Play the 'unavailable' greeting.\n"
00475 " j - Jump to priority n+101 if the mailbox is not found or some other\n"
00476 " error occurs.\n";
00477
00478 static char *synopsis_vmain =
00479 "Check Voicemail messages";
00480
00481 static char *descrip_vmain =
00482 " VoiceMailMain([mailbox][@context][|options]): This application allows the\n"
00483 "calling party to check voicemail messages. A specific mailbox, and optional\n"
00484 "corresponding context, may be specified. If a mailbox is not provided, the\n"
00485 "calling party will be prompted to enter one. If a context is not specified,\n"
00486 "the 'default' context will be used.\n\n"
00487 " Options:\n"
00488 " p - Consider the mailbox parameter as a prefix to the mailbox that\n"
00489 " is entered by the caller.\n"
00490 " g(#) - Use the specified amount of gain when recording a voicemail\n"
00491 " message. The units are whole-number decibels (dB).\n"
00492 " s - Skip checking the passcode for the mailbox.\n"
00493 " a(#) - Skip folder prompt and go directly to folder specified.\n"
00494 " Defaults to INBOX\n";
00495
00496 static char *synopsis_vm_box_exists =
00497 "Check to see if Voicemail mailbox exists";
00498
00499 static char *descrip_vm_box_exists =
00500 " MailboxExists(mailbox[@context][|options]): Check to see if the specified\n"
00501 "mailbox exists. If no voicemail context is specified, the 'default' context\n"
00502 "will be used.\n"
00503 " This application will set the following channel variable upon completion:\n"
00504 " VMBOXEXISTSSTATUS - This will contain the status of the execution of the\n"
00505 " MailboxExists application. Possible values include:\n"
00506 " SUCCESS | FAILED\n\n"
00507 " Options:\n"
00508 " j - Jump to priority n+101 if the mailbox is found.\n";
00509
00510 static char *synopsis_vmauthenticate =
00511 "Authenticate with Voicemail passwords";
00512
00513 static char *descrip_vmauthenticate =
00514 " VMAuthenticate([mailbox][@context][|options]): This application behaves the\n"
00515 "same way as the Authenticate application, but the passwords are taken from\n"
00516 "voicemail.conf.\n"
00517 " If the mailbox is specified, only that mailbox's password will be considered\n"
00518 "valid. If the mailbox is not specified, the channel variable AUTH_MAILBOX will\n"
00519 "be set with the authenticated mailbox.\n\n"
00520 " Options:\n"
00521 " s - Skip playing the initial prompts.\n";
00522
00523
00524 static char *app = "VoiceMail";
00525
00526
00527 static char *app2 = "VoiceMailMain";
00528
00529 static char *app3 = "MailboxExists";
00530 static char *app4 = "VMAuthenticate";
00531
00532 static AST_LIST_HEAD_STATIC(users, ast_vm_user);
00533 static AST_LIST_HEAD_STATIC(zones, vm_zone);
00534 static int maxsilence;
00535 static int maxmsg;
00536 static int silencethreshold = 128;
00537 static char serveremail[80];
00538 static char mailcmd[160];
00539 static char externnotify[160];
00540 static struct ast_smdi_interface *smdi_iface = NULL;
00541 static char vmfmts[80];
00542 static double volgain;
00543 static int vmminmessage;
00544 static int vmmaxmessage;
00545 static int maxgreet;
00546 static int skipms;
00547 static int maxlogins;
00548
00549 static struct ast_flags globalflags = {0};
00550
00551 static int saydurationminfo;
00552
00553 static char dialcontext[AST_MAX_CONTEXT];
00554 static char callcontext[AST_MAX_CONTEXT];
00555 static char exitcontext[AST_MAX_CONTEXT];
00556
00557 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
00558
00559
00560 static char *emailbody = NULL;
00561 static char *emailsubject = NULL;
00562 static char *pagerbody = NULL;
00563 static char *pagersubject = NULL;
00564 static char fromstring[100];
00565 static char pagerfromstring[100];
00566 static char emailtitle[100];
00567 static char charset[32] = "ISO-8859-1";
00568
00569 static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
00570 static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
00571 static int adsiver = 1;
00572 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
00573
00574
00575 static void populate_defaults(struct ast_vm_user *vmu)
00576 {
00577 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
00578 if (saydurationminfo)
00579 vmu->saydurationm = saydurationminfo;
00580 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
00581 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
00582 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
00583 if (maxmsg)
00584 vmu->maxmsg = maxmsg;
00585 vmu->volgain = volgain;
00586 }
00587
00588 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
00589 {
00590 int x;
00591 if (!strcasecmp(var, "attach")) {
00592 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
00593 } else if (!strcasecmp(var, "attachfmt")) {
00594 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
00595 } else if (!strcasecmp(var, "serveremail")) {
00596 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
00597 } else if (!strcasecmp(var, "language")) {
00598 ast_copy_string(vmu->language, value, sizeof(vmu->language));
00599 } else if (!strcasecmp(var, "tz")) {
00600 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
00601 #ifdef IMAP_STORAGE
00602 } else if (!strcasecmp(var, "imapuser")) {
00603 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
00604 } else if (!strcasecmp(var, "imappassword")) {
00605 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
00606 #endif
00607 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
00608 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
00609 } else if (!strcasecmp(var, "saycid")){
00610 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
00611 } else if (!strcasecmp(var,"sendvoicemail")){
00612 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
00613 } else if (!strcasecmp(var, "review")){
00614 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
00615 } else if (!strcasecmp(var, "tempgreetwarn")){
00616 ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
00617 } else if (!strcasecmp(var, "operator")){
00618 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
00619 } else if (!strcasecmp(var, "envelope")){
00620 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
00621 } else if (!strcasecmp(var, "sayduration")){
00622 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
00623 } else if (!strcasecmp(var, "saydurationm")){
00624 if (sscanf(value, "%d", &x) == 1) {
00625 vmu->saydurationm = x;
00626 } else {
00627 ast_log(LOG_WARNING, "Invalid min duration for say duration\n");
00628 }
00629 } else if (!strcasecmp(var, "forcename")){
00630 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
00631 } else if (!strcasecmp(var, "forcegreetings")){
00632 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
00633 } else if (!strcasecmp(var, "callback")) {
00634 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
00635 } else if (!strcasecmp(var, "dialout")) {
00636 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
00637 } else if (!strcasecmp(var, "exitcontext")) {
00638 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
00639 } else if (!strcasecmp(var, "maxmsg")) {
00640 vmu->maxmsg = atoi(value);
00641 if (vmu->maxmsg <= 0) {
00642 ast_log(LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %i\n", value, MAXMSG);
00643 vmu->maxmsg = MAXMSG;
00644 } else if (vmu->maxmsg > MAXMSGLIMIT) {
00645 ast_log(LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
00646 vmu->maxmsg = MAXMSGLIMIT;
00647 }
00648 } else if (!strcasecmp(var, "volgain")) {
00649 sscanf(value, "%lf", &vmu->volgain);
00650 } else if (!strcasecmp(var, "options")) {
00651 apply_options(vmu, value);
00652 }
00653 }
00654
00655 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
00656 {
00657 int res;
00658 if (!ast_strlen_zero(vmu->uniqueid)) {
00659 res = ast_update_realtime("voicemail", "uniqueid", vmu->uniqueid, "password", password, NULL);
00660 if (res > 0) {
00661 ast_copy_string(vmu->password, password, sizeof(vmu->password));
00662 res = 0;
00663 } else if (!res) {
00664 res = -1;
00665 }
00666 return res;
00667 }
00668 return -1;
00669 }
00670
00671 static void apply_options(struct ast_vm_user *vmu, const char *options)
00672 {
00673 char *stringp;
00674 char *s;
00675 char *var, *value;
00676 stringp = ast_strdupa(options);
00677 while ((s = strsep(&stringp, "|"))) {
00678 value = s;
00679 if ((var = strsep(&value, "=")) && value) {
00680 apply_option(vmu, var, value);
00681 }
00682 }
00683 }
00684
00685 static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
00686 {
00687 struct ast_variable *tmp;
00688 tmp = var;
00689 while (tmp) {
00690 if (!strcasecmp(tmp->name, "vmsecret")) {
00691 ast_copy_string(retval->password, tmp->value, sizeof(retval->password));
00692 } else if (!strcasecmp(tmp->name, "secret") || !strcasecmp(tmp->name, "password")) {
00693 if (ast_strlen_zero(retval->password))
00694 ast_copy_string(retval->password, tmp->value, sizeof(retval->password));
00695 } else if (!strcasecmp(tmp->name, "uniqueid")) {
00696 ast_copy_string(retval->uniqueid, tmp->value, sizeof(retval->uniqueid));
00697 } else if (!strcasecmp(tmp->name, "pager")) {
00698 ast_copy_string(retval->pager, tmp->value, sizeof(retval->pager));
00699 } else if (!strcasecmp(tmp->name, "email")) {
00700 ast_copy_string(retval->email, tmp->value, sizeof(retval->email));
00701 } else if (!strcasecmp(tmp->name, "fullname")) {
00702 ast_copy_string(retval->fullname, tmp->value, sizeof(retval->fullname));
00703 } else if (!strcasecmp(tmp->name, "context")) {
00704 ast_copy_string(retval->context, tmp->value, sizeof(retval->context));
00705 #ifdef IMAP_STORAGE
00706 } else if (!strcasecmp(tmp->name, "imapuser")) {
00707 ast_copy_string(retval->imapuser, tmp->value, sizeof(retval->imapuser));
00708 } else if (!strcasecmp(tmp->name, "imappassword")) {
00709 ast_copy_string(retval->imappassword, tmp->value, sizeof(retval->imappassword));
00710 #endif
00711 } else
00712 apply_option(retval, tmp->name, tmp->value);
00713 tmp = tmp->next;
00714 }
00715 }
00716
00717 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
00718 {
00719 struct ast_variable *var;
00720 struct ast_vm_user *retval;
00721
00722 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
00723 if (!ivm)
00724 ast_set_flag(retval, VM_ALLOCED);
00725 else
00726 memset(retval, 0, sizeof(*retval));
00727 if (mailbox)
00728 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
00729 populate_defaults(retval);
00730 if (!context && ast_test_flag((&globalflags), VM_SEARCH))
00731 var = ast_load_realtime("voicemail", "mailbox", mailbox, NULL);
00732 else
00733 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, NULL);
00734 if (var) {
00735 apply_options_full(retval, var);
00736 ast_variables_destroy(var);
00737 } else {
00738 if (!ivm)
00739 free(retval);
00740 retval = NULL;
00741 }
00742 }
00743 return retval;
00744 }
00745
00746 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
00747 {
00748
00749 struct ast_vm_user *vmu=NULL, *cur;
00750 AST_LIST_LOCK(&users);
00751
00752 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
00753 context = "default";
00754
00755 AST_LIST_TRAVERSE(&users, cur, list) {
00756 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
00757 break;
00758 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
00759 break;
00760 }
00761 if (cur) {
00762
00763 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
00764 memcpy(vmu, cur, sizeof(*vmu));
00765 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
00766 AST_LIST_NEXT(vmu, list) = NULL;
00767 }
00768 } else
00769 vmu = find_user_realtime(ivm, context, mailbox);
00770 AST_LIST_UNLOCK(&users);
00771 return vmu;
00772 }
00773
00774 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
00775 {
00776
00777 struct ast_vm_user *cur;
00778 int res = -1;
00779 AST_LIST_LOCK(&users);
00780 AST_LIST_TRAVERSE(&users, cur, list) {
00781 if ((!context || !strcasecmp(context, cur->context)) &&
00782 (!strcasecmp(mailbox, cur->mailbox)))
00783 break;
00784 }
00785 if (cur) {
00786 ast_copy_string(cur->password, newpass, sizeof(cur->password));
00787 res = 0;
00788 }
00789 AST_LIST_UNLOCK(&users);
00790 return res;
00791 }
00792
00793 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
00794 {
00795 struct ast_config *cfg=NULL;
00796 struct ast_variable *var=NULL;
00797 struct ast_category *cat=NULL;
00798 char *category=NULL, *value=NULL, *new=NULL;
00799 const char *tmp=NULL;
00800
00801 if (!change_password_realtime(vmu, newpassword))
00802 return;
00803
00804
00805 if ((cfg = ast_config_load_with_comments(VOICEMAIL_CONFIG))) {
00806 while ((category = ast_category_browse(cfg, category))) {
00807 if (!strcasecmp(category, vmu->context)) {
00808 tmp = ast_variable_retrieve(cfg, category, vmu->mailbox);
00809 if (!tmp) {
00810 ast_log(LOG_WARNING, "We could not find the mailbox.\n");
00811 break;
00812 }
00813 value = strstr(tmp,",");
00814 if (!value) {
00815 ast_log(LOG_WARNING, "variable has bad format.\n");
00816 break;
00817 }
00818 new = alloca((strlen(value)+strlen(newpassword)+1));
00819 sprintf(new,"%s%s", newpassword, value);
00820 if (!(cat = ast_category_get(cfg, category))) {
00821 ast_log(LOG_WARNING, "Failed to get category structure.\n");
00822 break;
00823 }
00824 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
00825 }
00826 }
00827
00828 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
00829 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
00830 config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
00831 }
00832 category = NULL;
00833 var = NULL;
00834
00835
00836 if ((cfg = ast_config_load_with_comments("users.conf"))) {
00837 if (option_debug > 3)
00838 ast_log(LOG_DEBUG, "we are looking for %s\n", vmu->mailbox);
00839 while ((category = ast_category_browse(cfg, category))) {
00840 if (option_debug > 3)
00841 ast_log(LOG_DEBUG, "users.conf: %s\n", category);
00842 if (!strcasecmp(category, vmu->mailbox)) {
00843 if (!(tmp = ast_variable_retrieve(cfg, category, "vmsecret"))) {
00844 if (option_debug > 3)
00845 ast_log(LOG_DEBUG, "looks like we need to make vmsecret!\n");
00846 var = ast_variable_new("vmsecret", newpassword);
00847 }
00848 new = alloca(strlen(newpassword)+1);
00849 sprintf(new, "%s", newpassword);
00850 if (!(cat = ast_category_get(cfg, category))) {
00851 if (option_debug > 3)
00852 ast_log(LOG_DEBUG, "failed to get category!\n");
00853 break;
00854 }
00855 if (!var)
00856 ast_variable_update(cat, "vmsecret", new, NULL, 0);
00857 else
00858 ast_variable_append(cat, var);
00859 }
00860 }
00861
00862 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
00863 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
00864 config_text_file_save("users.conf", cfg, "AppVoicemail");
00865 }
00866 }
00867
00868 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
00869 {
00870 char buf[255];
00871 snprintf(buf,255,"%s %s %s %s",ext_pass_cmd,vmu->context,vmu->mailbox,newpassword);
00872 if (!ast_safe_system(buf)) {
00873 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
00874
00875 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
00876 }
00877 }
00878
00879 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
00880 {
00881 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
00882 }
00883
00884 #ifdef IMAP_STORAGE
00885 static int make_gsm_file(char *dest, size_t len, char *imapuser, char *dir, int num)
00886 {
00887 if (mkdir(dir, 01777) && (errno != EEXIST)) {
00888 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
00889 return snprintf(dest, len, "%s/msg%04d", dir, num);
00890 }
00891 return snprintf(dest, len, "%s/msg%04d", dir, num);
00892 }
00893
00894 static void vm_imap_delete(int msgnum, struct vm_state *vms)
00895 {
00896 unsigned long messageNum = 0;
00897 char arg[10];
00898
00899
00900
00901
00902 messageNum = vms->msgArray[msgnum];
00903 if (messageNum == 0) {
00904 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n",msgnum,messageNum);
00905 return;
00906 }
00907 if (option_debug > 2)
00908 ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n",msgnum,messageNum);
00909
00910 snprintf (arg, sizeof(arg), "%lu",messageNum);
00911 mail_setflag (vms->mailstream,arg,"\\DELETED");
00912 }
00913
00914 #endif
00915 static int make_file(char *dest, int len, char *dir, int num)
00916 {
00917 return snprintf(dest, len, "%s/msg%04d", dir, num);
00918 }
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
00929 {
00930 mode_t mode = VOICEMAIL_DIR_MODE;
00931
00932 if (!ast_strlen_zero(context)) {
00933 make_dir(dest, len, context, "", "");
00934 if (mkdir(dest, mode) && errno != EEXIST) {
00935 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dest, strerror(errno));
00936 return -1;
00937 }
00938 }
00939 if (!ast_strlen_zero(ext)) {
00940 make_dir(dest, len, context, ext, "");
00941 if (mkdir(dest, mode) && errno != EEXIST) {
00942 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dest, strerror(errno));
00943 return -1;
00944 }
00945 }
00946 if (!ast_strlen_zero(folder)) {
00947 make_dir(dest, len, context, ext, folder);
00948 if (mkdir(dest, mode) && errno != EEXIST) {
00949 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dest, strerror(errno));
00950 return -1;
00951 }
00952 }
00953 return 0;
00954 }
00955
00956
00957
00958
00959 static int vm_lock_path(const char *path)
00960 {
00961 switch (ast_lock_path(path)) {
00962 case AST_LOCK_TIMEOUT:
00963 return -1;
00964 default:
00965 return 0;
00966 }
00967 }
00968
00969
00970 #ifdef ODBC_STORAGE
00971 struct generic_prepare_struct {
00972 char *sql;
00973 int argc;
00974 char **argv;
00975 };
00976
00977 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
00978 {
00979 struct generic_prepare_struct *gps = data;
00980 int res, i;
00981 SQLHSTMT stmt;
00982
00983 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
00984 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00985 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
00986 return NULL;
00987 }
00988 res = SQLPrepare(stmt, (unsigned char *)gps->sql, SQL_NTS);
00989 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00990 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
00991 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00992 return NULL;
00993 }
00994 for (i = 0; i < gps->argc; i++)
00995 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
00996
00997 return stmt;
00998 }
00999
01000 static int retrieve_file(char *dir, int msgnum)
01001 {
01002 int x = 0;
01003 int res;
01004 int fd=-1;
01005 size_t fdlen = 0;
01006 void *fdm = MAP_FAILED;
01007 SQLSMALLINT colcount=0;
01008 SQLHSTMT stmt;
01009 char sql[PATH_MAX];
01010 char fmt[80]="";
01011 char *c;
01012 char coltitle[256];
01013 SQLSMALLINT collen;
01014 SQLSMALLINT datatype;
01015 SQLSMALLINT decimaldigits;
01016 SQLSMALLINT nullable;
01017 SQLULEN colsize;
01018 SQLLEN colsize2;
01019 FILE *f=NULL;
01020 char rowdata[80];
01021 char fn[PATH_MAX];
01022 char full_fn[PATH_MAX];
01023 char msgnums[80];
01024 char *argv[] = { dir, msgnums };
01025 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
01026
01027 struct odbc_obj *obj;
01028 obj = ast_odbc_request_obj(odbc_database, 0);
01029 if (obj) {
01030 ast_copy_string(fmt, vmfmts, sizeof(fmt));
01031 c = strchr(fmt, '|');
01032 if (c)
01033 *c = '\0';
01034 if (!strcasecmp(fmt, "wav49"))
01035 strcpy(fmt, "WAV");
01036 snprintf(msgnums, sizeof(msgnums),"%d", msgnum);
01037 if (msgnum > -1)
01038 make_file(fn, sizeof(fn), dir, msgnum);
01039 else
01040 ast_copy_string(fn, dir, sizeof(fn));
01041 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
01042
01043 if (!(f = fopen(full_fn, "w+"))) {
01044 ast_log(LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
01045 goto yuck;
01046 }
01047
01048 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
01049 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?",odbc_table);
01050 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
01051 if (!stmt) {
01052 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
01053 ast_odbc_release_obj(obj);
01054 goto yuck;
01055 }
01056 res = SQLFetch(stmt);
01057 if (res == SQL_NO_DATA) {
01058 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
01059 ast_odbc_release_obj(obj);
01060 goto yuck;
01061 }
01062 else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01063 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
01064 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
01065 ast_odbc_release_obj(obj);
01066 goto yuck;
01067 }
01068 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, 0770);
01069 if (fd < 0) {
01070 ast_log(LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
01071 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
01072 ast_odbc_release_obj(obj);
01073 goto yuck;
01074 }
01075 res = SQLNumResultCols(stmt, &colcount);
01076 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01077 ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
01078 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
01079 ast_odbc_release_obj(obj);
01080 goto yuck;
01081 }
01082 if (f)
01083 fprintf(f, "[message]\n");
01084 for (x=0;x<colcount;x++) {
01085 rowdata[0] = '\0';
01086 collen = sizeof(coltitle);
01087 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen,
01088 &datatype, &colsize, &decimaldigits, &nullable);
01089 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01090 ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
01091 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
01092 ast_odbc_release_obj(obj);
01093 goto yuck;
01094 }
01095 if (!strcasecmp(coltitle, "recording")) {
01096 off_t offset;
01097 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
01098 fdlen = colsize2;
01099 if (fd > -1) {
01100 char tmp[1]="";
01101 lseek(fd, fdlen - 1, SEEK_SET);
01102 if (write(fd, tmp, 1) != 1) {
01103 close(fd);
01104 fd = -1;
01105 continue;
01106 }
01107
01108 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
01109 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
01110 ast_log(LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
01111 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
01112 ast_odbc_release_obj(obj);
01113 goto yuck;
01114 } else {
01115 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
01116 munmap(fdm, CHUNKSIZE);
01117 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01118 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
01119 unlink(full_fn);
01120 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
01121 ast_odbc_release_obj(obj);
01122 goto yuck;
01123 }
01124 }
01125 }
01126 truncate(full_fn, fdlen);
01127 }
01128 } else {
01129 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
01130 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01131 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
01132 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
01133 ast_odbc_release_obj(obj);
01134 goto yuck;
01135 }
01136 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
01137 fprintf(f, "%s=%s\n", coltitle, rowdata);
01138 }
01139 }
01140 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
01141 ast_odbc_release_obj(obj);
01142 } else
01143 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
01144 yuck:
01145 if (f)
01146 fclose(f);
01147 if (fd > -1)
01148 close(fd);
01149 return x - 1;
01150 }
01151
01152 static int remove_file(char *dir, int msgnum)
01153 {
01154 char fn[PATH_MAX];
01155 char full_fn[PATH_MAX];
01156 char msgnums[80];
01157
01158 if (msgnum > -1) {
01159 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
01160 make_file(fn, sizeof(fn), dir, msgnum);
01161 } else
01162 ast_copy_string(fn, dir, sizeof(fn));
01163 ast_filedelete(fn, NULL);
01164 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
01165 unlink(full_fn);
01166 return 0;
01167 }
01168
01169 static int last_message_index(struct ast_vm_user *vmu, char *dir)
01170 {
01171 int x = 0;
01172 int res;
01173 SQLHSTMT stmt;
01174 char sql[PATH_MAX];
01175 char rowdata[20];
01176 char *argv[] = { dir };
01177 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
01178
01179 struct odbc_obj *obj;
01180 obj = ast_odbc_request_obj(odbc_database, 0);
01181 if (obj) {
01182 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?",odbc_table);
01183 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
01184 if (!stmt) {
01185 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
01186 ast_odbc_release_obj(obj);
01187 goto yuck;
01188 }
01189 res = SQLFetch(stmt);
01190 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01191 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
01192 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
01193 ast_odbc_release_obj(obj);
01194 goto yuck;
01195 }
01196 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
01197 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01198 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
01199 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
01200 ast_odbc_release_obj(obj);
01201 goto yuck;
01202 }
01203 if (sscanf(rowdata, "%d", &x) != 1)
01204 ast_log(LOG_WARNING, "Failed to read message count!\n");
01205 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
01206 ast_odbc_release_obj(obj);
01207 } else
01208 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
01209 yuck:
01210 return x - 1;
01211 }
01212
01213 static int message_exists(char *dir, int msgnum)
01214 {
01215 int x = 0;
01216 int res;
01217 SQLHSTMT stmt;
01218 char sql[PATH_MAX];
01219 char rowdata[20];
01220 char msgnums[20];
01221 char *argv[] = { dir, msgnums };
01222 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
01223
01224 struct odbc_obj *obj;
01225 obj = ast_odbc_request_obj(odbc_database, 0);
01226 if (obj) {
01227 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
01228 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?",odbc_table);
01229 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
01230 if (!stmt) {
01231 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
01232 ast_odbc_release_obj(obj);
01233 goto yuck;
01234 }
01235 res = SQLFetch(stmt);
01236 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01237 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
01238 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
01239 ast_odbc_release_obj(obj);
01240 goto yuck;
01241 }
01242 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
01243 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01244 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
01245 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
01246 ast_odbc_release_obj(obj);
01247 goto yuck;
01248 }
01249 if (sscanf(rowdata, "%d", &x) != 1)
01250 ast_log(LOG_WARNING, "Failed to read message count!\n");
01251 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
01252 ast_odbc_release_obj(obj);
01253 } else
01254 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
01255 yuck:
01256 return x;
01257 }
01258
01259 static int count_messages(struct ast_vm_user *vmu, char *dir)
01260 {
01261 return last_message_index(vmu, dir) + 1;
01262 }
01263
01264 static void delete_file(char *sdir, int smsg)
01265 {
01266 SQLHSTMT stmt;
01267 char sql[PATH_MAX];
01268 char msgnums[20];
01269 char *argv[] = { sdir, msgnums };
01270 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
01271
01272 struct odbc_obj *obj;
01273 obj = ast_odbc_request_obj(odbc_database, 0);
01274 if (obj) {
01275 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
01276 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?",odbc_table);
01277 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
01278 if (!stmt)
01279 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
01280 else
01281 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
01282 ast_odbc_release_obj(obj);
01283 } else
01284 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
01285 return;
01286 }
01287
01288 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
01289 {
01290 SQLHSTMT stmt;
01291 char sql[512];
01292 char msgnums[20];
01293 char msgnumd[20];
01294 struct odbc_obj *obj;
01295 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
01296 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
01297
01298 delete_file(ddir, dmsg);
01299 obj = ast_odbc_request_obj(odbc_database, 0);
01300 if (obj) {
01301 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
01302 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
01303 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir, msgnum, context, macrocontext, callerid, origtime, duration, recording, mailboxuser, mailboxcontext) SELECT ?,?,context,macrocontext,callerid,origtime,duration,recording,?,? FROM %s WHERE dir=? AND msgnum=?",odbc_table,odbc_table);
01304 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
01305 if (!stmt)
01306 ast_log(LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
01307 else
01308 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
01309 ast_odbc_release_obj(obj);
01310 } else
01311 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
01312 return;
01313 }
01314
01315 static int store_file(char *dir, char *mailboxuser, char *mailboxcontext, int msgnum)
01316 {
01317 int x = 0;
01318 int res;
01319 int fd = -1;
01320 void *fdm = MAP_FAILED;
01321 size_t fdlen = -1;
01322 SQLHSTMT stmt;
01323 SQLLEN len;
01324 char sql[PATH_MAX];
01325 char msgnums[20];
01326 char fn[PATH_MAX];
01327 char full_fn[PATH_MAX];
01328 char fmt[80]="";
01329 char *c;
01330 const char *context="", *macrocontext="", *callerid="", *origtime="", *duration="";
01331 const char *category = "";
01332 struct ast_config *cfg=NULL;
01333 struct odbc_obj *obj;
01334
01335 delete_file(dir, msgnum);
01336 obj = ast_odbc_request_obj(odbc_database, 0);
01337 if (obj) {
01338 ast_copy_string(fmt, vmfmts, sizeof(fmt));
01339 c = strchr(fmt, '|');
01340 if (c)
01341 *c = '\0';
01342 if (!strcasecmp(fmt, "wav49"))
01343 strcpy(fmt, "WAV");
01344 snprintf(msgnums, sizeof(msgnums),"%d", msgnum);
01345 if (msgnum > -1)
01346 make_file(fn, sizeof(fn), dir, msgnum);
01347 else
01348 ast_copy_string(fn, dir, sizeof(fn));
01349 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
01350 cfg = ast_config_load(full_fn);
01351 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
01352 fd = open(full_fn, O_RDWR);
01353 if (fd < 0) {
01354 ast_log(LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
01355 ast_odbc_release_obj(obj);
01356 goto yuck;
01357 }
01358 if (cfg) {
01359 context = ast_variable_retrieve(cfg, "message", "context");
01360 if (!context) context = "";
01361 macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext");
01362 if (!macrocontext) macrocontext = "";
01363 callerid = ast_variable_retrieve(cfg, "message", "callerid");
01364 if (!callerid) callerid = "";
01365 origtime = ast_variable_retrieve(cfg, "message", "origtime");
01366 if (!origtime) origtime = "";
01367 duration = ast_variable_retrieve(cfg, "message", "duration");
01368 if (!duration) duration = "";
01369 category = ast_variable_retrieve(cfg, "message", "category");
01370 if (!category) category = "";
01371 }
01372 fdlen = lseek(fd, 0, SEEK_END);
01373 lseek(fd, 0, SEEK_SET);
01374 printf("Length is %zd\n", fdlen);
01375 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED,fd, 0);
01376 if (fdm == MAP_FAILED) {
01377 ast_log(LOG_WARNING, "Memory map failed!\n");
01378 ast_odbc_release_obj(obj);
01379 goto yuck;
01380 }
01381 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
01382 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01383 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
01384 ast_odbc_release_obj(obj);
01385 goto yuck;
01386 }
01387 if (!ast_strlen_zero(category))
01388 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,category) VALUES (?,?,?,?,?,?,?,?,?,?,?)",odbc_table);
01389 else
01390 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext) VALUES (?,?,?,?,?,?,?,?,?,?)",odbc_table);
01391 res = SQLPrepare(stmt, (unsigned char *)sql, SQL_NTS);
01392 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01393 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
01394 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
01395 ast_odbc_release_obj(obj);
01396 goto yuck;
01397 }
01398 len = fdlen;
01399 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(dir), 0, (void *)dir, 0, NULL);
01400 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnums), 0, (void *)msgnums, 0, NULL);
01401 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, fdlen, 0, (void *)fdm, fdlen, &len);
01402 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(context), 0, (void *)context, 0, NULL);
01403 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(macrocontext), 0, (void *)macrocontext, 0, NULL);
01404 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(callerid), 0, (void *)callerid, 0, NULL);
01405 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(origtime), 0, (void *)origtime, 0, NULL);
01406 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(duration), 0, (void *)duration, 0, NULL);
01407 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(mailboxuser), 0, (void *)mailboxuser, 0, NULL);
01408 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(mailboxcontext), 0, (void *)mailboxcontext, 0, NULL);
01409 if (!ast_strlen_zero(category))
01410 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(category), 0, (void *)category, 0, NULL);
01411 res = ast_odbc_smart_execute(obj, stmt);
01412 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01413 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
01414 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
01415 ast_odbc_release_obj(obj);
01416 goto yuck;
01417 }
01418 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
01419 ast_odbc_release_obj(obj);
01420 } else
01421 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
01422 yuck:
01423 if (cfg)
01424 ast_config_destroy(cfg);
01425 if (fdm != MAP_FAILED)
01426 munmap(fdm, fdlen);
01427 if (fd > -1)
01428 close(fd);
01429 return x;
01430 }
01431
01432 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
01433 {
01434 SQLHSTMT stmt;
01435 char sql[PATH_MAX];
01436 char msgnums[20];
01437 char msgnumd[20];
01438 struct odbc_obj *obj;
01439 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
01440 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
01441
01442 delete_file(ddir, dmsg);
01443 obj = ast_odbc_request_obj(odbc_database, 0);
01444 if (obj) {
01445 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
01446 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
01447 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?",odbc_table);
01448 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
01449 if (!stmt)
01450 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
01451 else
01452 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
01453 ast_odbc_release_obj(obj);
01454 } else
01455 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
01456 return;
01457 }
01458
01459 #else
01460 #ifndef IMAP_STORAGE
01461 static int count_messages(struct ast_vm_user *vmu, char *dir)
01462 {
01463
01464
01465 int vmcount = 0;
01466 DIR *vmdir = NULL;
01467 struct dirent *vment = NULL;
01468
01469 if (vm_lock_path(dir))
01470 return ERROR_LOCK_PATH;
01471
01472 if ((vmdir = opendir(dir))) {
01473 while ((vment = readdir(vmdir))) {
01474 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4))
01475 vmcount++;
01476 }
01477 closedir(vmdir);
01478 }
01479 ast_unlock_path(dir);
01480
01481 return vmcount;
01482 }
01483
01484 static void rename_file(char *sfn, char *dfn)
01485 {
01486 char stxt[PATH_MAX];
01487 char dtxt[PATH_MAX];
01488 ast_filerename(sfn,dfn,NULL);
01489 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
01490 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
01491 rename(stxt, dtxt);
01492 }
01493 #endif
01494
01495
01496
01497
01498 #if (!defined(IMAP_STORAGE) && !defined(ODBC_STORAGE))
01499 static int last_message_index(struct ast_vm_user *vmu, char *dir)
01500 {
01501 int x;
01502 char fn[PATH_MAX];
01503
01504 if (vm_lock_path(dir))
01505 return ERROR_LOCK_PATH;
01506
01507 for (x = 0; x < vmu->maxmsg; x++) {
01508 make_file(fn, sizeof(fn), dir, x);
01509 if (ast_fileexists(fn, NULL, NULL) < 1)
01510 break;
01511 }
01512 ast_unlock_path(dir);
01513
01514 return x - 1;
01515 }
01516 #endif
01517 #endif
01518
01519 static int copy(char *infile, char *outfile)
01520 {
01521 int ifd;
01522 int ofd;
01523 int res;
01524 int len;
01525 char buf[4096];
01526
01527 #ifdef HARDLINK_WHEN_POSSIBLE
01528
01529 if (link(infile, outfile)) {
01530 #endif
01531 if ((ifd = open(infile, O_RDONLY)) < 0) {
01532 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
01533 return -1;
01534 }
01535 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
01536 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
01537 close(ifd);
01538 return -1;
01539 }
01540 do {
01541 len = read(ifd, buf, sizeof(buf));
01542 if (len < 0) {
01543 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
01544 close(ifd);
01545 close(ofd);
01546 unlink(outfile);
01547 }
01548 if (len) {
01549 res = write(ofd, buf, len);
01550 if (errno == ENOMEM || errno == ENOSPC || res != len) {
01551 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
01552 close(ifd);
01553 close(ofd);
01554 unlink(outfile);
01555 }
01556 }
01557 } while (len);
01558 close(ifd);
01559 close(ofd);
01560 return 0;
01561 #ifdef HARDLINK_WHEN_POSSIBLE
01562 } else {
01563
01564 return 0;
01565 }
01566 #endif
01567 }
01568
01569 static void copy_plain_file(char *frompath, char *topath)
01570 {
01571 char frompath2[PATH_MAX], topath2[PATH_MAX];
01572 ast_filecopy(frompath, topath, NULL);
01573 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
01574 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
01575 copy(frompath2, topath2);
01576 }
01577
01578 static int vm_delete(char *file)
01579 {
01580 char *txt;
01581 int txtsize = 0;
01582
01583 txtsize = (strlen(file) + 5)*sizeof(char);
01584 txt = alloca(txtsize);
01585
01586
01587
01588 snprintf(txt, txtsize, "%s.txt", file);
01589 unlink(txt);
01590 return ast_filedelete(file, NULL);
01591 }
01592
01593 static int inbuf(struct baseio *bio, FILE *fi)
01594 {
01595 int l;
01596
01597 if (bio->ateof)
01598 return 0;
01599
01600 if ((l = fread(bio->iobuf,1,BASEMAXINLINE,fi)) <= 0) {
01601 if (ferror(fi))
01602 return -1;
01603
01604 bio->ateof = 1;
01605 return 0;
01606 }
01607
01608 bio->iolen= l;
01609 bio->iocp= 0;
01610
01611 return 1;
01612 }
01613
01614 static int inchar(struct baseio *bio, FILE *fi)
01615 {
01616 if (bio->iocp>=bio->iolen) {
01617 if (!inbuf(bio, fi))
01618 return EOF;
01619 }
01620
01621 return bio->iobuf[bio->iocp++];
01622 }
01623
01624 static int ochar(struct baseio *bio, int c, FILE *so)
01625 {
01626 if (bio->linelength>=BASELINELEN) {
01627 if (fputs(eol,so)==EOF)
01628 return -1;
01629
01630 bio->linelength= 0;
01631 }
01632
01633 if (putc(((unsigned char)c),so)==EOF)
01634 return -1;
01635
01636 bio->linelength++;
01637
01638 return 1;
01639 }
01640
01641 static int base_encode(char *filename, FILE *so)
01642 {
01643 unsigned char dtable[BASEMAXINLINE];
01644 int i,hiteof= 0;
01645 FILE *fi;
01646 struct baseio bio;
01647
01648 memset(&bio, 0, sizeof(bio));
01649 bio.iocp = BASEMAXINLINE;
01650
01651 if (!(fi = fopen(filename, "rb"))) {
01652 ast_log(LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
01653 return -1;
01654 }
01655
01656 for (i= 0;i<9;i++) {
01657 dtable[i]= 'A'+i;
01658 dtable[i+9]= 'J'+i;
01659 dtable[26+i]= 'a'+i;
01660 dtable[26+i+9]= 'j'+i;
01661 }
01662 for (i= 0;i<8;i++) {
01663 dtable[i+18]= 'S'+i;
01664 dtable[26+i+18]= 's'+i;
01665 }
01666 for (i= 0;i<10;i++) {
01667 dtable[52+i]= '0'+i;
01668 }
01669 dtable[62]= '+';
01670 dtable[63]= '/';
01671
01672 while (!hiteof){
01673 unsigned char igroup[3],ogroup[4];
01674 int c,n;
01675
01676 igroup[0]= igroup[1]= igroup[2]= 0;
01677
01678 for (n= 0;n<3;n++) {
01679 if ((c = inchar(&bio, fi)) == EOF) {
01680 hiteof= 1;
01681 break;
01682 }
01683
01684 igroup[n]= (unsigned char)c;
01685 }
01686
01687 if (n> 0) {
01688 ogroup[0]= dtable[igroup[0]>>2];
01689 ogroup[1]= dtable[((igroup[0]&3)<<4)|(igroup[1]>>4)];
01690 ogroup[2]= dtable[((igroup[1]&0xF)<<2)|(igroup[2]>>6)];
01691 ogroup[3]= dtable[igroup[2]&0x3F];
01692
01693 if (n<3) {
01694 ogroup[3]= '=';
01695
01696 if (n<2)
01697 ogroup[2]= '=';
01698 }
01699
01700 for (i= 0;i<4;i++)
01701 ochar(&bio, ogroup[i], so);
01702 }
01703 }
01704
01705 fclose(fi);
01706
01707 if (fputs(eol,so)==EOF)
01708 return 0;
01709
01710 return 1;
01711 }
01712
01713 static void prep_email_sub_vars(struct ast_channel *ast, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, char *dur, char *date, char *passdata, size_t passdatasize, const char *category)
01714 {
01715 char callerid[256];
01716
01717 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
01718 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
01719 snprintf(passdata, passdatasize, "%d", msgnum);
01720 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", passdata);
01721 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
01722 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
01723 pbx_builtin_setvar_helper(ast, "VM_CALLERID", ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, "Unknown Caller"));
01724 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (cidname ? cidname : "an unknown caller"));
01725 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (cidnum ? cidnum : "an unknown caller"));
01726 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
01727 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
01728 }
01729
01730 static char *quote(const char *from, char *to, size_t len)
01731 {
01732 char *ptr = to;
01733 *ptr++ = '"';
01734 for (; ptr < to + len - 1; from++) {
01735 if (*from == '"')
01736 *ptr++ = '\\';
01737 else if (*from == '\0')
01738 break;
01739 *ptr++ = *from;
01740 }
01741 if (ptr < to + len - 1)
01742 *ptr++ = '"';
01743 *ptr = '\0';
01744 return to;
01745 }
01746
01747
01748
01749
01750 static const struct tm *vmu_tm(const struct ast_vm_user *vmu, struct tm *tm)
01751 {
01752 const struct vm_zone *z = NULL;
01753 time_t t = time(NULL);
01754
01755
01756 if (!ast_strlen_zero(vmu->zonetag)) {
01757
01758 AST_LIST_LOCK(&zones);
01759 AST_LIST_TRAVERSE(&zones, z, list) {
01760 if (!strcmp(z->name, vmu->zonetag))
01761 break;
01762 }
01763 AST_LIST_UNLOCK(&zones);
01764 }
01765 ast_localtime(&t, tm, z ? z->timezone : NULL);
01766 return tm;
01767 }
01768
01769
01770 static FILE *vm_mkftemp(char *template)
01771 {
01772 FILE *p = NULL;
01773 int pfd = mkstemp(template);
01774 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01775 if (pfd > -1) {
01776 p = fdopen(pfd, "w+");
01777 if (!p) {
01778 close(pfd);
01779 pfd = -1;
01780 }
01781 }
01782 return p;
01783 }
01784
01785 static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, char *attach, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap)
01786 {
01787 char date[256];
01788 char host[MAXHOSTNAMELEN] = "";
01789 char who[256];
01790 char bound[256];
01791 char fname[256];
01792 char dur[256];
01793 char tmpcmd[256];
01794 struct tm tm;
01795 char *passdata2;
01796 size_t len_passdata;
01797 #ifdef IMAP_STORAGE
01798 #define ENDL "\r\n"
01799 #else
01800 #define ENDL "\n"
01801 #endif
01802
01803 gethostname(host, sizeof(host) - 1);
01804 if (strchr(srcemail, '@'))
01805 ast_copy_string(who, srcemail, sizeof(who));
01806 else {
01807 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
01808 }
01809 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
01810 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
01811 fprintf(p, "Date: %s" ENDL, date);
01812
01813
01814 strftime(date, sizeof(date), emaildateformat, &tm);
01815
01816 if (*fromstring) {
01817 struct ast_channel *ast;
01818 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, 0))) {
01819 char *passdata;
01820 int vmlen = strlen(fromstring)*3 + 200;
01821 if ((passdata = alloca(vmlen))) {
01822 memset(passdata, 0, vmlen);
01823 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category);
01824 pbx_substitute_variables_helper(ast, fromstring, passdata, vmlen);
01825 len_passdata = strlen(passdata) * 2 + 3;
01826 passdata2 = alloca(len_passdata);
01827 fprintf(p, "From: %s <%s>" ENDL, quote(passdata, passdata2, len_passdata), who);
01828 } else
01829 ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
01830 ast_channel_free(ast);
01831 } else
01832 ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
01833 } else
01834 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
01835 len_passdata = strlen(vmu->fullname) * 2 + 3;
01836 passdata2 = alloca(len_passdata);
01837 fprintf(p, "To: %s <%s>" ENDL, quote(vmu->fullname, passdata2, len_passdata), vmu->email);
01838 if (emailsubject) {
01839 struct ast_channel *ast;
01840 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, 0))) {
01841 char *passdata;
01842 int vmlen = strlen(emailsubject)*3 + 200;
01843 if ((passdata = alloca(vmlen))) {
01844 memset(passdata, 0, vmlen);
01845 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category);
01846 pbx_substitute_variables_helper(ast, emailsubject, passdata, vmlen);
01847 fprintf(p, "Subject: %s" ENDL, passdata);
01848 } else
01849 ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
01850 ast_channel_free(ast);
01851 } else
01852 ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
01853 } else if (*emailtitle) {
01854 fprintf(p, emailtitle, msgnum + 1, mailbox) ;
01855 fprintf(p, ENDL) ;
01856 } else if (ast_test_flag((&globalflags), VM_PBXSKIP))
01857 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
01858 else
01859 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
01860 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1, (unsigned int)ast_random(), mailbox, (int)getpid(), host);
01861 if (imap) {
01862
01863 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
01864
01865 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
01866 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
01867 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
01868 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
01869 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
01870 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, cidnum);
01871 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, cidname);
01872 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
01873 if (!ast_strlen_zero(category))
01874 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
01875 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
01876 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long)time(NULL));
01877 }
01878 if (!ast_strlen_zero(cidnum))
01879 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, cidnum);
01880 if (!ast_strlen_zero(cidname))
01881 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, cidname);
01882 fprintf(p, "MIME-Version: 1.0" ENDL);
01883 if (attach_user_voicemail) {
01884
01885 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox, (int)getpid(), (unsigned int)ast_random());
01886
01887 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
01888 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
01889 fprintf(p, "--%s" ENDL, bound);
01890 }
01891 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
01892 if (emailbody) {
01893 struct ast_channel *ast;
01894 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, 0))) {
01895 char *passdata;
01896 int vmlen = strlen(emailbody)*3 + 200;
01897 if ((passdata = alloca(vmlen))) {
01898 memset(passdata, 0, vmlen);
01899 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category);
01900 pbx_substitute_variables_helper(ast, emailbody, passdata, vmlen);
01901 fprintf(p, "%s" ENDL, passdata);
01902 } else
01903 ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
01904 ast_channel_free(ast);
01905 } else
01906 ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
01907 } else {
01908 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a %s long message (number %d)" ENDL
01909
01910 "in mailbox %s from %s, on %s so you might" ENDL
01911 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname,
01912 dur, msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
01913 }
01914 if (attach_user_voicemail) {
01915
01916 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
01917 char tmpdir[256], newtmp[256];
01918 int tmpfd = -1;
01919
01920 if (vmu->volgain < -.001 || vmu->volgain > .001) {
01921 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
01922 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
01923 tmpfd = mkstemp(newtmp);
01924 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
01925 if (option_debug > 2)
01926 ast_log(LOG_DEBUG, "newtmp: %s\n", newtmp);
01927 if (tmpfd > -1) {
01928 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
01929 ast_safe_system(tmpcmd);
01930 attach = newtmp;
01931 if (option_debug > 2)
01932 ast_log(LOG_DEBUG, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
01933 }
01934 }
01935 fprintf(p, "--%s" ENDL, bound);
01936 fprintf(p, "Content-Type: %s%s; name=\"msg%04d.%s\"" ENDL, ctype, format, msgnum + 1, format);
01937 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
01938 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
01939 fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"" ENDL ENDL, msgnum + 1, format);
01940 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
01941 base_encode(fname, p);
01942 fprintf(p, ENDL "--%s--" ENDL "." ENDL, bound);
01943 if (tmpfd > -1) {
01944 unlink(fname);
01945 close(tmpfd);
01946 unlink(newtmp);
01947 }
01948 }
01949 #undef ENDL
01950 }
01951 static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, char *attach, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category)
01952 {
01953 FILE *p=NULL;
01954 char tmp[80] = "/tmp/astmail-XXXXXX";
01955 char tmp2[256];
01956
01957 if (vmu && ast_strlen_zero(vmu->email)) {
01958 ast_log(LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
01959 return(0);
01960 }
01961 if (!strcmp(format, "wav49"))
01962 format = "WAV";
01963 if (option_debug > 2)
01964 ast_log(LOG_DEBUG, "Attaching file '%s', format '%s', uservm is '%d', global is %d\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags), VM_ATTACH));
01965
01966
01967 if ((p = vm_mkftemp(tmp)) == NULL) {
01968 ast_log(LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
01969 return -1;
01970 } else {
01971 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, cidnum, cidname, attach, format, duration, attach_user_voicemail, chan, category, 0);
01972 fclose(p);
01973 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
01974 ast_safe_system(tmp2);
01975 if (option_debug > 2)
01976 ast_log(LOG_DEBUG, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
01977 }
01978 return 0;
01979 }
01980
01981 static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, int duration, struct ast_vm_user *vmu, const char *category)
01982 {
01983 char date[256];
01984 char host[MAXHOSTNAMELEN] = "";
01985 char who[256];
01986 char dur[PATH_MAX];
01987 char tmp[80] = "/tmp/astmail-XXXXXX";
01988 char tmp2[PATH_MAX];
01989 struct tm tm;
01990 FILE *p;
01991
01992 if ((p = vm_mkftemp(tmp)) == NULL) {
01993 ast_log(LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
01994 return -1;
01995 } else {
01996 gethostname(host, sizeof(host)-1);
01997 if (strchr(srcemail, '@'))
01998 ast_copy_string(who, srcemail, sizeof(who));
01999 else {
02000 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
02001 }
02002 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
02003 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
02004 fprintf(p, "Date: %s\n", date);
02005
02006 if (*pagerfromstring) {
02007 struct ast_channel *ast;
02008 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, 0))) {
02009 char *passdata;
02010 int vmlen = strlen(fromstring)*3 + 200;
02011 if ((passdata = alloca(vmlen))) {
02012 memset(passdata, 0, vmlen);
02013 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category);
02014 pbx_substitute_variables_helper(ast, pagerfromstring, passdata, vmlen);
02015 fprintf(p, "From: %s <%s>\n", passdata, who);
02016 } else
02017 ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
02018 ast_channel_free(ast);
02019 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
02020 } else
02021 fprintf(p, "From: Asterisk PBX <%s>\n", who);
02022 fprintf(p, "To: %s\n", pager);
02023 if (pagersubject) {
02024 struct ast_channel *ast;
02025 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, 0))) {
02026 char *passdata;
02027 int vmlen = strlen(pagersubject) * 3 + 200;
02028 if ((passdata = alloca(vmlen))) {
02029 memset(passdata, 0, vmlen);
02030 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category);
02031 pbx_substitute_variables_helper(ast, pagersubject, passdata, vmlen);
02032 fprintf(p, "Subject: %s\n\n", passdata);
02033 } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
02034 ast_channel_free(ast);
02035 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
02036 } else
02037 fprintf(p, "Subject: New VM\n\n");
02038 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
02039 if (pagerbody) {
02040 struct ast_channel *ast;
02041 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, 0))) {
02042 char *passdata;
02043 int vmlen = strlen(pagerbody)*3 + 200;
02044 if ((passdata = alloca(vmlen))) {
02045 memset(passdata, 0, vmlen);
02046 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category);
02047 pbx_substitute_variables_helper(ast, pagerbody, passdata, vmlen);
02048 fprintf(p, "%s\n", passdata);
02049 } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
02050 ast_channel_free(ast);
02051 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
02052 } else {
02053 fprintf(p, "New %s long msg in box %s\n"
02054 "from %s, on %s", dur, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
02055 }
02056 fclose(p);
02057 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
02058 ast_safe_system(tmp2);
02059 if (option_debug > 2)
02060 ast_log(LOG_DEBUG, "Sent page to %s with command '%s'\n", pager, mailcmd);
02061 }
02062 return 0;
02063 }
02064
02065 static int get_date(char *s, int len)
02066 {
02067 struct tm tm;
02068 time_t t;
02069
02070 time(&t);
02071
02072 ast_localtime(&t, &tm, NULL);
02073
02074 return strftime(s, len, "%a %b %e %r %Z %Y", &tm);
02075 }
02076
02077 static int play_greeting(struct ast_channel *chan, struct ast_vm_user *vmu, char *filename, char *ecodes)
02078 {
02079 int res = -2;
02080
02081 #ifdef ODBC_STORAGE
02082 int success =
02083 #endif
02084 RETRIEVE(filename, -1);
02085 if (ast_fileexists(filename, NULL, NULL) > 0) {
02086 res = ast_streamfile(chan, filename, chan->language);
02087 if (res > -1)
02088 res = ast_waitstream(chan, ecodes);
02089 #ifdef ODBC_STORAGE
02090 if (success == -1) {
02091
02092 if (option_debug)
02093 ast_log(LOG_DEBUG, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
02094 store_file(filename, vmu->mailbox, vmu->context, -1);
02095 }
02096 #endif
02097 }
02098 DISPOSE(filename, -1);
02099
02100 return res;
02101 }
02102
02103 static int invent_message(struct ast_channel *chan, struct ast_vm_user *vmu, char *ext, int busy, char *ecodes)
02104 {
02105 int res;
02106 char fn[PATH_MAX];
02107 char dest[PATH_MAX];
02108
02109 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, ext);
02110
02111 if ((res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "greet"))) {
02112 ast_log(LOG_WARNING, "Failed to make directory(%s)\n", fn);
02113 return -1;
02114 }
02115
02116 res = play_greeting(chan, vmu, fn, ecodes);
02117 if (res == -2) {
02118
02119 res = ast_stream_and_wait(chan, "vm-theperson", chan->language, ecodes);
02120 if (res)
02121 return res;
02122 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
02123 }
02124
02125 if (res)
02126 return res;
02127
02128 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", chan->language, ecodes);
02129 return res;
02130 }
02131
02132 static void free_user(struct ast_vm_user *vmu)
02133 {
02134 if (ast_test_flag(vmu, VM_ALLOCED))
02135 free(vmu);
02136 }
02137
02138 static void free_zone(struct vm_zone *z)
02139 {
02140 free(z);
02141 }
02142
02143 static const char *mbox(int id)
02144 {
02145 static const char *msgs[] = {
02146 "INBOX",
02147 "Old",
02148 "Work",
02149 "Family",
02150 "Friends",
02151 "Cust1",
02152 "Cust2",
02153 "Cust3",
02154 "Cust4",
02155 "Cust5",
02156 };
02157 return (id >= 0 && id < (sizeof(msgs)/sizeof(msgs[0]))) ? msgs[id] : "tmp";
02158 }
02159 #ifdef IMAP_STORAGE
02160 static int folder_int(const char *folder)
02161 {
02162
02163 if (!folder)
02164 return 0;
02165 if (!strcasecmp(folder, "INBOX"))
02166 return 0;
02167 else if (!strcasecmp(folder, "Old"))
02168 return 1;
02169 else if (!strcasecmp(folder, "Work"))
02170 return 2;
02171 else if (!strcasecmp(folder, "Family"))
02172 return 3;
02173 else if (!strcasecmp(folder, "Friends"))
02174 return 4;
02175 else if (!strcasecmp(folder, "Cust1"))
02176 return 5;
02177 else if (!strcasecmp(folder, "Cust2"))
02178 return 6;
02179 else if (!strcasecmp(folder, "Cust3"))
02180 return 7;
02181 else if (!strcasecmp(folder, "Cust4"))
02182 return 8;
02183 else if (!strcasecmp(folder, "Cust5"))
02184 return 9;
02185 else
02186 return 0;
02187 }
02188 #endif
02189
02190 #ifdef ODBC_STORAGE
02191
02192 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
02193 {
02194 int x = -1;
02195 int res;
02196 SQLHSTMT stmt;
02197 char sql[PATH_MAX];
02198 char rowdata[20];
02199 char tmp[PATH_MAX] = "";
02200 struct odbc_obj *obj;
02201 char *context;
02202 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
02203
02204 if (newmsgs)
02205 *newmsgs = 0;
02206 if (oldmsgs)
02207 *oldmsgs = 0;
02208
02209
02210 if (ast_strlen_zero(mailbox))
02211 return 0;
02212
02213 ast_copy_string(tmp, mailbox, sizeof(tmp));
02214
02215 context = strchr(tmp, '@');
02216 if (context) {
02217 *context = '\0';
02218 context++;
02219 } else
02220 context = "default";
02221
02222 obj = ast_odbc_request_obj(odbc_database, 0);
02223 if (obj) {
02224 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
02225 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02226 if (!stmt) {
02227 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02228 ast_odbc_release_obj(obj);
02229 goto yuck;
02230 }
02231 res = SQLFetch(stmt);
02232 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02233 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
02234 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02235 ast_odbc_release_obj(obj);
02236 goto yuck;
02237 }
02238 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
02239 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02240 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
02241 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02242 ast_odbc_release_obj(obj);
02243 goto yuck;
02244 }
02245 *newmsgs = atoi(rowdata);
02246 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02247
02248 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
02249 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02250 if (!stmt) {
02251 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02252 ast_odbc_release_obj(obj);
02253 goto yuck;
02254 }
02255 res = SQLFetch(stmt);
02256 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02257 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
02258 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02259 ast_odbc_release_obj(obj);
02260 goto yuck;
02261 }
02262 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
02263 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02264 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
02265 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02266 ast_odbc_release_obj(obj);
02267 goto yuck;
02268 }
02269 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02270 ast_odbc_release_obj(obj);
02271 *oldmsgs = atoi(rowdata);
02272 x = 0;
02273 } else
02274 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02275
02276 yuck:
02277 return x;
02278 }
02279
02280 static int messagecount(const char *context, const char *mailbox, const char *folder)
02281 {
02282 struct odbc_obj *obj = NULL;
02283 int nummsgs = 0;
02284 int res;
02285 SQLHSTMT stmt = NULL;
02286 char sql[PATH_MAX];
02287 char rowdata[20];
02288 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
02289 if (!folder)
02290 folder = "INBOX";
02291
02292 if (ast_strlen_zero(mailbox))
02293 return 0;
02294
02295 obj = ast_odbc_request_obj(odbc_database, 0);
02296 if (obj) {
02297 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
02298 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02299 if (!stmt) {
02300 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02301 goto yuck;
02302 }
02303 res = SQLFetch(stmt);
02304 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02305 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
02306 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02307 goto yuck;
02308 }
02309 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
02310 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02311 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
02312 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02313 goto yuck;
02314 }
02315 nummsgs = atoi(rowdata);
02316 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02317 } else
02318 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02319
02320 yuck:
02321 if (obj)
02322 ast_odbc_release_obj(obj);
02323 return nummsgs;
02324 }
02325
02326 static int has_voicemail(const char *mailbox, const char *folder)
02327 {
02328 char tmp[256], *tmp2 = tmp, *mbox, *context;
02329 ast_copy_string(tmp, mailbox, sizeof(tmp));
02330 while ((context = mbox = strsep(&tmp2, ","))) {
02331 strsep(&context, "@");
02332 if (ast_strlen_zero(context))
02333 context = "default";
02334 if (messagecount(context, mbox, folder))
02335 return 1;
02336 }
02337 return 0;
02338 }
02339
02340 #elif defined(IMAP_STORAGE)
02341
02342 static int imap_store_file(char *dir, char *mailboxuser, char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms)
02343 {
02344 char *myserveremail = serveremail;
02345 char fn[PATH_MAX];
02346 char mailbox[256];
02347 char *stringp;
02348 FILE *p=NULL;
02349 char tmp[80] = "/tmp/astmail-XXXXXX";
02350 long len;
02351 void *buf;
02352 int tempcopy = 0;
02353 STRING str;
02354
02355
02356 if (msgnum < 0)
02357 return 0;
02358
02359
02360 fmt = ast_strdupa(fmt);
02361 stringp = fmt;
02362 strsep(&stringp, "|");
02363
02364 if (!ast_strlen_zero(vmu->serveremail))
02365 myserveremail = vmu->serveremail;
02366
02367 make_file(fn, sizeof(fn), dir, msgnum);
02368
02369 if (ast_strlen_zero(vmu->email)) {
02370
02371
02372
02373
02374 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
02375 tempcopy = 1;
02376 }
02377
02378 if (!strcmp(fmt, "wav49"))
02379 fmt = "WAV";
02380 if (option_debug > 2)
02381 ast_log(LOG_DEBUG, "Storing file '%s', format '%s'\n", fn, fmt);
02382
02383
02384 if ((p = vm_mkftemp(tmp)) == NULL) {
02385 ast_log(LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
02386 if (tempcopy)
02387 *(vmu->email) = '\0';
02388 return -1;
02389 } else {
02390 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), fn, fmt, duration, 1, chan, NULL, 1);
02391
02392 len = ftell(p);
02393 rewind(p);
02394 if ((buf = ast_malloc(len+1)) == NIL) {
02395 ast_log(LOG_ERROR, "Can't allocate %ld bytes to read message\n", len+1);
02396 fclose(p);
02397 return -1;
02398 }
02399 fread(buf, len, 1, p);
02400 ((char *)buf)[len] = '\0';
02401 INIT(&str, mail_string, buf, len);
02402 init_mailstream(vms, 0);
02403 imap_mailbox_name(mailbox, sizeof(mailbox), vms, 0, 1);
02404 if (!mail_append(vms->mailstream, mailbox, &str))
02405 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
02406 fclose(p);
02407 unlink(tmp);
02408 ast_free(buf);
02409 if (option_debug > 2)
02410 ast_log(LOG_DEBUG, "%s stored\n", fn);
02411 }
02412 if (tempcopy)
02413 *(vmu->email) = '\0';
02414 return 0;
02415
02416 }
02417
02418 static int messagecount(const char *context, const char *mailbox, const char *folder)
02419 {
02420 SEARCHPGM *pgm;
02421 SEARCHHEADER *hdr;
02422
02423 struct ast_vm_user *vmu, vmus;
02424 struct vm_state *vms_p;
02425 int ret = 0;
02426 int fold = folder_int(folder);
02427
02428 if (ast_strlen_zero(mailbox))
02429 return 0;
02430
02431
02432
02433 vmu = find_user(&vmus, context, mailbox);
02434 if (!vmu) {
02435 ast_log (LOG_ERROR,"Couldn't find mailbox %s in context %s\n",mailbox,context);
02436 return -1;
02437 } else {
02438
02439 if (vmu->imapuser[0] == '\0') {
02440 ast_log (LOG_WARNING,"IMAP user not set for mailbox %s\n",vmu->mailbox);
02441 return -1;
02442 }
02443 }
02444
02445
02446 vms_p = get_vm_state_by_imapuser(vmu->imapuser,1);
02447 if (!vms_p) {
02448 vms_p = get_vm_state_by_mailbox(mailbox,1);
02449 }
02450 if (vms_p) {
02451 if (option_debug > 2)
02452 ast_log (LOG_DEBUG,"Returning before search - user is logged in\n");
02453 if (fold == 0) {
02454 return vms_p->newmessages;
02455 }
02456 if (fold == 1) {
02457 return vms_p->oldmessages;
02458 }
02459 }
02460
02461
02462 vms_p = get_vm_state_by_imapuser(vmu->imapuser,0);
02463 if (!vms_p) {
02464 vms_p = get_vm_state_by_mailbox(mailbox,0);
02465 }
02466
02467 if (!vms_p) {
02468 if (option_debug > 2)
02469 ast_log (LOG_DEBUG,"Adding new vmstate for %s\n",vmu->imapuser);
02470 if (!(vms_p = ast_calloc(1, sizeof(*vms_p)))) {
02471 return -1;
02472 }
02473 ast_copy_string(vms_p->imapuser,vmu->imapuser, sizeof(vms_p->imapuser));
02474 ast_copy_string(vms_p->username, mailbox, sizeof(vms_p->username));
02475 vms_p->mailstream = NIL;
02476 if (option_debug > 2)
02477 ast_log (LOG_DEBUG,"Copied %s to %s\n",vmu->imapuser,vms_p->imapuser);
02478 vms_p->updated = 1;
02479
02480 ast_copy_string(vms_p->curbox, mbox(fold), sizeof(vms_p->curbox));
02481 init_vm_state(vms_p);
02482 vmstate_insert(vms_p);
02483 }
02484 ret = init_mailstream(vms_p, fold);
02485 if (!vms_p->mailstream) {
02486 ast_log (LOG_ERROR,"IMAP mailstream is NULL\n");
02487 return -1;
02488 }
02489 if (ret == 0) {
02490 pgm = mail_newsearchpgm ();
02491 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)mailbox);
02492 pgm->header = hdr;
02493 if (fold != 1) {
02494 pgm->unseen = 1;
02495 pgm->seen = 0;
02496 }
02497
02498
02499
02500 else {
02501 pgm->unseen = 0;
02502 pgm->seen = 1;
02503 }
02504 pgm->undeleted = 1;
02505 pgm->deleted = 0;
02506
02507 vms_p->vmArrayIndex = 0;
02508 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
02509 if (fold == 0)
02510 vms_p->newmessages = vms_p->vmArrayIndex;
02511 if (fold == 1)
02512 vms_p->oldmessages = vms_p->vmArrayIndex;
02513
02514 mail_free_searchpgm(&pgm);
02515 vms_p->updated = 0;
02516 return vms_p->vmArrayIndex;
02517 } else {
02518 mail_ping(vms_p->mailstream);
02519 }
02520 return 0;
02521 }
02522 static int inboxcount(const char *mailbox_context, int *newmsgs, int *oldmsgs)
02523 {
02524 char tmp[PATH_MAX] = "";
02525 char *mailboxnc;
02526 char *context;
02527 char *mb;
02528 char *cur;
02529 if (newmsgs)
02530 *newmsgs = 0;
02531 if (oldmsgs)
02532 *oldmsgs = 0;
02533
02534 if (option_debug > 2)
02535 ast_log (LOG_DEBUG,"Mailbox is set to %s\n",mailbox_context);
02536
02537 if (ast_strlen_zero(mailbox_context))
02538 return 0;
02539
02540 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02541 context = strchr(tmp, '@');
02542 if (strchr(mailbox_context, ',')) {
02543 int tmpnew, tmpold;
02544 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02545 mb = tmp;
02546 while ((cur = strsep(&mb, ", "))) {
02547 if (!ast_strlen_zero(cur)) {
02548 if (inboxcount(cur, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
02549 return -1;
02550 else {
02551 if (newmsgs)
02552 *newmsgs += tmpnew;
02553 if (oldmsgs)
02554 *oldmsgs += tmpold;
02555 }
02556 }
02557 }
02558 return 0;
02559 }
02560 if (context) {
02561 *context = '\0';
02562 mailboxnc = tmp;
02563 context++;
02564 } else {
02565 context = "default";
02566 mailboxnc = (char *)mailbox_context;
02567 }
02568 if (newmsgs) {
02569 if ((*newmsgs = messagecount(context, mailboxnc, "INBOX")) < 0)
02570 return -1;
02571 }
02572 if (oldmsgs) {
02573 if ((*oldmsgs = messagecount(context, mailboxnc, "Old")) < 0)
02574 return -1;
02575 }
02576 return 0;
02577 }
02578
02579
02580 static int has_voicemail(const char *mailbox, const char *folder)
02581 {
02582 char tmp[256], *tmp2, *mbox, *context;
02583 ast_copy_string(tmp, mailbox, sizeof(tmp));
02584 tmp2 = tmp;
02585 if (strchr(tmp2, ',')) {
02586 while ((mbox = strsep(&tmp2, ","))) {
02587 if (!ast_strlen_zero(mbox)) {
02588 if (has_voicemail(mbox, folder))
02589 return 1;
02590 }
02591 }
02592 }
02593 if ((context= strchr(tmp, '@')))
02594 *context++ = '\0';
02595 else
02596 context = "default";
02597 return messagecount(context, tmp, folder) ? 1 : 0;
02598 }
02599
02600 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)
02601 {
02602 struct vm_state *sendvms = NULL, *destvms = NULL;
02603 char messagestring[10];
02604 if (msgnum >= recip->maxmsg) {
02605 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
02606 return -1;
02607 }
02608 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
02609 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
02610 return -1;
02611 }
02612 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
02613 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
02614 return -1;
02615 }
02616 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
02617 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(imbox)) == T))
02618 return 0;
02619 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
02620 return -1;
02621 }
02622
02623 #endif
02624 #ifndef IMAP_STORAGE
02625
02626 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)
02627 {
02628 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
02629 const char *frombox = mbox(imbox);
02630 int recipmsgnum;
02631
02632 ast_log(LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
02633
02634 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
02635
02636 if (!dir)
02637 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
02638 else
02639 ast_copy_string(fromdir, dir, sizeof(fromdir));
02640
02641 make_file(frompath, sizeof(frompath), fromdir, msgnum);
02642
02643 if (vm_lock_path(todir))
02644 return ERROR_LOCK_PATH;
02645
02646 recipmsgnum = 0;
02647 do {
02648 make_file(topath, sizeof(topath), todir, recipmsgnum);
02649 if (!EXISTS(todir, recipmsgnum, topath, chan->language))
02650 break;
02651 recipmsgnum++;
02652 } while (recipmsgnum < recip->maxmsg);
02653 if (recipmsgnum < recip->maxmsg) {
02654 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
02655 } else {
02656 ast_log(LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
02657 }
02658 ast_unlock_path(todir);
02659 notify_new_message(chan, recip, recipmsgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL));
02660
02661 return 0;
02662 }
02663 #endif
02664 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
02665 static int messagecount(const char *context, const char *mailbox, const char *folder)
02666 {
02667 return __has_voicemail(context, mailbox, folder, 0);
02668 }
02669
02670
02671 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
02672 {
02673 DIR *dir;
02674 struct dirent *de;
02675 char fn[256];
02676 int ret = 0;
02677 if (!folder)
02678 folder = "INBOX";
02679
02680 if (ast_strlen_zero(mailbox))
02681 return 0;
02682 if (!context)
02683 context = "default";
02684 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
02685 dir = opendir(fn);
02686 if (!dir)
02687 return 0;
02688 while ((de = readdir(dir))) {
02689 if (!strncasecmp(de->d_name, "msg", 3)) {
02690 if (shortcircuit) {
02691 ret = 1;
02692 break;
02693 } else if (!strncasecmp(de->d_name + 8, "txt", 3))
02694 ret++;
02695 }
02696 }
02697 closedir(dir);
02698 return ret;
02699 }
02700
02701
02702 static int has_voicemail(const char *mailbox, const char *folder)
02703 {
02704 char tmp[256], *tmp2 = tmp, *mbox, *context;
02705 ast_copy_string(tmp, mailbox, sizeof(tmp));
02706 while ((mbox = strsep(&tmp2, ","))) {
02707 if ((context = strchr(mbox, '@')))
02708 *context++ = '\0';
02709 else
02710 context = "default";
02711 if (__has_voicemail(context, mbox, folder, 1))
02712 return 1;
02713 }
02714 return 0;
02715 }
02716
02717
02718 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
02719 {
02720 char tmp[256];
02721 char *context;
02722
02723 if (newmsgs)
02724 *newmsgs = 0;
02725 if (oldmsgs)
02726 *oldmsgs = 0;
02727
02728 if (ast_strlen_zero(mailbox))
02729 return 0;
02730 if (strchr(mailbox, ',')) {
02731 int tmpnew, tmpold;
02732 char *mb, *cur;
02733
02734 ast_copy_string(tmp, mailbox, sizeof(tmp));
02735 mb = tmp;
02736 while ((cur = strsep(&mb, ", "))) {
02737 if (!ast_strlen_zero(cur)) {
02738 if (inboxcount(cur, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
02739 return -1;
02740 else {
02741 if (newmsgs)
02742 *newmsgs += tmpnew;
02743 if (oldmsgs)
02744 *oldmsgs += tmpold;
02745 }
02746 }
02747 }
02748 return 0;
02749 }
02750 ast_copy_string(tmp, mailbox, sizeof(tmp));
02751 context = strchr(tmp, '@');
02752 if (context) {
02753 *context = '\0';
02754 context++;
02755 } else
02756 context = "default";
02757 if (newmsgs)
02758 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
02759 if (oldmsgs)
02760 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
02761 return 0;
02762 }
02763
02764 #endif
02765
02766 static void run_externnotify(char *context, char *extension)
02767 {
02768 char arguments[255];
02769 char ext_context[256] = "";
02770 int newvoicemails = 0, oldvoicemails = 0;
02771 struct ast_smdi_mwi_message *mwi_msg;
02772
02773 if (!ast_strlen_zero(context))
02774 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
02775 else
02776 ast_copy_string(ext_context, extension, sizeof(ext_context));
02777
02778 if (!strcasecmp(externnotify, "smdi")) {
02779 if (ast_app_has_voicemail(ext_context, NULL))
02780 ast_smdi_mwi_set(smdi_iface, extension);
02781 else
02782 ast_smdi_mwi_unset(smdi_iface, extension);
02783
02784 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
02785 ast_log(LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
02786 if (!strncmp(mwi_msg->cause, "INV", 3))
02787 ast_log(LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
02788 else if (!strncmp(mwi_msg->cause, "BLK", 3))
02789 ast_log(LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
02790 ast_log(LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
02791 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
02792 } else {
02793 if (option_debug)
02794 ast_log(LOG_DEBUG, "Successfully executed SMDI MWI change for %s\n", extension);
02795 }
02796 } else if (!ast_strlen_zero(externnotify)) {
02797 if (inboxcount(ext_context, &newvoicemails, &oldvoicemails)) {
02798 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
02799 } else {
02800 snprintf(arguments, sizeof(arguments), "%s %s %s %d&", externnotify, context, extension, newvoicemails);
02801 if (option_debug)
02802 ast_log(LOG_DEBUG, "Executing %s\n", arguments);
02803 ast_safe_system(arguments);
02804 }
02805 }
02806 }
02807
02808 struct leave_vm_options {
02809 unsigned int flags;
02810 signed char record_gain;
02811 };
02812
02813 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
02814 {
02815 #ifdef IMAP_STORAGE
02816 int newmsgs, oldmsgs;
02817 struct vm_state *vms = NULL;
02818 #endif
02819 char txtfile[PATH_MAX], tmptxtfile[PATH_MAX];
02820 char callerid[256];
02821 FILE *txt;
02822 char date[256];
02823 int txtdes;
02824 int res = 0;
02825 int msgnum;
02826 int duration = 0;
02827 int ausemacro = 0;
02828 int ousemacro = 0;
02829 int ouseexten = 0;
02830 char dir[PATH_MAX], tmpdir[PATH_MAX];
02831 char dest[PATH_MAX];
02832 char fn[PATH_MAX];
02833 char prefile[PATH_MAX] = "";
02834 char tempfile[PATH_MAX] = "";
02835 char ext_context[256] = "";
02836 char fmt[80];
02837 char *context;
02838 char ecodes[16] = "#";
02839 char tmp[1024] = "", *tmpptr;
02840 struct ast_vm_user *vmu;
02841 struct ast_vm_user svm;
02842 const char *category = NULL;
02843
02844 ast_copy_string(tmp, ext, sizeof(tmp));
02845 ext = tmp;
02846 context = strchr(tmp, '@');
02847 if (context) {
02848 *context++ = '\0';
02849 tmpptr = strchr(context, '&');
02850 } else {
02851 tmpptr = strchr(ext, '&');
02852 }
02853
02854 if (tmpptr)
02855 *tmpptr++ = '\0';
02856
02857 category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY");
02858
02859 if (option_debug > 2)
02860 ast_log(LOG_DEBUG, "Before find_user\n");
02861 if (!(vmu = find_user(&svm, context, ext))) {
02862 ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
02863 if (ast_test_flag(options, OPT_PRIORITY_JUMP) || ast_opt_priority_jumping)
02864 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
02865 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
02866 return res;
02867 }
02868
02869 if (strcmp(vmu->context, "default"))
02870 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
02871 else
02872 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
02873 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
02874 res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "busy");
02875 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
02876 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
02877 res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "unavail");
02878 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
02879 }
02880 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
02881 if ((res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "temp"))) {
02882 ast_log(LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
02883 return -1;
02884 }
02885 RETRIEVE(tempfile, -1);
02886 if (ast_fileexists(tempfile, NULL, NULL) > 0)
02887 ast_copy_string(prefile, tempfile, sizeof(prefile));
02888 DISPOSE(tempfile, -1);
02889
02890 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
02891 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp");
02892
02893
02894 if (ast_test_flag(vmu, VM_OPERATOR)) {
02895 if (!ast_strlen_zero(vmu->exit)) {
02896 if (ast_exists_extension(chan, vmu->exit, "o", 1, chan->cid.cid_num)) {
02897 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
02898 ouseexten = 1;
02899 }
02900 } else if (ast_exists_extension(chan, chan->context, "o", 1, chan->cid.cid_num)) {
02901 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
02902 ouseexten = 1;
02903 }
02904 else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "o", 1, chan->cid.cid_num)) {
02905 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
02906 ousemacro = 1;
02907 }
02908 }
02909
02910 if (!ast_strlen_zero(vmu->exit)) {
02911 if (ast_exists_extension(chan, vmu->exit, "a", 1, chan->cid.cid_num))
02912 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
02913 } else if (ast_exists_extension(chan, chan->context, "a", 1, chan->cid.cid_num))
02914 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
02915 else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "a", 1, chan->cid.cid_num)) {
02916 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
02917 ausemacro = 1;
02918 }
02919
02920
02921 if (!ast_strlen_zero(prefile)) {
02922 res = play_greeting(chan, vmu, prefile, ecodes);
02923 if (res == -2) {
02924
02925 if (option_debug)
02926 ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile);
02927 res = invent_message(chan, vmu, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
02928 }
02929 if (res < 0) {
02930 if (option_debug)
02931 ast_log(LOG_DEBUG, "Hang up during prefile playback\n");
02932 free_user(vmu);
02933 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
02934 return -1;
02935 }
02936 }
02937 if (res == '#') {
02938
02939 ast_set_flag(options, OPT_SILENT);
02940 res = 0;
02941 }
02942 if (!res && !ast_test_flag(options, OPT_SILENT)) {
02943 res = ast_stream_and_wait(chan, INTRO, chan->language, ecodes);
02944 if (res == '#') {
02945 ast_set_flag(options, OPT_SILENT);
02946 res = 0;
02947 }
02948 }
02949 if (res > 0)
02950 ast_stopstream(chan);
02951
02952
02953 if (res == '*') {
02954 chan->exten[0] = 'a';
02955 chan->exten[1] = '\0';
02956 if (!ast_strlen_zero(vmu->exit)) {
02957 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
02958 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
02959 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
02960 }
02961 chan->priority = 0;
02962 free_user(vmu);
02963 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
02964 return 0;
02965 }
02966
02967
02968 if (res == '0') {
02969 transfer:
02970 if (ouseexten || ousemacro) {
02971 chan->exten[0] = 'o';
02972 chan->exten[1] = '\0';
02973 if (!ast_strlen_zero(vmu->exit)) {
02974 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
02975 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
02976 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
02977 }
02978 ast_play_and_wait(chan, "transfer");
02979 chan->priority = 0;
02980 free_user(vmu);
02981 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
02982 }
02983 return 0;
02984 }
02985 if (res < 0) {
02986 free_user(vmu);
02987 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
02988 return -1;
02989 }
02990
02991 ast_copy_string(fmt, vmfmts, sizeof(fmt));
02992 if (!ast_strlen_zero(fmt)) {
02993 msgnum = 0;
02994
02995 #ifdef IMAP_STORAGE
02996
02997
02998 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
02999 if (res < 0) {
03000 ast_log(LOG_NOTICE,"Can not leave voicemail, unable to count messages\n");
03001 return -1;
03002 }
03003 if (!(vms = get_vm_state_by_mailbox(ext,0))) {
03004
03005
03006 if (!(vms = ast_calloc(1, sizeof(*vms)))) {
03007 ast_log(LOG_ERROR, "Couldn't allocate necessary space\n");
03008 return -1;
03009 }
03010 ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser));
03011 ast_copy_string(vms->username, ext, sizeof(vms->username));
03012 vms->mailstream = NIL;
03013 if (option_debug > 2)
03014 ast_log(LOG_DEBUG, "Copied %s to %s\n", vmu->imapuser, vms->imapuser);
03015 vms->updated=1;
03016 ast_copy_string(vms->curbox, mbox(0), sizeof(vms->curbox));
03017 init_vm_state(vms);
03018 vmstate_insert(vms);
03019 vms = get_vm_state_by_mailbox(ext,0);
03020 }
03021 vms->newmessages++;
03022
03023 msgnum = newmsgs + oldmsgs;
03024 if (option_debug > 2)
03025 ast_log(LOG_DEBUG, "Messagecount set to %d\n",msgnum);
03026 snprintf(fn, sizeof(fn), "%s/imap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
03027
03028 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
03029
03030
03031 check_quota(vms, imapfolder);
03032 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
03033 if (option_debug)
03034 ast_log(LOG_DEBUG, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
03035 ast_play_and_wait(chan, "vm-mailboxfull");
03036 return -1;
03037 }
03038 if (option_debug > 2)
03039 ast_log(LOG_DEBUG, "Checking message number quota - mailbox has %d messages, maximum is set to %d\n",msgnum,vmu->maxmsg);
03040 if (msgnum >= vmu->maxmsg) {
03041 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
03042 if (!res)
03043 res = ast_waitstream(chan, "");
03044 ast_log(LOG_WARNING, "No more messages possible\n");
03045 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
03046 goto leave_vm_out;
03047 }
03048
03049
03050 if (msgnum >= vmu->maxmsg) {
03051 ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u > %u)\n", msgnum, vmu->maxmsg);
03052 ast_play_and_wait(chan, "vm-mailboxfull");
03053 return -1;
03054 }
03055
03056 if (option_debug > 2)
03057 ast_log(LOG_DEBUG, "Messagecount set to %d\n",msgnum);
03058 #else
03059 if (count_messages(vmu, dir) >= vmu->maxmsg) {
03060 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
03061 if (!res)
03062 res = ast_waitstream(chan, "");
03063 ast_log(LOG_WARNING, "No more messages possible\n");
03064 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
03065 goto leave_vm_out;
03066 }
03067
03068 #endif
03069 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
03070 txtdes = mkstemp(tmptxtfile);
03071 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
03072 if (txtdes < 0) {
03073 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
03074 if (!res)
03075 res = ast_waitstream(chan, "");
03076 ast_log(LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
03077 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
03078 goto leave_vm_out;
03079 }
03080
03081
03082 if (res >= 0) {
03083
03084 res = ast_stream_and_wait(chan, "beep", chan->language, "");
03085 }
03086
03087
03088 txt = fdopen(txtdes, "w+");
03089 if (txt) {
03090 get_date(date, sizeof(date));
03091 fprintf(txt,
03092 ";\n"
03093 "; Message Information file\n"
03094 ";\n"
03095 "[message]\n"
03096 "origmailbox=%s\n"
03097 "context=%s\n"
03098 "macrocontext=%s\n"
03099 "exten=%s\n"
03100 "priority=%d\n"
03101 "callerchan=%s\n"
03102 "callerid=%s\n"
03103 "origdate=%s\n"
03104 "origtime=%ld\n"
03105 "category=%s\n",
03106 ext,
03107 chan->context,
03108 chan->macrocontext,
03109 chan->exten,
03110 chan->priority,
03111 chan->name,
03112 ast_callerid_merge(callerid, sizeof(callerid), S_OR(chan->cid.cid_name, NULL), S_OR(chan->cid.cid_num, NULL), "Unknown"),
03113 date, (long)time(NULL),
03114 category ? category : "");
03115 } else
03116 ast_log(LOG_WARNING, "Error opening text file for output\n");
03117 #ifdef IMAP_STORAGE
03118 res = play_record_review(chan, NULL, tmptxtfile, vmmaxmessage, fmt, 1, vmu, &duration, NULL, options->record_gain, vms);
03119 #else
03120 res = play_record_review(chan, NULL, tmptxtfile, vmmaxmessage, fmt, 1, vmu, &duration, NULL, options->record_gain, NULL);
03121 #endif
03122
03123 if (txt) {
03124 if (duration < vmminmessage) {
03125 fclose(txt);
03126 if (option_verbose > 2)
03127 ast_verbose( VERBOSE_PREFIX_3 "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmminmessage);
03128 ast_filedelete(tmptxtfile, NULL);
03129 unlink(tmptxtfile);
03130 } else {
03131 fprintf(txt, "duration=%d\n", duration);
03132 fclose(txt);
03133 if (vm_lock_path(dir)) {
03134 ast_log(LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
03135
03136 ast_filedelete(tmptxtfile, NULL);
03137 unlink(tmptxtfile);
03138 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
03139 if (option_debug)
03140 ast_log(LOG_DEBUG, "The recorded media file is gone, so we should remove the .txt file too!\n");
03141 unlink(tmptxtfile);
03142 ast_unlock_path(dir);
03143 } else {
03144 for (;;) {
03145 make_file(fn, sizeof(fn), dir, msgnum);
03146 if (!EXISTS(dir, msgnum, fn, NULL))
03147 break;
03148 msgnum++;
03149 }
03150
03151
03152 #ifndef IMAP_STORAGE
03153 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
03154 #else
03155 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
03156 #endif
03157
03158 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
03159 ast_filerename(tmptxtfile, fn, NULL);
03160 rename(tmptxtfile, txtfile);
03161
03162 ast_unlock_path(dir);
03163
03164
03165
03166 if (ast_fileexists(fn, NULL, NULL) > 0) {
03167 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms);
03168 }
03169
03170
03171 while (tmpptr) {
03172 struct ast_vm_user recipu, *recip;
03173 char *exten, *context;
03174
03175 exten = strsep(&tmpptr, "&");
03176 context = strchr(exten, '@');
03177 if (context) {
03178 *context = '\0';
03179 context++;
03180 }
03181 if ((recip = find_user(&recipu, context, exten))) {
03182 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir);
03183 free_user(recip);
03184 }
03185 }
03186
03187 if (ast_fileexists(fn, NULL, NULL)) {
03188 notify_new_message(chan, vmu, msgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL));
03189 DISPOSE(dir, msgnum);
03190 }
03191 }
03192 }
03193 }
03194 if (res == '0') {
03195 goto transfer;
03196 } else if (res > 0)
03197 res = 0;
03198
03199 if (duration < vmminmessage)
03200
03201 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
03202 else
03203 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
03204 } else
03205 ast_log(LOG_WARNING, "No format for saving voicemail?\n");
03206 leave_vm_out:
03207 free_user(vmu);
03208
03209 return res;
03210 }
03211
03212 #ifndef IMAP_STORAGE
03213 static int resequence_mailbox(struct ast_vm_user *vmu, char *dir)
03214 {
03215
03216
03217 int x,dest;
03218 char sfn[PATH_MAX];
03219 char dfn[PATH_MAX];
03220
03221 if (vm_lock_path(dir))
03222 return ERROR_LOCK_PATH;
03223
03224 for (x = 0, dest = 0; x < vmu->maxmsg; x++) {
03225 make_file(sfn, sizeof(sfn), dir, x);
03226 if (EXISTS(dir, x, sfn, NULL)) {
03227
03228 if (x != dest) {
03229 make_file(dfn, sizeof(dfn), dir, dest);
03230 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
03231 }
03232
03233 dest++;
03234 }
03235 }
03236 ast_unlock_path(dir);
03237
03238 return 0;
03239 }
03240 #endif
03241
03242 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
03243 {
03244 int d;
03245 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, (char *) NULL);
03246 return d;
03247 }
03248
03249 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
03250 {
03251 #ifdef IMAP_STORAGE
03252
03253
03254 long res;
03255 char sequence[10];
03256
03257
03258 if (box == 1) return 10;
03259
03260 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
03261 if (option_debug > 2)
03262 ast_log(LOG_DEBUG, "Copying sequence %s to mailbox %s\n",sequence,(char *) mbox(box));
03263 res = mail_copy(vms->mailstream,sequence,(char *) mbox(box));
03264 if (res == 1) return 0;
03265 return 1;
03266 #else
03267 char *dir = vms->curdir;
03268 char *username = vms->username;
03269 char *context = vmu->context;
03270 char sfn[PATH_MAX];
03271 char dfn[PATH_MAX];
03272 char ddir[PATH_MAX];
03273 const char *dbox = mbox(box);
03274 int x;
03275 make_file(sfn, sizeof(sfn), dir, msg);
03276 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
03277
03278 if (vm_lock_path(ddir))
03279 return ERROR_LOCK_PATH;
03280
03281 for (x = 0; x < vmu->maxmsg; x++) {
03282 make_file(dfn, sizeof(dfn), ddir, x);
03283 if (!EXISTS(ddir, x, dfn, NULL))
03284 break;
03285 }
03286 if (x >= vmu->maxmsg) {
03287 ast_unlock_path(ddir);
03288 return ERROR_MAILBOX_FULL;
03289 }
03290 if (strcmp(sfn, dfn)) {
03291 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
03292 }
03293 ast_unlock_path(ddir);
03294 #endif
03295 return 0;
03296 }
03297
03298 static int adsi_logo(unsigned char *buf)
03299 {
03300 int bytes = 0;
03301 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
03302 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
03303 return bytes;
03304 }
03305
03306 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
03307 {
03308 unsigned char buf[256];
03309 int bytes=0;
03310 int x;
03311 char num[5];
03312
03313 *useadsi = 0;
03314 bytes += ast_adsi_data_mode(buf + bytes);
03315 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
03316
03317 bytes = 0;
03318 bytes += adsi_logo(buf);
03319 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
03320 #ifdef DISPLAY
03321 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
03322 #endif
03323 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
03324 bytes += ast_adsi_data_mode(buf + bytes);
03325 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
03326
03327 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
03328 bytes = 0;
03329 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
03330 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
03331 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
03332 bytes += ast_adsi_voice_mode(buf + bytes, 0);
03333 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
03334 return 0;
03335 }
03336
03337 #ifdef DISPLAY
03338
03339 bytes = 0;
03340 bytes += ast_adsi_logo(buf);
03341 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
03342 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
03343 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
03344 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
03345 #endif
03346 bytes = 0;
03347 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
03348 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
03349 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
03350 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
03351 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
03352 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
03353 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
03354
03355 #ifdef DISPLAY
03356
03357 bytes = 0;
03358 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
03359 bytes += ast_adsi_voice_mode(buf + bytes, 0);
03360
03361 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
03362 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
03363 #endif
03364
03365 bytes = 0;
03366
03367 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
03368 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
03369 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
03370 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
03371 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
03372 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
03373 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
03374
03375 #ifdef DISPLAY
03376
03377 bytes = 0;
03378 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
03379 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
03380 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
03381 #endif
03382
03383 bytes = 0;
03384 for (x=0;x<5;x++) {
03385 snprintf(num, sizeof(num), "%d", x);
03386 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
03387 }
03388 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
03389 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
03390
03391 #ifdef DISPLAY
03392
03393 bytes = 0;
03394 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
03395 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
03396 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
03397 #endif
03398
03399 if (ast_adsi_end_download(chan)) {
03400 bytes = 0;
03401 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
03402 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
03403 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
03404 bytes += ast_adsi_voice_mode(buf + bytes, 0);
03405 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
03406 return 0;
03407 }
03408 bytes = 0;
03409 bytes += ast_adsi_download_disconnect(buf + bytes);
03410 bytes += ast_adsi_voice_mode(buf + bytes, 0);
03411 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
03412
03413 if (option_debug)
03414 ast_log(LOG_DEBUG, "Done downloading scripts...\n");
03415
03416 #ifdef DISPLAY
03417
03418 bytes = 0;
03419 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
03420 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
03421 #endif
03422 if (option_debug)
03423 ast_log(LOG_DEBUG, "Restarting session...\n");
03424
03425 bytes = 0;
03426
03427 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
03428 *useadsi = 1;
03429 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
03430 } else
03431 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
03432
03433 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
03434 return 0;
03435 }
03436
03437 static void adsi_begin(struct ast_channel *chan, int *useadsi)
03438 {
03439 int x;
03440 if (!ast_adsi_available(chan))
03441 return;
03442 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
03443 if (x < 0)
03444 return;
03445 if (!x) {
03446 if (adsi_load_vmail(chan, useadsi)) {
03447 ast_log(LOG_WARNING, "Unable to upload voicemail scripts\n");
03448 return;
03449 }
03450 } else
03451 *useadsi = 1;
03452 }
03453
03454 static void adsi_login(struct ast_channel *chan)
03455 {
03456 unsigned char buf[256];
03457 int bytes=0;
03458 unsigned char keys[8];
03459 int x;
03460 if (!ast_adsi_available(chan))
03461 return;
03462
03463 for (x=0;x<8;x++)
03464 keys[x] = 0;
03465
03466 keys[3] = ADSI_KEY_APPS + 3;
03467
03468 bytes += adsi_logo(buf + bytes);
03469 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
03470 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
03471 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
03472 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
03473 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
03474 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
03475 bytes += ast_adsi_set_keys(buf + bytes, keys);
03476 bytes += ast_adsi_voice_mode(buf + bytes, 0);
03477 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
03478 }
03479
03480 static void adsi_password(struct ast_channel *chan)
03481 {
03482 unsigned char buf[256];
03483 int bytes=0;
03484 unsigned char keys[8];
03485 int x;
03486 if (!ast_adsi_available(chan))
03487 return;
03488
03489 for (x=0;x<8;x++)
03490 keys[x] = 0;
03491
03492 keys[3] = ADSI_KEY_APPS + 3;
03493
03494 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
03495 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
03496 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
03497 bytes += ast_adsi_set_keys(buf + bytes, keys);
03498 bytes += ast_adsi_voice_mode(buf + bytes, 0);
03499 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
03500 }
03501
03502 static void adsi_folders(struct ast_channel *chan, int start, char *label)
03503 {
03504 unsigned char buf[256];
03505 int bytes=0;
03506 unsigned char keys[8];
03507 int x,y;
03508
03509 if (!ast_adsi_available(chan))
03510 return;
03511
03512 for (x=0;x<5;x++) {
03513 y = ADSI_KEY_APPS + 12 + start + x;
03514 if (y > ADSI_KEY_APPS + 12 + 4)
03515 y = 0;
03516 keys[x] = ADSI_KEY_SKT | y;
03517 }
03518 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
03519 keys[6] = 0;
03520 keys[7] = 0;
03521
03522 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
03523 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
03524 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
03525 bytes += ast_adsi_set_keys(buf + bytes, keys);
03526 bytes += ast_adsi_voice_mode(buf + bytes, 0);
03527
03528 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
03529 }
03530
03531 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
03532 {
03533 int bytes=0;
03534 unsigned char buf[256];
03535 char buf1[256], buf2[256];
03536 char fn2[PATH_MAX];
03537
03538 char cid[256]="";
03539 char *val;
03540 char *name, *num;
03541 char datetime[21]="";
03542 FILE *f;
03543
03544 unsigned char keys[8];
03545
03546 int x;
03547
03548 if (!ast_adsi_available(chan))
03549 return;
03550
03551
03552 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
03553 f = fopen(fn2, "r");
03554 if (f) {
03555 while (!feof(f)) {
03556 fgets((char *)buf, sizeof(buf), f);
03557 if (!feof(f)) {
03558 char *stringp=NULL;
03559 stringp = (char *)buf;
03560 strsep(&stringp, "=");
03561 val = strsep(&stringp, "=");
03562 if (!ast_strlen_zero(val)) {
03563 if (!strcmp((char *)buf, "callerid"))
03564 ast_copy_string(cid, val, sizeof(cid));
03565 if (!strcmp((char *)buf, "origdate"))
03566 ast_copy_string(datetime, val, sizeof(datetime));
03567 }
03568 }
03569 }
03570 fclose(f);
03571 }
03572
03573 for (x=0;x<5;x++)
03574 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
03575 keys[6] = 0x0;
03576 keys[7] = 0x0;
03577
03578 if (!vms->curmsg) {
03579
03580 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
03581 }
03582 if (vms->curmsg >= vms->lastmsg) {
03583
03584 if (vms->curmsg) {
03585
03586 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
03587 bytes += ast_adsi_voice_mode(buf + bytes, 0);
03588
03589 } else {
03590
03591 keys[3] = 1;
03592 }
03593 }
03594
03595 if (!ast_strlen_zero(cid)) {
03596 ast_callerid_parse(cid, &name, &num);
03597 if (!name)
03598 name = num;
03599 } else
03600 name = "Unknown Caller";
03601
03602
03603
03604 if (vms->deleted[vms->curmsg])
03605 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
03606
03607
03608 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
03609 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
03610 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
03611 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
03612
03613 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
03614 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
03615 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
03616 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
03617 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
03618 bytes += ast_adsi_set_keys(buf + bytes, keys);
03619 bytes += ast_adsi_voice_mode(buf + bytes, 0);
03620
03621 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
03622 }
03623
03624 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
03625 {
03626 int bytes=0;
03627 unsigned char buf[256];
03628 unsigned char keys[8];
03629
03630 int x;
03631
03632 if (!ast_adsi_available(chan))
03633 return;
03634
03635
03636 for (x=0;x<5;x++)
03637 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
03638
03639 keys[6] = 0x0;
03640 keys[7] = 0x0;
03641
03642 if (!vms->curmsg) {
03643
03644 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
03645 }
03646 if (vms->curmsg >= vms->lastmsg) {
03647
03648 if (vms->curmsg) {
03649
03650 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
03651 } else {
03652
03653 keys[3] = 1;
03654 }
03655 }
03656
03657
03658 if (vms->deleted[vms->curmsg])
03659 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
03660
03661
03662 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
03663 bytes += ast_adsi_set_keys(buf + bytes, keys);
03664 bytes += ast_adsi_voice_mode(buf + bytes, 0);
03665
03666 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
03667 }
03668
03669 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
03670 {
03671 unsigned char buf[256] = "";
03672 char buf1[256] = "", buf2[256] = "";
03673 int bytes=0;
03674 unsigned char keys[8];
03675 int x;
03676
03677 char *newm = (vms->newmessages == 1) ? "message" : "messages";
03678 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
03679 if (!ast_adsi_available(chan))
03680 return;
03681 if (vms->newmessages) {
03682 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
03683 if (vms->oldmessages) {
03684 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
03685 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
03686 } else {
03687 snprintf(buf2, sizeof(buf2), "%s.", newm);
03688 }
03689 } else if (vms->oldmessages) {
03690 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
03691 snprintf(buf2, sizeof(buf2), "%s.", oldm);
03692 } else {
03693 strcpy(buf1, "You have no messages.");
03694 buf2[0] = ' ';
03695 buf2[1] = '\0';
03696 }
03697 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
03698 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
03699 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
03700
03701 for (x=0;x<6;x++)
03702 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
03703 keys[6] = 0;
03704 keys[7] = 0;
03705
03706
03707 if (vms->lastmsg < 0)
03708 keys[0] = 1;
03709 bytes += ast_adsi_set_keys(buf + bytes, keys);
03710
03711 bytes += ast_adsi_voice_mode(buf + bytes, 0);
03712
03713 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
03714 }
03715
03716 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
03717 {
03718 unsigned char buf[256] = "";
03719 char buf1[256] = "", buf2[256] = "";
03720 int bytes=0;
03721 unsigned char keys[8];
03722 int x;
03723
03724 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
03725
03726 if (!ast_adsi_available(chan))
03727 return;
03728
03729
03730 for (x=0;x<6;x++)
03731 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
03732
03733 keys[6] = 0;
03734 keys[7] = 0;
03735
03736 if ((vms->lastmsg + 1) < 1)
03737 keys[0] = 0;
03738
03739 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
03740 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
03741
03742 if (vms->lastmsg + 1)
03743 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
03744 else
03745 strcpy(buf2, "no messages.");
03746 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
03747 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
03748 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
03749 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
03750 bytes += ast_adsi_set_keys(buf + bytes, keys);
03751
03752 bytes += ast_adsi_voice_mode(buf + bytes, 0);
03753
03754 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
03755
03756 }
03757
03758
03759
03760
03761
03762
03763
03764
03765
03766
03767
03768
03769
03770
03771
03772 static void adsi_goodbye(struct ast_channel *chan)
03773 {
03774 unsigned char buf[256];
03775 int bytes=0;
03776
03777 if (!ast_adsi_available(chan))
03778 return;
03779 bytes += adsi_logo(buf + bytes);
03780 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
03781 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
03782 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
03783 bytes += ast_adsi_voice_mode(buf + bytes, 0);
03784
03785 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
03786 }
03787
03788
03789
03790
03791
03792 static int get_folder(struct ast_channel *chan, int start)
03793 {
03794 int x;
03795 int d;
03796 char fn[PATH_MAX];
03797 d = ast_play_and_wait(chan, "vm-press");
03798 if (d)
03799 return d;
03800 for (x = start; x< 5; x++) {
03801 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, (char *) NULL)))
03802 return d;
03803 d = ast_play_and_wait(chan, "vm-for");
03804 if (d)
03805 return d;
03806 snprintf(fn, sizeof(fn), "vm-%s", mbox(x));
03807 d = vm_play_folder_name(chan, fn);
03808 if (d)
03809 return d;
03810 d = ast_waitfordigit(chan, 500);
03811 if (d)
03812 return d;
03813 }
03814 d = ast_play_and_wait(chan, "vm-tocancel");
03815 if (d)
03816 return d;
03817 d = ast_waitfordigit(chan, 4000);
03818 return d;
03819 }
03820
03821 static int get_folder2(struct ast_channel *chan, char *fn, int start)
03822 {
03823 int res = 0;
03824 res = ast_play_and_wait(chan, fn);
03825 while (((res < '0') || (res > '9')) &&
03826 (res != '#') && (res >= 0)) {
03827 res = get_folder(chan, 0);
03828 }
03829 return res;
03830 }
03831
03832 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vmfmts,
03833 char *context, signed char record_gain, long *duration, struct vm_state *vms)
03834 {
03835 int cmd = 0;
03836 int retries = 0, prepend_duration = 0, already_recorded = 0;
03837 signed char zero_gain = 0;
03838 struct ast_config *msg_cfg;
03839 const char *duration_str;
03840 char msgfile[PATH_MAX], backup[PATH_MAX];
03841 char textfile[PATH_MAX];
03842
03843
03844 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
03845 strcpy(textfile, msgfile);
03846 strcpy(backup, msgfile);
03847 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
03848 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
03849
03850 if (!(msg_cfg = ast_config_load(textfile))) {
03851 return -1;
03852 }
03853
03854 *duration = 0;
03855 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
03856 *duration = atoi(duration_str);
03857
03858 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
03859 if (cmd)
03860 retries = 0;
03861 switch (cmd) {
03862 case '1':
03863
03864 {
03865 prepend_duration = 0;
03866
03867
03868 if (!msg_cfg) {
03869 cmd = 0;
03870 break;
03871 }
03872
03873
03874 if (already_recorded)
03875 ast_filecopy(backup, msgfile, NULL);
03876 else
03877 ast_filecopy(msgfile, backup, NULL);
03878 already_recorded = 1;
03879
03880 if (record_gain)
03881 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
03882
03883 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vmfmts, &prepend_duration, 1, silencethreshold, maxsilence);
03884 if (record_gain)
03885 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
03886
03887 if (prepend_duration) {
03888 struct ast_category *msg_cat;
03889
03890 char duration_str[12];
03891
03892 prepend_duration += *duration;
03893 msg_cat = ast_category_get(msg_cfg, "message");
03894 snprintf(duration_str, 11, "%d", prepend_duration);
03895 if (!ast_variable_update(msg_cat, "duration", duration_str, NULL, 0)) {
03896 config_text_file_save(textfile, msg_cfg, "app_voicemail");
03897 STORE(curdir, vmu->mailbox, context, curmsg, chan, vmu, vmfmts, prepend_duration, vms);
03898 }
03899 }
03900
03901 break;
03902 }
03903 case '2':
03904 cmd = 't';
03905 break;
03906 case '*':
03907 cmd = '*';
03908 break;
03909 default:
03910 cmd = ast_play_and_wait(chan,"vm-forwardoptions");
03911
03912 if (!cmd)
03913 cmd = ast_play_and_wait(chan,"vm-starmain");
03914
03915 if (!cmd)
03916 cmd = ast_waitfordigit(chan,6000);
03917 if (!cmd)
03918 retries++;
03919 if (retries > 3)
03920 cmd = 't';
03921 }
03922 }
03923
03924 ast_config_destroy(msg_cfg);
03925 if (already_recorded)
03926 ast_filedelete(backup, NULL);
03927 if (prepend_duration)
03928 *duration = prepend_duration;
03929
03930 if (cmd == 't' || cmd == 'S')
03931 cmd = 0;
03932 return cmd;
03933 }
03934
03935 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *cidnum, char *cidname)
03936 {
03937 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
03938 int newmsgs = 0, oldmsgs = 0;
03939 const char *category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY");
03940
03941 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, "INBOX");
03942 make_file(fn, sizeof(fn), todir, msgnum);
03943 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
03944
03945 if (!ast_strlen_zero(vmu->attachfmt)) {
03946 if (strstr(fmt, vmu->attachfmt)) {
03947 fmt = vmu->attachfmt;
03948 } else {
03949 ast_log(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);
03950 }
03951 }
03952
03953
03954 fmt = ast_strdupa(fmt);
03955 stringp = fmt;
03956 strsep(&stringp, "|");
03957
03958 if (!ast_strlen_zero(vmu->email)) {
03959 int attach_user_voicemail = ast_test_flag((&globalflags), VM_ATTACH);
03960 char *myserveremail = serveremail;
03961 attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
03962 if (!ast_strlen_zero(vmu->serveremail))
03963 myserveremail = vmu->serveremail;
03964
03965 if (attach_user_voicemail)
03966 RETRIEVE(todir, msgnum);
03967
03968
03969 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, cidnum, cidname, fn, fmt, duration, attach_user_voicemail, chan, category);
03970
03971 if (attach_user_voicemail)
03972 DISPOSE(todir, msgnum);
03973 }
03974
03975 if (!ast_strlen_zero(vmu->pager)) {
03976 char *myserveremail = serveremail;
03977 if (!ast_strlen_zero(vmu->serveremail))
03978 myserveremail = vmu->serveremail;
03979 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, cidnum, cidname, duration, vmu, category);
03980 }
03981
03982 if (ast_test_flag(vmu, VM_DELETE)) {
03983 DELETE(todir, msgnum, fn);
03984 }
03985
03986 #ifdef IMAP_STORAGE
03987 DELETE(todir, msgnum, fn);
03988 #endif
03989
03990 if (ast_app_has_voicemail(ext_context, NULL)) {
03991 ast_app_inboxcount(ext_context, &newmsgs, &oldmsgs);
03992 }
03993 manager_event(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);
03994 run_externnotify(vmu->context, vmu->mailbox);
03995 return 0;
03996 }
03997
03998 static int forward_message(struct ast_channel *chan, char *context, struct vm_state *vms, struct ast_vm_user *sender, char *fmt, int flag, signed char record_gain)
03999 {
04000 #ifdef IMAP_STORAGE
04001 BODY *body;
04002 char *header_content;
04003 char *temp;
04004 char todir[256];
04005 int todircount=0;
04006 struct vm_state *dstvms;
04007 #endif
04008 char username[70]="";
04009 int res = 0, cmd = 0;
04010 struct ast_vm_user *receiver = NULL, *vmtmp;
04011 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
04012 char *stringp;
04013 const char *s;
04014 int saved_messages = 0, found = 0;
04015 int valid_extensions = 0;
04016 char *dir;
04017 int curmsg;
04018
04019 if (vms == NULL) return -1;
04020 dir = vms->curdir;
04021 curmsg = vms->curmsg;
04022
04023 while (!res && !valid_extensions) {
04024 int use_directory = 0;
04025 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
04026 int done = 0;
04027 int retries = 0;
04028 cmd=0;
04029 while ((cmd >= 0) && !done ){
04030 if (cmd)
04031 retries = 0;
04032 switch (cmd) {
04033 case '1':
04034 use_directory = 0;
04035 done = 1;
04036 break;
04037 case '2':
04038 use_directory = 1;
04039 done=1;
04040 break;
04041 case '*':
04042 cmd = 't';
04043 done = 1;
04044 break;
04045 default:
04046
04047 cmd = ast_play_and_wait(chan,"vm-forward");
04048 if (!cmd)
04049 cmd = ast_waitfordigit(chan,3000);
04050 if (!cmd)
04051 retries++;
04052 if (retries > 3)
04053 {
04054 cmd = 't';
04055 done = 1;
04056 }
04057
04058 }
04059 }
04060 if (cmd < 0 || cmd == 't')
04061 break;
04062 }
04063
04064 if (use_directory) {
04065
04066
04067 char old_context[sizeof(chan->context)];
04068 char old_exten[sizeof(chan->exten)];
04069 int old_priority;
04070 struct ast_app* app;
04071
04072
04073 app = pbx_findapp("Directory");
04074 if (app) {
04075 char vmcontext[256];
04076
04077 memcpy(old_context, chan->context, sizeof(chan->context));
04078 memcpy(old_exten, chan->exten, sizeof(chan->exten));
04079 old_priority = chan->priority;
04080
04081
04082 snprintf(vmcontext, sizeof(vmcontext), "%s||v", context ? context : "default");
04083 res = pbx_exec(chan, app, vmcontext);
04084
04085 ast_copy_string(username, chan->exten, sizeof(username));
04086
04087
04088 memcpy(chan->context, old_context, sizeof(chan->context));
04089 memcpy(chan->exten, old_exten, sizeof(chan->exten));
04090 chan->priority = old_priority;
04091
04092 } else {
04093 ast_log(LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
04094 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
04095 }
04096 } else {
04097
04098 res = ast_streamfile(chan, "vm-extension", chan->language);
04099 if (res)
04100 break;
04101 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
04102 break;
04103 }
04104
04105
04106 if (ast_strlen_zero(username))
04107 continue;
04108 stringp = username;
04109 s = strsep(&stringp, "*");
04110
04111 valid_extensions = 1;
04112 while (s) {
04113
04114 if ((flag == 1 || strcmp(s,sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
04115 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
04116 found++;
04117 } else {
04118 valid_extensions = 0;
04119 break;
04120 }
04121 s = strsep(&stringp, "*");
04122 }
04123
04124 if (valid_extensions)
04125 break;
04126
04127 res = ast_play_and_wait(chan, "pbx-invalid");
04128 }
04129
04130 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
04131 return res;
04132 if (flag==1) {
04133 struct leave_vm_options leave_options;
04134 char mailbox[AST_MAX_EXTENSION * 2 + 2];
04135
04136 if (context)
04137 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
04138 else
04139 ast_copy_string(mailbox, username, sizeof(mailbox));
04140
04141
04142 memset(&leave_options, 0, sizeof(leave_options));
04143 leave_options.record_gain = record_gain;
04144 cmd = leave_voicemail(chan, mailbox, &leave_options);
04145 } else {
04146
04147 long duration = 0;
04148 char origmsgfile[PATH_MAX], msgfile[PATH_MAX];
04149 struct vm_state vmstmp;
04150
04151 memcpy(&vmstmp, vms, sizeof(vmstmp));
04152
04153 make_file(origmsgfile, sizeof(origmsgfile), dir, curmsg);
04154 create_dirpath(vmstmp.curdir, sizeof(vmstmp.curdir), sender->context, vmstmp.username, "tmp");
04155 make_file(msgfile, sizeof(msgfile), vmstmp.curdir, curmsg);
04156
04157 RETRIEVE(dir, curmsg);
04158
04159
04160 copy_plain_file(origmsgfile, msgfile);
04161
04162 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp);
04163 if (!cmd) {
04164 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
04165 #ifdef IMAP_STORAGE
04166 char *myserveremail;
04167 int attach_user_voicemail;
04168
04169 if (option_debug > 2)
04170 ast_log (LOG_DEBUG, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", vms->curmsg, vms->msgArray[vms->curmsg]);
04171 if (vms->msgArray[vms->curmsg] == 0) {
04172 ast_log (LOG_WARNING,"Trying to access unknown message\n");
04173 return -1;
04174 }
04175
04176
04177 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[vms->curmsg]);
04178
04179 if (ast_strlen_zero(header_content)) {
04180 ast_log (LOG_ERROR,"Could not fetch header for message number %ld\n",vms->msgArray[vms->curmsg]);
04181 return -1;
04182 }
04183
04184 temp = get_header_by_tag(header_content, "X-Asterisk-VM-Duration:");
04185 if (temp)
04186 duration = atoi(temp);
04187 else
04188 duration = 0;
04189
04190
04191 fmt = ast_strdupa(fmt);
04192 if (fmt) {
04193 stringp = fmt;
04194 strsep(&stringp, "|");
04195 } else {
04196 ast_log (LOG_ERROR,"audio format not set. Default to WAV\n");
04197 fmt = "WAV";
04198 }
04199 if (!strcasecmp(fmt, "wav49"))
04200 fmt = "WAV";
04201 if (option_debug > 2)
04202 ast_log (LOG_DEBUG,"**** format set to %s, vmfmts set to %s\n",fmt,vmfmts);
04203
04204
04205 snprintf(todir, sizeof(todir), "%s%s/%s/tmp", VM_SPOOL_DIR, vmtmp->context, vmtmp->mailbox);
04206 make_gsm_file(vms->fn, sizeof(vms->fn), vms->imapuser, todir, vms->curmsg);
04207 if (option_debug > 2)
04208 ast_log (LOG_DEBUG,"Before mail_fetchstructure, message number is %ld, filename is:%s\n",vms->msgArray[vms->curmsg], vms->fn);
04209
04210 mail_fetchstructure (vms->mailstream, vms->msgArray[vms->curmsg], &body);
04211 save_body(body,vms,"3","gsm");
04212
04213 save_body(body,vms,"2",fmt);
04214
04215
04216 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox,0);
04217 if (dstvms) {
04218 init_mailstream(dstvms, 0);
04219 if (!dstvms->mailstream) {
04220 ast_log (LOG_ERROR,"IMAP mailstream for %s is NULL\n",vmtmp->mailbox);
04221 } else {
04222 STORE(todir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms);
04223 run_externnotify(vmtmp->context, vmtmp->mailbox);
04224 }
04225 } else {
04226 ast_log (LOG_ERROR,"Could not find state information for mailbox %s\n",vmtmp->mailbox);
04227 }
04228
04229 myserveremail = serveremail;
04230 if (!ast_strlen_zero(vmtmp->serveremail))
04231 myserveremail = vmtmp->serveremail;
04232 attach_user_voicemail = ast_test_flag((&globalflags), VM_ATTACH);
04233 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
04234
04235 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), vms->fn, fmt, duration, attach_user_voicemail, chan, NULL);
04236 #else
04237 copy_message(chan, sender, -1, curmsg, duration, vmtmp, fmt, vmstmp.curdir);
04238 #endif
04239 saved_messages++;
04240 AST_LIST_REMOVE_CURRENT(&extensions, list);
04241 free_user(vmtmp);
04242 if (res)
04243 break;
04244 }
04245 AST_LIST_TRAVERSE_SAFE_END;
04246 if (saved_messages > 0) {
04247
04248
04249
04250
04251
04252
04253
04254
04255 res = ast_play_and_wait(chan, "vm-msgsaved");
04256 }
04257 }
04258
04259
04260 vm_delete(msgfile);
04261 }
04262
04263
04264 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list)))
04265 free_user(vmtmp);
04266 return res ? res : cmd;
04267 }
04268
04269 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
04270 {
04271 int res;
04272 if ((res = ast_stream_and_wait(chan, file, chan->language, AST_DIGIT_ANY)) < 0)
04273 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
04274 return res;
04275 }
04276
04277 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
04278 {
04279 return ast_control_streamfile(chan, file, "#", "*", "1456789", "0", "2", skipms);
04280 }
04281
04282 static int play_message_category(struct ast_channel *chan, const char *category)
04283 {
04284 int res = 0;
04285
04286 if (!ast_strlen_zero(category))
04287 res = ast_play_and_wait(chan, category);
04288
04289 if (res) {
04290 ast_log(LOG_WARNING, "No sound file for category '%s' was found.\n", category);
04291 res = 0;
04292 }
04293
04294 return res;
04295 }
04296
04297 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
04298 {
04299 int res = 0;
04300 struct vm_zone *the_zone = NULL;
04301 time_t t;
04302
04303 if (ast_get_time_t(origtime, &t, 0, NULL)) {
04304 ast_log(LOG_WARNING, "Couldn't find origtime in %s\n", filename);
04305 return 0;
04306 }
04307
04308
04309 if (!ast_strlen_zero(vmu->zonetag)) {
04310
04311 struct vm_zone *z;
04312 AST_LIST_LOCK(&zones);
04313 AST_LIST_TRAVERSE(&zones, z, list) {
04314 if (!strcmp(z->name, vmu->zonetag)) {
04315 the_zone = z;
04316 break;
04317 }
04318 }
04319 AST_LIST_UNLOCK(&zones);
04320 }
04321
04322
04323 #if 0
04324
04325 ast_localtime(&t, &time_now, NULL);
04326 tv_now = ast_tvnow();
04327 tnow = tv_now.tv_sec;
04328 ast_localtime(&tnow, &time_then, NULL);
04329
04330
04331 if (time_now.tm_year == time_then.tm_year)
04332 snprintf(temp,sizeof(temp),"%d",time_now.tm_yday);
04333 else
04334 snprintf(temp,sizeof(temp),"%d",(time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
04335 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
04336
04337
04338 #endif
04339 if (the_zone)
04340 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
04341 else if (!strncasecmp(chan->language,"pl",2))
04342 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
04343 else if (!strncasecmp(chan->language,"se",2))
04344 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
04345 else if (!strncasecmp(chan->language,"no",2))
04346 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
04347 else if (!strncasecmp(chan->language,"de",2))
04348 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
04349 else if (!strncasecmp(chan->language,"nl",2))
04350 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
04351 else if (!strncasecmp(chan->language,"it",2))
04352 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);
04353 else if (!strncasecmp(chan->language,"gr",2))
04354 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
04355 else if (!strcasecmp(chan->language,"pt_BR"))
04356 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);
04357 else
04358 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
04359 #if 0
04360 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
04361 #endif
04362 return res;
04363 }
04364
04365
04366
04367 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
04368 {
04369 int res = 0;
04370 int i;
04371 char *callerid, *name;
04372 char prefile[PATH_MAX] = "";
04373
04374
04375
04376
04377 if ((cid == NULL)||(context == NULL))
04378 return res;
04379
04380
04381 if (option_debug > 2)
04382 ast_log(LOG_DEBUG, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
04383 ast_callerid_parse(cid, &name, &callerid);
04384 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
04385
04386
04387 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
04388 if (option_debug > 2)
04389 ast_log(LOG_DEBUG, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
04390 if ((strcmp(cidinternalcontexts[i], context) == 0))
04391 break;
04392 }
04393 if (i != MAX_NUM_CID_CONTEXTS){
04394 if (!res) {
04395 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
04396 if (!ast_strlen_zero(prefile)) {
04397
04398 if (ast_fileexists(prefile, NULL, NULL) > 0) {
04399 if (option_verbose > 2)
04400 ast_verbose(VERBOSE_PREFIX_3 "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
04401 if (!callback)
04402 res = wait_file2(chan, vms, "vm-from");
04403 res = ast_stream_and_wait(chan, prefile, chan->language, "");
04404 } else {
04405 if (option_verbose > 2)
04406 ast_verbose(VERBOSE_PREFIX_3 "Playing envelope info: message from '%s'\n", callerid);
04407
04408 if (!callback)
04409 res = wait_file2(chan, vms, "vm-from-extension");
04410 res = ast_say_digit_str(chan, callerid, "", chan->language);
04411 }
04412 }
04413 }
04414 }
04415
04416 else if (!res){
04417 if (option_debug > 2)
04418 ast_log(LOG_DEBUG, "VM-CID: Numeric caller id: (%s)\n",callerid);
04419
04420 if (!callback)
04421 res = wait_file2(chan, vms, "vm-from-phonenumber");
04422 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
04423 }
04424 } else {
04425
04426 if (option_debug)
04427 ast_log(LOG_DEBUG, "VM-CID: From an unknown number\n");
04428
04429 res = wait_file2(chan, vms, "vm-unknown-caller");
04430 }
04431 return res;
04432 }
04433
04434 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
04435 {
04436 int res = 0;
04437 int durationm;
04438 int durations;
04439
04440 if (duration == NULL)
04441 return res;
04442
04443
04444 durations=atoi(duration);
04445 durationm=(durations / 60);
04446
04447 if (option_debug > 2)
04448 ast_log(LOG_DEBUG, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
04449
04450 if ((!res) && (durationm >= minduration)) {
04451 res = wait_file2(chan, vms, "vm-duration");
04452
04453
04454 if (!strncasecmp(chan->language, "pl",2)) {
04455 div_t num = div(durationm, 10);
04456
04457 if (durationm == 1) {
04458 res = ast_play_and_wait(chan, "digits/1z");
04459 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
04460 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
04461 if (num.rem == 2) {
04462 if (!num.quot) {
04463 res = ast_play_and_wait(chan, "digits/2-ie");
04464 } else {
04465 res = say_and_wait(chan, durationm - 2 , chan->language);
04466 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
04467 }
04468 } else {
04469 res = say_and_wait(chan, durationm, chan->language);
04470 }
04471 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
04472 } else {
04473 res = say_and_wait(chan, durationm, chan->language);
04474 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
04475 }
04476
04477 } else {
04478 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
04479 res = wait_file2(chan, vms, "vm-minutes");
04480 }
04481 }
04482 return res;
04483 }
04484
04485 #ifdef IMAP_STORAGE
04486 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
04487 {
04488 BODY *body;
04489 char *header_content;
04490 char cid[256];
04491 char context[256];
04492 char origtime[32];
04493 char duration[16];
04494 char category[32];
04495 char todir[PATH_MAX];
04496 int res = 0;
04497 char *attachedfilefmt;
04498 char *temp;
04499
04500 vms->starting = 0;
04501 if (option_debug > 2)
04502 ast_log (LOG_DEBUG,"Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n",vms->curmsg, vms->msgArray[vms->curmsg]);
04503 if (vms->msgArray[vms->curmsg] == 0) {
04504 ast_log (LOG_WARNING,"Trying to access unknown message\n");
04505 return -1;
04506 }
04507
04508
04509 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[vms->curmsg]);
04510
04511 if (ast_strlen_zero(header_content)) {
04512 ast_log (LOG_ERROR,"Could not fetch header for message number %ld\n",vms->msgArray[vms->curmsg]);
04513 return -1;
04514 }
04515 snprintf(todir, sizeof(todir), "%s%s/%s/tmp", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
04516 make_gsm_file(vms->fn, sizeof(vms->fn), vms->imapuser, todir, vms->curmsg);
04517
04518 mail_fetchstructure (vms->mailstream,vms->msgArray[vms->curmsg],&body);
04519
04520
04521 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
04522 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
04523 } else {
04524 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
04525 return -1;
04526 }
04527
04528
04529
04530 strsep(&attachedfilefmt, ".");
04531 if (!attachedfilefmt) {
04532 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
04533 return -1;
04534 }
04535 save_body(body, vms, "2", attachedfilefmt);
04536
04537 adsi_message(chan, vms);
04538 if (!vms->curmsg)
04539 res = wait_file2(chan, vms, "vm-first");
04540 else if (vms->curmsg == vms->lastmsg)
04541 res = wait_file2(chan, vms, "vm-last");
04542 if (!res) {
04543 res = wait_file2(chan, vms, "vm-message");
04544 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
04545 if (!res)
04546 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
04547 }
04548 }
04549
04550
04551 temp = get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:");
04552
04553 if (temp)
04554 ast_copy_string(cid, temp, sizeof(cid));
04555 else
04556 cid[0] = '\0';
04557
04558 temp = get_header_by_tag(header_content, "X-Asterisk-VM-Context:");
04559
04560 if (temp)
04561 ast_copy_string(context, temp, sizeof(context));
04562 else
04563 context[0] = '\0';
04564
04565 temp = get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:");
04566
04567 if (temp)
04568 ast_copy_string(origtime, temp, sizeof(origtime));
04569 else
04570 origtime[0] = '\0';
04571
04572 temp = get_header_by_tag(header_content, "X-Asterisk-VM-Duration:");
04573
04574 if (temp)
04575 ast_copy_string(duration,temp, sizeof(duration));
04576 else
04577 duration[0] = '\0';
04578
04579 temp = get_header_by_tag(header_content, "X-Asterisk-VM-Category:");
04580
04581 if (temp)
04582 ast_copy_string(category,temp, sizeof(category));
04583 else
04584 category[0] = '\0';
04585
04586
04587
04588 if (res == '1')
04589 res = 0;
04590
04591 if ((!res) && !ast_strlen_zero(category)) {
04592 res = play_message_category(chan, category);
04593 }
04594
04595 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE)) && origtime[0] != '\0')
04596 res = play_message_datetime(chan, vmu, origtime, "IMAP_STORAGE");
04597 if ((!res) && (ast_test_flag(vmu, VM_SAYCID)) && cid[0] !='\0' && context[0] !='\0')
04598 res = play_message_callerid(chan, vms, cid, context, 0);
04599
04600 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION)) && duration[0] != '\0')
04601 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
04602
04603
04604
04605
04606
04607
04608 res = 0;
04609
04610 if (!res) {
04611 vms->heard[vms->curmsg] = 1;
04612 res = wait_file(chan, vms, vms->fn);
04613 }
04614 DISPOSE(vms->curdir, vms->curmsg);
04615 DELETE(0, 0, vms->fn);
04616 return res;
04617 }
04618 #else
04619 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
04620 {
04621 int res = 0;
04622 char filename[256], *cid;
04623 const char *origtime, *context, *category, *duration;
04624 struct ast_config *msg_cfg;
04625
04626 vms->starting = 0;
04627 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
04628 adsi_message(chan, vms);
04629 if (!vms->curmsg)
04630 res = wait_file2(chan, vms, "vm-first");
04631 else if (vms->curmsg == vms->lastmsg)
04632 res = wait_file2(chan, vms, "vm-last");
04633 if (!res) {
04634
04635 if (!strncasecmp(chan->language, "pl",2)) {
04636 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
04637 int ten, one;
04638 char nextmsg[256];
04639 ten = (vms->curmsg + 1) / 10;
04640 one = (vms->curmsg + 1) % 10;
04641
04642 if (vms->curmsg < 20) {
04643 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
04644 res = wait_file2(chan, vms, nextmsg);
04645 } else {
04646 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
04647 res = wait_file2(chan, vms, nextmsg);
04648 if (one > 0) {
04649 if (!res) {
04650 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
04651 res = wait_file2(chan, vms, nextmsg);
04652 }
04653 }
04654 }
04655 }
04656 if (!res)
04657 res = wait_file2(chan, vms, "vm-message");
04658 } else {
04659 if (!strncasecmp(chan->language,"se",2))
04660 res = wait_file2(chan, vms, "vm-meddelandet");
04661 else
04662 res = wait_file2(chan, vms, "vm-message");
04663 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
04664 if (!res)
04665 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
04666 }
04667 }
04668 }
04669
04670
04671 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
04672 snprintf(filename, sizeof(filename), "%s.txt", vms->fn2);
04673 RETRIEVE(vms->curdir, vms->curmsg);
04674 msg_cfg = ast_config_load(filename);
04675 if (!msg_cfg) {
04676 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
04677 return 0;
04678 }
04679
04680 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
04681 ast_log(LOG_WARNING, "No origtime?!\n");
04682 DISPOSE(vms->curdir, vms->curmsg);
04683 ast_config_destroy(msg_cfg);
04684 return 0;
04685 }
04686
04687 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
04688 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
04689 category = ast_variable_retrieve(msg_cfg, "message", "category");
04690
04691 context = ast_variable_retrieve(msg_cfg, "message", "context");
04692 if (!strncasecmp("macro",context,5))
04693 context = ast_variable_retrieve(msg_cfg, "message","macrocontext");
04694 if (!res)
04695 res = play_message_category(chan, category);
04696 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE)))
04697 res = play_message_datetime(chan, vmu, origtime, filename);
04698 if ((!res) && (ast_test_flag(vmu, VM_SAYCID)))
04699 res = play_message_callerid(chan, vms, cid, context, 0);
04700 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION)))
04701 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
04702
04703 if (res == '1')
04704 res = 0;
04705 ast_config_destroy(msg_cfg);
04706
04707 if (!res) {
04708 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
04709 vms->heard[vms->curmsg] = 1;
04710 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
04711 ast_log(LOG_WARNING, "Playback of message %s failed\n", vms->fn);
04712 res = 0;
04713 }
04714 }
04715 DISPOSE(vms->curdir, vms->curmsg);
04716 return res;
04717 }
04718 #endif
04719
04720 #ifdef IMAP_STORAGE
04721 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
04722 {
04723 char tmp[256], *t = tmp;
04724 size_t left = sizeof(tmp);
04725
04726 if (box == 1) {
04727 ast_copy_string(vms->curbox, mbox(0), sizeof(vms->curbox));
04728 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(1));
04729 } else {
04730 ast_copy_string(vms->curbox, mbox(box), sizeof(vms->curbox));
04731 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
04732 }
04733
04734
04735 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
04736
04737
04738 if (!ast_strlen_zero(authuser))
04739 ast_build_string(&t, &left, "/authuser=%s", authuser);
04740
04741
04742 if (!ast_strlen_zero(imapflags))
04743 ast_build_string(&t, &left, "/%s", imapflags);
04744
04745
04746 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
04747
04748 if (box == 0 || box == 1)
04749 snprintf(spec, len, "%s%s", tmp, use_folder? imapfolder: "INBOX");
04750 else
04751 snprintf(spec, len, "%s%s%c%s", tmp, imapfolder, delimiter, mbox(box));
04752 }
04753
04754 static int init_mailstream(struct vm_state *vms, int box)
04755 {
04756 MAILSTREAM *stream = NIL;
04757 long debug;
04758 char tmp[256];
04759
04760 if (!vms) {
04761 ast_log (LOG_ERROR,"vm_state is NULL!\n");
04762 return -1;
04763 }
04764 if (option_debug > 2)
04765 ast_log (LOG_DEBUG,"vm_state user is:%s\n",vms->imapuser);
04766 if (vms->mailstream == NIL || !vms->mailstream) {
04767 if (option_debug)
04768 ast_log (LOG_DEBUG,"mailstream not set.\n");
04769 } else {
04770 stream = vms->mailstream;
04771 }
04772
04773 debug = NIL;
04774
04775 if (delimiter == '\0') {
04776 char *cp;
04777 #ifdef USE_SYSTEM_IMAP
04778 #include <imap/linkage.c>
04779 #elif defined(USE_SYSTEM_CCLIENT)
04780 #include <c-client/linkage.c>
04781 #else
04782 #include "linkage.c"
04783 #endif
04784
04785 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
04786 ast_mutex_lock(&vms->lock);
04787 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
04788 ast_mutex_unlock(&vms->lock);
04789 if (stream == NIL) {
04790 ast_log (LOG_ERROR, "Can't connect to imap server %s\n", tmp);
04791 return -1;
04792 }
04793 get_mailbox_delimiter(stream);
04794
04795 for (cp = imapfolder; *cp; cp++)
04796 if (*cp == '/')
04797 *cp = delimiter;
04798 }
04799
04800 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
04801 if (option_debug > 2)
04802 ast_log (LOG_DEBUG,"Before mail_open, server: %s, box:%d\n", tmp, box);
04803 ast_mutex_lock(&vms->lock);
04804 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
04805 ast_mutex_unlock(&vms->lock);
04806 if (vms->mailstream == NIL) {
04807 return -1;
04808 } else {
04809 return 0;
04810 }
04811 }
04812
04813 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
04814 {
04815 SEARCHPGM *pgm;
04816 SEARCHHEADER *hdr;
04817 int ret;
04818
04819 ast_copy_string(vms->imapuser,vmu->imapuser, sizeof(vms->imapuser));
04820 if (option_debug > 2)
04821 ast_log(LOG_DEBUG,"Before init_mailstream, user is %s\n",vmu->imapuser);
04822 ret = init_mailstream(vms, box);
04823 if (ret != 0 || !vms->mailstream) {
04824 ast_log (LOG_ERROR,"Could not initialize mailstream\n");
04825 return -1;
04826 }
04827
04828
04829 if (box == 0) {
04830 if (option_debug > 2)
04831 ast_log(LOG_DEBUG, "Mailbox name set to: %s, about to check quotas\n", mbox(box));
04832 check_quota(vms,(char *)mbox(box));
04833 }
04834
04835 pgm = mail_newsearchpgm();
04836
04837
04838 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", vmu->mailbox);
04839 pgm->header = hdr;
04840 pgm->deleted = 0;
04841 pgm->undeleted = 1;
04842
04843
04844 if (box == 0) {
04845 pgm->unseen = 1;
04846 pgm->seen = 0;
04847 } else if (box == 1) {
04848 pgm->seen = 1;
04849 pgm->unseen = 0;
04850 }
04851
04852 vms->vmArrayIndex = 0;
04853 if (option_debug > 2)
04854 ast_log(LOG_DEBUG,"Before mail_search_full, user is %s\n",vmu->imapuser);
04855 mail_search_full (vms->mailstream, NULL, pgm, NIL);
04856
04857
04858 vms->lastmsg = vms->vmArrayIndex - 1;
04859
04860 mail_free_searchpgm(&pgm);
04861 return 0;
04862 }
04863 #else
04864 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box)
04865 {
04866 int res = 0;
04867 int count_msg, last_msg;
04868
04869 ast_copy_string(vms->curbox, mbox(box), sizeof(vms->curbox));
04870
04871
04872
04873
04874 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
04875
04876
04877 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
04878
04879 count_msg = count_messages(vmu, vms->curdir);
04880 if (count_msg < 0)
04881 return count_msg;
04882 else
04883 vms->lastmsg = count_msg - 1;
04884
04885
04886
04887
04888
04889
04890
04891
04892 last_msg = last_message_index(vmu, vms->curdir);
04893 if (last_msg < 0)
04894 return last_msg;
04895 else if (vms->lastmsg != last_msg)
04896 {
04897 ast_log(LOG_NOTICE, "Resequencing Mailbox: %s\n", vms->curdir);
04898 res = resequence_mailbox(vmu, vms->curdir);
04899 if (res)
04900 return res;
04901 }
04902
04903 return 0;
04904 }
04905 #endif
04906
04907 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
04908 {
04909 int x = 0;
04910 #ifndef IMAP_STORAGE
04911 int res = 0, nummsg;
04912 #endif
04913
04914 if (vms->lastmsg <= -1)
04915 goto done;
04916
04917 vms->curmsg = -1;
04918 #ifndef IMAP_STORAGE
04919
04920 if (vm_lock_path(vms->curdir))
04921 return ERROR_LOCK_PATH;
04922
04923 for (x = 0; x < vmu->maxmsg; x++) {
04924 if (!vms->deleted[x] && (strcasecmp(vms->curbox, "INBOX") || !vms->heard[x])) {
04925
04926 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
04927 if (!EXISTS(vms->curdir, x, vms->fn, NULL))
04928 break;
04929 vms->curmsg++;
04930 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
04931 if (strcmp(vms->fn, vms->fn2)) {
04932 RENAME(vms->curdir, x, vmu->mailbox,vmu->context, vms->curdir, vms->curmsg, vms->fn, vms->fn2);
04933 }
04934 } else if (!strcasecmp(vms->curbox, "INBOX") && vms->heard[x] && !vms->deleted[x]) {
04935
04936 res = save_to_folder(vmu, vms, x, 1);
04937 if (res == ERROR_LOCK_PATH || res == ERROR_MAILBOX_FULL) {
04938
04939 ast_log(LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
04940 vms->deleted[x] = 0;
04941 vms->heard[x] = 0;
04942 --x;
04943 }
04944 }
04945 }
04946
04947
04948 nummsg = x - 1;
04949 for (x = vms->curmsg + 1; x <= nummsg; x++) {
04950 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
04951 if (EXISTS(vms->curdir, x, vms->fn, NULL))
04952 DELETE(vms->curdir, x, vms->fn);
04953 }
04954 ast_unlock_path(vms->curdir);
04955 #else
04956 if (vms->deleted) {
04957 for (x=0;x < vmu->maxmsg;x++) {
04958 if (vms->deleted[x]) {
04959 if (option_debug > 2)
04960 ast_log(LOG_DEBUG,"IMAP delete of %d\n",x);
04961 IMAP_DELETE(vms->curdir, x, vms->fn, vms);
04962 }
04963 }
04964 }
04965 #endif
04966
04967 done:
04968 if (vms->deleted)
04969 memset(vms->deleted, 0, vmu->maxmsg * sizeof(int));
04970 if (vms->heard)
04971 memset(vms->heard, 0, vmu->maxmsg * sizeof(int));
04972
04973 return 0;
04974 }
04975
04976
04977
04978
04979
04980
04981
04982 static int vm_play_folder_name_gr(struct ast_channel *chan, char *mbox)
04983 {
04984 int cmd;
04985 char *buf;
04986
04987 buf = alloca(strlen(mbox)+2);
04988 strcpy(buf, mbox);
04989 strcat(buf,"s");
04990
04991 if (!strcasecmp(mbox, "vm-INBOX") || !strcasecmp(mbox, "vm-Old")){
04992 cmd = ast_play_and_wait(chan, buf);
04993 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
04994 } else {
04995 cmd = ast_play_and_wait(chan, "vm-messages");
04996 return cmd ? cmd : ast_play_and_wait(chan, mbox);
04997 }
04998 }
04999
05000 static int vm_play_folder_name_pl(struct ast_channel *chan, char *mbox)
05001 {
05002 int cmd;
05003
05004 if (!strcasecmp(mbox, "vm-INBOX") || !strcasecmp(mbox, "vm-Old")) {
05005 if (!strcasecmp(mbox, "vm-INBOX"))
05006 cmd = ast_play_and_wait(chan, "vm-new-e");
05007 else
05008 cmd = ast_play_and_wait(chan, "vm-old-e");
05009 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
05010 } else {
05011 cmd = ast_play_and_wait(chan, "vm-messages");
05012 return cmd ? cmd : ast_play_and_wait(chan, mbox);
05013 }
05014 }
05015
05016 static int vm_play_folder_name_ua(struct ast_channel *chan, char *mbox)
05017 {
05018 int cmd;
05019
05020 if (!strcasecmp(mbox, "vm-Family") || !strcasecmp(mbox, "vm-Friends") || !strcasecmp(mbox, "vm-Work")){
05021 cmd = ast_play_and_wait(chan, "vm-messages");
05022 return cmd ? cmd : ast_play_and_wait(chan, mbox);
05023 } else {
05024 cmd = ast_play_and_wait(chan, mbox);
05025 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
05026 }
05027 }
05028
05029 static int vm_play_folder_name(struct ast_channel *chan, char *mbox)
05030 {
05031 int cmd;
05032
05033 if (!strncasecmp(chan->language, "it", 2) || !strncasecmp(chan->language, "es", 2) || !strncasecmp(chan->language, "fr", 2) || !strncasecmp(chan->language, "pt", 2)) {
05034 cmd = ast_play_and_wait(chan, "vm-messages");
05035 return cmd ? cmd : ast_play_and_wait(chan, mbox);
05036 } else if (!strncasecmp(chan->language, "gr", 2)){
05037 return vm_play_folder_name_gr(chan, mbox);
05038 } else if (!strncasecmp(chan->language, "pl", 2)){
05039 return vm_play_folder_name_pl(chan, mbox);
05040 } else if (!strncasecmp(chan->language, "ua", 2)){
05041 return vm_play_folder_name_ua(chan, mbox);
05042 } else {
05043 cmd = ast_play_and_wait(chan, mbox);
05044 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
05045 }
05046 }
05047
05048
05049
05050
05051
05052
05053
05054
05055
05056
05057
05058
05059
05060 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
05061 {
05062 int res = 0;
05063
05064 if (vms->newmessages) {
05065 res = ast_play_and_wait(chan, "vm-youhave");
05066 if (!res)
05067 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
05068 if (!res) {
05069 if ((vms->newmessages == 1)) {
05070 res = ast_play_and_wait(chan, "vm-INBOX");
05071 if (!res)
05072 res = ast_play_and_wait(chan, "vm-message");
05073 } else {
05074 res = ast_play_and_wait(chan, "vm-INBOXs");
05075 if (!res)
05076 res = ast_play_and_wait(chan, "vm-messages");
05077 }
05078 }
05079 } else if (vms->oldmessages){
05080 res = ast_play_and_wait(chan, "vm-youhave");
05081 if (!res)
05082 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
05083 if ((vms->oldmessages == 1)){
05084 res = ast_play_and_wait(chan, "vm-Old");
05085 if (!res)
05086 res = ast_play_and_wait(chan, "vm-message");
05087 } else {
05088 res = ast_play_and_wait(chan, "vm-Olds");
05089 if (!res)
05090 res = ast_play_and_wait(chan, "vm-messages");
05091 }
05092 } else if (!vms->oldmessages && !vms->newmessages)
05093 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
05094 return res;
05095 }
05096
05097
05098 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
05099 {
05100 int res;
05101
05102
05103 res = ast_play_and_wait(chan, "vm-youhave");
05104 if (!res) {
05105 if (vms->newmessages) {
05106 res = say_and_wait(chan, vms->newmessages, chan->language);
05107 if (!res)
05108 res = ast_play_and_wait(chan, "vm-INBOX");
05109 if (vms->oldmessages && !res)
05110 res = ast_play_and_wait(chan, "vm-and");
05111 else if (!res) {
05112 if ((vms->newmessages == 1))
05113 res = ast_play_and_wait(chan, "vm-message");
05114 else
05115 res = ast_play_and_wait(chan, "vm-messages");
05116 }
05117
05118 }
05119 if (!res && vms->oldmessages) {
05120 res = say_and_wait(chan, vms->oldmessages, chan->language);
05121 if (!res)
05122 res = ast_play_and_wait(chan, "vm-Old");
05123 if (!res) {
05124 if (vms->oldmessages == 1)
05125 res = ast_play_and_wait(chan, "vm-message");
05126 else
05127 res = ast_play_and_wait(chan, "vm-messages");
05128 }
05129 }
05130 if (!res) {
05131 if (!vms->oldmessages && !vms->newmessages) {
05132 res = ast_play_and_wait(chan, "vm-no");
05133 if (!res)
05134 res = ast_play_and_wait(chan, "vm-messages");
05135 }
05136 }
05137 }
05138 return res;
05139 }
05140
05141
05142 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
05143 {
05144
05145 int res;
05146 if (!vms->oldmessages && !vms->newmessages)
05147 res = ast_play_and_wait(chan, "vm-no") ||
05148 ast_play_and_wait(chan, "vm-message");
05149 else
05150 res = ast_play_and_wait(chan, "vm-youhave");
05151 if (!res && vms->newmessages) {
05152 res = (vms->newmessages == 1) ?
05153 ast_play_and_wait(chan, "digits/un") ||
05154 ast_play_and_wait(chan, "vm-nuovo") ||
05155 ast_play_and_wait(chan, "vm-message") :
05156
05157 say_and_wait(chan, vms->newmessages, chan->language) ||
05158 ast_play_and_wait(chan, "vm-nuovi") ||
05159 ast_play_and_wait(chan, "vm-messages");
05160 if (!res && vms->oldmessages)
05161 res = ast_play_and_wait(chan, "vm-and");
05162 }
05163 if (!res && vms->oldmessages) {
05164 res = (vms->oldmessages == 1) ?
05165 ast_play_and_wait(chan, "digits/un") ||
05166 ast_play_and_wait(chan, "vm-vecchio") ||
05167 ast_play_and_wait(chan, "vm-message") :
05168
05169 say_and_wait(chan, vms->oldmessages, chan->language) ||
05170 ast_play_and_wait(chan, "vm-vecchi") ||
05171 ast_play_and_wait(chan, "vm-messages");
05172 }
05173 return res ? -1 : 0;
05174 }
05175
05176
05177 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
05178 {
05179
05180 int res;
05181 div_t num;
05182
05183 if (!vms->oldmessages && !vms->newmessages) {
05184 res = ast_play_and_wait(chan, "vm-no");
05185 res = res ? res : ast_play_and_wait(chan, "vm-messages");
05186 return res;
05187 } else {
05188 res = ast_play_and_wait(chan, "vm-youhave");
05189 }
05190
05191 if (vms->newmessages) {
05192 num = div(vms->newmessages, 10);
05193 if (vms->newmessages == 1) {
05194 res = ast_play_and_wait(chan, "digits/1-a");
05195 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
05196 res = res ? res : ast_play_and_wait(chan, "vm-message");
05197 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
05198 if (num.rem == 2) {
05199 if (!num.quot) {
05200 res = ast_play_and_wait(chan, "digits/2-ie");
05201 } else {
05202 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
05203 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
05204 }
05205 } else {
05206 res = say_and_wait(chan, vms->newmessages, chan->language);
05207 }
05208 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
05209 res = res ? res : ast_play_and_wait(chan, "vm-messages");
05210 } else {
05211 res = say_and_wait(chan, vms->newmessages, chan->language);
05212 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
05213 res = res ? res : ast_play_and_wait(chan, "vm-messages");
05214 }
05215 if (!res && vms->oldmessages)
05216 res = ast_play_and_wait(chan, "vm-and");
05217 }
05218 if (!res && vms->oldmessages) {
05219 num = div(vms->oldmessages, 10);
05220 if (vms->oldmessages == 1) {
05221 res = ast_play_and_wait(chan, "digits/1-a");
05222 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
05223 res = res ? res : ast_play_and_wait(chan, "vm-message");
05224 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
05225 if (num.rem == 2) {
05226 if (!num.quot) {
05227 res = ast_play_and_wait(chan, "digits/2-ie");
05228 } else {
05229 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
05230 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
05231 }
05232 } else {
05233 res = say_and_wait(chan, vms->oldmessages, chan->language);
05234 }
05235 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
05236 res = res ? res : ast_play_and_wait(chan, "vm-messages");
05237 } else {
05238 res = say_and_wait(chan, vms->oldmessages, chan->language);
05239 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
05240 res = res ? res : ast_play_and_wait(chan, "vm-messages");
05241 }
05242 }
05243
05244 return res;
05245 }
05246
05247
05248 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
05249 {
05250
05251 int res;
05252
05253 res = ast_play_and_wait(chan, "vm-youhave");
05254 if (res)
05255 return res;
05256
05257 if (!vms->oldmessages && !vms->newmessages) {
05258 res = ast_play_and_wait(chan, "vm-no");
05259 res = res ? res : ast_play_and_wait(chan, "vm-messages");
05260 return res;
05261 }
05262
05263 if (vms->newmessages) {
05264 if ((vms->newmessages == 1)) {
05265 res = ast_play_and_wait(chan, "digits/ett");
05266 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
05267 res = res ? res : ast_play_and_wait(chan, "vm-message");
05268 } else {
05269 res = say_and_wait(chan, vms->newmessages, chan->language);
05270 res = res ? res : ast_play_and_wait(chan, "vm-nya");
05271 res = res ? res : ast_play_and_wait(chan, "vm-messages");
05272 }
05273 if (!res && vms->oldmessages)
05274 res = ast_play_and_wait(chan, "vm-and");
05275 }
05276 if (!res && vms->oldmessages) {
05277 if (vms->oldmessages == 1) {
05278 res = ast_play_and_wait(chan, "digits/ett");
05279 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
05280 res = res ? res : ast_play_and_wait(chan, "vm-message");
05281 } else {
05282 res = say_and_wait(chan, vms->oldmessages, chan->language);
05283 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
05284 res = res ? res : ast_play_and_wait(chan, "vm-messages");
05285 }
05286 }
05287
05288 return res;
05289 }
05290
05291
05292 static int vm_intro_no(struct ast_channel *chan,struct vm_state *vms)
05293 {
05294
05295 int res;
05296
05297 res = ast_play_and_wait(chan, "vm-youhave");
05298 if (res)
05299 return res;
05300
05301 if (!vms->oldmessages && !vms->newmessages) {
05302 res = ast_play_and_wait(chan, "vm-no");
05303 res = res ? res : ast_play_and_wait(chan, "vm-messages");
05304 return res;
05305 }
05306
05307 if (vms->newmessages) {
05308 if ((vms->newmessages == 1)) {
05309 res = ast_play_and_wait(chan, "digits/1");
05310 res = res ? res : ast_play_and_wait(chan, "vm-ny");
05311 res = res ? res : ast_play_and_wait(chan, "vm-message");
05312 } else {
05313 res = say_and_wait(chan, vms->newmessages, chan->language);
05314 res = res ? res : ast_play_and_wait(chan, "vm-nye");
05315 res = res ? res : ast_play_and_wait(chan, "vm-messages");
05316 }
05317 if (!res && vms->oldmessages)
05318 res = ast_play_and_wait(chan, "vm-and");
05319 }
05320 if (!res && vms->oldmessages) {
05321 if (vms->oldmessages == 1) {
05322 res = ast_play_and_wait(chan, "digits/1");
05323 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
05324 res = res ? res : ast_play_and_wait(chan, "vm-message");
05325 } else {
05326 res = say_and_wait(chan, vms->oldmessages, chan->language);
05327 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
05328 res = res ? res : ast_play_and_wait(chan, "vm-messages");
05329 }
05330 }
05331
05332 return res;
05333 }
05334
05335
05336 static int vm_intro_de(struct ast_channel *chan,struct vm_state *vms)
05337 {
05338
05339 int res;
05340 res = ast_play_and_wait(chan, "vm-youhave");
05341 if (!res) {
05342 if (vms->newmessages) {
05343 if ((vms->newmessages == 1))
05344 res = ast_play_and_wait(chan, "digits/1F");
05345 else
05346 res = say_and_wait(chan, vms->newmessages, chan->language);
05347 if (!res)
05348 res = ast_play_and_wait(chan, "vm-INBOX");
05349 if (vms->oldmessages && !res)
05350 res = ast_play_and_wait(chan, "vm-and");
05351 else if (!res) {
05352 if ((vms->newmessages == 1))
05353 res = ast_play_and_wait(chan, "vm-message");
05354 else
05355 res = ast_play_and_wait(chan, "vm-messages");
05356 }
05357
05358 }
05359 if (!res && vms->oldmessages) {
05360 if (vms->oldmessages == 1)
05361 res = ast_play_and_wait(chan, "digits/1F");
05362 else
05363 res = say_and_wait(chan, vms->oldmessages, chan->language);
05364 if (!res)
05365 res = ast_play_and_wait(chan, "vm-Old");
05366 if (!res) {
05367 if (vms->oldmessages == 1)
05368 res = ast_play_and_wait(chan, "vm-message");
05369 else
05370 res = ast_play_and_wait(chan, "vm-messages");
05371 }
05372 }
05373 if (!res) {
05374 if (!vms->oldmessages && !vms->newmessages) {
05375 res = ast_play_and_wait(chan, "vm-no");
05376 if (!res)
05377 res = ast_play_and_wait(chan, "vm-messages");
05378 }
05379 }
05380 }
05381 return res;
05382 }
05383
05384
05385 static int vm_intro_es(struct ast_channel *chan,struct vm_state *vms)
05386 {
05387
05388 int res;
05389 if (!vms->oldmessages && !vms->newmessages) {
05390 res = ast_play_and_wait(chan, "vm-youhaveno");
05391 if (!res)
05392 res = ast_play_and_wait(chan, "vm-messages");
05393 } else {
05394 res = ast_play_and_wait(chan, "vm-youhave");
05395 }
05396 if (!res) {
05397 if (vms->newmessages) {
05398 if (!res) {
05399 if ((vms->newmessages == 1)) {
05400 res = ast_play_and_wait(chan, "digits/1M");
05401 if (!res)
05402 res = ast_play_and_wait(chan, "vm-message");
05403 if (!res)
05404 res = ast_play_and_wait(chan, "vm-INBOXs");
05405 } else {
05406 res = say_and_wait(chan, vms->newmessages, chan->language);
05407 if (!res)
05408 res = ast_play_and_wait(chan, "vm-messages");
05409 if (!res)
05410 res = ast_play_and_wait(chan, "vm-INBOX");
05411 }
05412 }
05413 if (vms->oldmessages && !res)
05414 res = ast_play_and_wait(chan, "vm-and");
05415 }
05416 if (vms->oldmessages) {
05417 if (!res) {
05418 if (vms->oldmessages == 1) {
05419 res = ast_play_and_wait(chan, "digits/1M");
05420 if (!res)
05421 res = ast_play_and_wait(chan, "vm-message");
05422 if (!res)
05423 res = ast_play_and_wait(chan, "vm-Olds");
05424 } else {
05425 res = say_and_wait(chan, vms->oldmessages, chan->language);
05426 if (!res)
05427 res = ast_play_and_wait(chan, "vm-messages");
05428 if (!res)
05429 res = ast_play_and_wait(chan, "vm-Old");
05430 }
05431 }
05432 }
05433 }
05434 return res;
05435 }
05436
05437
05438 static int vm_intro_pt_BR(struct ast_channel *chan,struct vm_state *vms) {
05439
05440 int res;
05441 if (!vms->oldmessages && !vms->newmessages) {
05442 res = ast_play_and_wait(chan, "vm-nomessages");
05443 return res;
05444 }
05445 else {
05446 res = ast_play_and_wait(chan, "vm-youhave");
05447 }
05448 if (vms->newmessages) {
05449 if (!res)
05450 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
05451 if ((vms->newmessages == 1)) {
05452 if (!res)
05453 res = ast_play_and_wait(chan, "vm-message");
05454 if (!res)
05455 res = ast_play_and_wait(chan, "vm-INBOXs");
05456 }
05457 else {
05458 if (!res)
05459 res = ast_play_and_wait(chan, "vm-messages");
05460 if (!res)
05461 res = ast_play_and_wait(chan, "vm-INBOX");
05462 }
05463 if (vms->oldmessages && !res)
05464 res = ast_play_and_wait(chan, "vm-and");
05465 }
05466 if (vms->oldmessages) {
05467 if (!res)
05468 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
05469 if (vms->oldmessages == 1) {
05470 if (!res)
05471 res = ast_play_and_wait(chan, "vm-message");
05472 if (!res)
05473 res = ast_play_and_wait(chan, "vm-Olds");
05474 }
05475 else {
05476 if (!res)
05477 res = ast_play_and_wait(chan, "vm-messages");
05478 if (!res)
05479 res = ast_play_and_wait(chan, "vm-Old");
05480 }
05481 }
05482 return res;
05483 }
05484
05485
05486 static int vm_intro_fr(struct ast_channel *chan,struct vm_state *vms)
05487 {
05488
05489 int res;
05490 res = ast_play_and_wait(chan, "vm-youhave");
05491 if (!res) {
05492 if (vms->newmessages) {
05493 res = say_and_wait(chan, vms->newmessages, chan->language);
05494 if (!res)
05495 res = ast_play_and_wait(chan, "vm-INBOX");
05496 if (vms->oldmessages && !res)
05497 res = ast_play_and_wait(chan, "vm-and");
05498 else if (!res) {
05499 if ((vms->newmessages == 1))
05500 res = ast_play_and_wait(chan, "vm-message");
05501 else
05502 res = ast_play_and_wait(chan, "vm-messages");
05503 }
05504
05505 }
05506 if (!res && vms->oldmessages) {
05507 res = say_and_wait(chan, vms->oldmessages, chan->language);
05508 if (!res)
05509 res = ast_play_and_wait(chan, "vm-Old");
05510 if (!res) {
05511 if (vms->oldmessages == 1)
05512 res = ast_play_and_wait(chan, "vm-message");
05513 else
05514 res = ast_play_and_wait(chan, "vm-messages");
05515 }
05516 }
05517 if (!res) {
05518 if (!vms->oldmessages && !vms->newmessages) {
05519 res = ast_play_and_wait(chan, "vm-no");
05520 if (!res)
05521 res = ast_play_and_wait(chan, "vm-messages");
05522 }
05523 }
05524 }
05525 return res;
05526 }
05527
05528
05529 static int vm_intro_nl(struct ast_channel *chan,struct vm_state *vms)
05530 {
05531
05532 int res;
05533 res = ast_play_and_wait(chan, "vm-youhave");
05534 if (!res) {
05535 if (vms->newmessages) {
05536 res = say_and_wait(chan, vms->newmessages, chan->language);
05537 if (!res) {
05538 if (vms->newmessages == 1)
05539 res = ast_play_and_wait(chan, "vm-INBOXs");
05540 else
05541 res = ast_play_and_wait(chan, "vm-INBOX");
05542 }
05543 if (vms->oldmessages && !res)
05544 res = ast_play_and_wait(chan, "vm-and");
05545 else if (!res) {
05546 if ((vms->newmessages == 1))
05547 res = ast_play_and_wait(chan, "vm-message");
05548 else
05549 res = ast_play_and_wait(chan, "vm-messages");
05550 }
05551
05552 }
05553 if (!res && vms->oldmessages) {
05554 res = say_and_wait(chan, vms->oldmessages, chan->language);
05555 if (!res) {
05556 if (vms->oldmessages == 1)
05557 res = ast_play_and_wait(chan, "vm-Olds");
05558 else
05559 res = ast_play_and_wait(chan, "vm-Old");
05560 }
05561 if (!res) {
05562 if (vms->oldmessages == 1)
05563 res = ast_play_and_wait(chan, "vm-message");
05564 else
05565 res = ast_play_and_wait(chan, "vm-messages");
05566 }
05567 }
05568 if (!res) {
05569 if (!vms->oldmessages && !vms->newmessages) {
05570 res = ast_play_and_wait(chan, "vm-no");
05571 if (!res)
05572 res = ast_play_and_wait(chan, "vm-messages");
05573 }
05574 }
05575 }
05576 return res;
05577 }
05578
05579
05580 static int vm_intro_pt(struct ast_channel *chan,struct vm_state *vms)
05581 {
05582
05583 int res;
05584 res = ast_play_and_wait(chan, "vm-youhave");
05585 if (!res) {
05586 if (vms->newmessages) {
05587 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
05588 if (!res) {
05589 if ((vms->newmessages == 1)) {
05590 res = ast_play_and_wait(chan, "vm-message");
05591 if (!res)
05592 res = ast_play_and_wait(chan, "vm-INBOXs");
05593 } else {
05594 res = ast_play_and_wait(chan, "vm-messages");
05595 if (!res)
05596 res = ast_play_and_wait(chan, "vm-INBOX");
05597 }
05598 }
05599 if (vms->oldmessages && !res)
05600 res = ast_play_and_wait(chan, "vm-and");
05601 }
05602 if (!res && vms->oldmessages) {
05603 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
05604 if (!res) {
05605 if (vms->oldmessages == 1) {
05606 res = ast_play_and_wait(chan, "vm-message");
05607 if (!res)
05608 res = ast_play_and_wait(chan, "vm-Olds");
05609 } else {
05610 res = ast_play_and_wait(chan, "vm-messages");
05611 if (!res)
05612 res = ast_play_and_wait(chan, "vm-Old");
05613 }
05614 }
05615 }
05616 if (!res) {
05617 if (!vms->oldmessages && !vms->newmessages) {
05618 res = ast_play_and_wait(chan, "vm-no");
05619 if (!res)
05620 res = ast_play_and_wait(chan, "vm-messages");
05621 }
05622 }
05623 }
05624 return res;
05625 }
05626
05627
05628
05629
05630
05631
05632
05633
05634
05635
05636
05637
05638
05639
05640
05641
05642
05643 static int vm_intro_cz(struct ast_channel *chan,struct vm_state *vms)
05644 {
05645 int res;
05646 res = ast_play_and_wait(chan, "vm-youhave");
05647 if (!res) {
05648 if (vms->newmessages) {
05649 if (vms->newmessages == 1) {
05650 res = ast_play_and_wait(chan, "digits/jednu");
05651 } else {
05652 res = say_and_wait(chan, vms->newmessages, chan->language);
05653 }
05654 if (!res) {
05655 if ((vms->newmessages == 1))
05656 res = ast_play_and_wait(chan, "vm-novou");
05657 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
05658 res = ast_play_and_wait(chan, "vm-nove");
05659 if (vms->newmessages > 4)
05660 res = ast_play_and_wait(chan, "vm-novych");
05661 }
05662 if (vms->oldmessages && !res)
05663 res = ast_play_and_wait(chan, "vm-and");
05664 else if (!res) {
05665 if ((vms->newmessages == 1))
05666 res = ast_play_and_wait(chan, "vm-zpravu");
05667 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
05668 res = ast_play_and_wait(chan, "vm-zpravy");
05669 if (vms->newmessages > 4)
05670 res = ast_play_and_wait(chan, "vm-zprav");
05671 }
05672 }
05673 if (!res && vms->oldmessages) {
05674 res = say_and_wait(chan, vms->oldmessages, chan->language);
05675 if (!res) {
05676 if ((vms->oldmessages == 1))
05677 res = ast_play_and_wait(chan, "vm-starou");
05678 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
05679 res = ast_play_and_wait(chan, "vm-stare");
05680 if (vms->oldmessages > 4)
05681 res = ast_play_and_wait(chan, "vm-starych");
05682 }
05683 if (!res) {
05684 if ((vms->oldmessages == 1))
05685 res = ast_play_and_wait(chan, "vm-zpravu");
05686 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
05687 res = ast_play_and_wait(chan, "vm-zpravy");
05688 if (vms->oldmessages > 4)
05689 res = ast_play_and_wait(chan, "vm-zprav");
05690 }
05691 }
05692 if (!res) {
05693 if (!vms->oldmessages && !vms->newmessages) {
05694 res = ast_play_and_wait(chan, "vm-no");
05695 if (!res)
05696 res = ast_play_and_wait(chan, "vm-zpravy");
05697 }
05698 }
05699 }
05700 return res;
05701 }
05702
05703 static int get_lastdigits(int num)
05704 {
05705 num %= 100;
05706 return (num < 20) ? num : num % 10;
05707 }
05708
05709 static int vm_intro_ru(struct ast_channel *chan,struct vm_state *vms)
05710 {
05711 int res;
05712 int lastnum = 0;
05713 int dcnum;
05714
05715 res = ast_play_and_wait(chan, "vm-youhave");
05716 if (!res && vms->newmessages) {
05717 lastnum = get_lastdigits(vms->newmessages);
05718 dcnum = vms->newmessages - lastnum;
05719 if (dcnum)
05720 res = say_and_wait(chan, dcnum, chan->language);
05721 if (!res && lastnum) {
05722 if (lastnum == 1)
05723 res = ast_play_and_wait(chan, "digits/odno");
05724 else
05725 res = say_and_wait(chan, lastnum, chan->language);
05726 }
05727
05728 if (!res)
05729 res = ast_play_and_wait(chan, (lastnum == 1) ? "vm-novoe" : "vm-novyh");
05730
05731 if (!res && vms->oldmessages)
05732 res = ast_play_and_wait(chan, "vm-and");
05733 }
05734
05735 if (!res && vms->oldmessages) {
05736 lastnum = get_lastdigits(vms->oldmessages);
05737 dcnum = vms->oldmessages - lastnum;
05738 if (dcnum)
05739 res = say_and_wait(chan, dcnum, chan->language);
05740 if (!res && lastnum) {
05741 if (lastnum == 1)
05742 res = ast_play_and_wait(chan, "digits/odno");
05743 else
05744 res = say_and_wait(chan, lastnum, chan->language);
05745 }
05746
05747 if (!res)
05748 res = ast_play_and_wait(chan, (lastnum == 1) ? "vm-staroe" : "vm-staryh");
05749 }
05750
05751 if (!res && !vms->newmessages && !vms->oldmessages) {
05752 lastnum = 0;
05753 res = ast_play_and_wait(chan, "vm-no");
05754 }
05755
05756 if (!res) {
05757 switch (lastnum) {
05758 case 1:
05759 res = ast_play_and_wait(chan, "vm-soobshenie");
05760 break;
05761 case 2:
05762 case 3:
05763 case 4:
05764 res = ast_play_and_wait(chan, "vm-soobsheniya");
05765 break;
05766 default:
05767 res = ast_play_and_wait(chan, "vm-soobsheniy");
05768 break;
05769 }
05770 }
05771
05772 return res;
05773 }
05774
05775
05776
05777
05778
05779
05780
05781
05782
05783 static int vm_intro_ua(struct ast_channel *chan,struct vm_state *vms)
05784 {
05785 int res;
05786 int lastnum = 0;
05787 int dcnum;
05788
05789 res = ast_play_and_wait(chan, "vm-youhave");
05790 if (!res && vms->newmessages) {
05791 lastnum = get_lastdigits(vms->newmessages);
05792 dcnum = vms->newmessages - lastnum;
05793 if (dcnum)
05794 res = say_and_wait(chan, dcnum, chan->language);
05795 if (!res && lastnum) {
05796 if (lastnum == 1)
05797 res = ast_play_and_wait(chan, "digits/ua/1e");
05798 else
05799 res = say_and_wait(chan, lastnum, chan->language);
05800 }
05801
05802 if (!res)
05803 res = ast_play_and_wait(chan, (lastnum == 1) ? "vm-nove" : "vm-INBOX");
05804
05805 if (!res && vms->oldmessages)
05806 res = ast_play_and_wait(chan, "vm-and");
05807 }
05808
05809 if (!res && vms->oldmessages) {
05810 lastnum = get_lastdigits(vms->oldmessages);
05811 dcnum = vms->oldmessages - lastnum;
05812 if (dcnum)
05813 res = say_and_wait(chan, dcnum, chan->language);
05814 if (!res && lastnum) {
05815 if (lastnum == 1)
05816 res = ast_play_and_wait(chan, "digits/ua/1e");
05817 else
05818 res = say_and_wait(chan, lastnum, chan->language);
05819 }
05820
05821 if (!res)
05822 res = ast_play_and_wait(chan, (lastnum == 1) ? "vm-stare" : "vm-Old");
05823 }
05824
05825 if (!res && !vms->newmessages && !vms->oldmessages) {
05826 lastnum = 0;
05827 res = ast_play_and_wait(chan, "vm-no");
05828 }
05829
05830 if (!res) {
05831 switch (lastnum) {
05832 case 1:
05833 case 2:
05834 case 3:
05835 case 4:
05836 res = ast_play_and_wait(chan, "vm-message");
05837 break;
05838 default:
05839 res = ast_play_and_wait(chan, "vm-messages");
05840 break;
05841 }
05842 }
05843
05844 return res;
05845 }
05846
05847
05848 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
05849 {
05850 char prefile[256];
05851
05852
05853 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
05854 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
05855 if (ast_fileexists(prefile, NULL, NULL) > 0)
05856 ast_play_and_wait(chan, "vm-tempgreetactive");
05857 }
05858
05859
05860 if (!strncasecmp(chan->language, "de", 2)) {
05861 return vm_intro_de(chan, vms);
05862 } else if (!strncasecmp(chan->language, "es", 2)) {
05863 return vm_intro_es(chan, vms);
05864 } else if (!strncasecmp(chan->language, "it", 2)) {
05865 return vm_intro_it(chan, vms);
05866 } else if (!strncasecmp(chan->language, "fr", 2)) {
05867 return vm_intro_fr(chan, vms);
05868 } else if (!strncasecmp(chan->language, "nl", 2)) {
05869 return vm_intro_nl(chan, vms);
05870 } else if (!strcasecmp(chan->language, "pt_BR")) {
05871 return vm_intro_pt_BR(chan, vms);
05872 } else if (!strncasecmp(chan->language, "pt", 2)) {
05873 return vm_intro_pt(chan, vms);
05874 } else if (!strncasecmp(chan->language, "cz", 2)) {
05875 return vm_intro_cz(chan, vms);
05876 } else if (!strncasecmp(chan->language, "gr", 2)) {
05877 return vm_intro_gr(chan, vms);
05878 } else if (!strncasecmp(chan->language, "pl", 2)) {
05879 return vm_intro_pl(chan, vms);
05880 } else if (!strncasecmp(chan->language, "se", 2)) {
05881 return vm_intro_se(chan, vms);
05882 } else if (!strncasecmp(chan->language, "no", 2)) {
05883 return vm_intro_no(chan, vms);
05884 } else if (!strncasecmp(chan->language, "ru", 2)) {
05885 return vm_intro_ru(chan, vms);
05886 } else if (!strncasecmp(chan->language, "ua", 2)) {
05887 return vm_intro_ua(chan, vms);
05888 } else {
05889 return vm_intro_en(chan, vms);
05890 }
05891 }
05892
05893 static int vm_instructions(struct ast_channel *chan, struct vm_state *vms, int skipadvanced)
05894 {
05895 int res = 0;
05896
05897 while (!res) {
05898 if (vms->starting) {
05899 if (vms->lastmsg > -1) {
05900 res = ast_play_and_wait(chan, "vm-onefor");
05901 if (!res)
05902 res = vm_play_folder_name(chan, vms->vmbox);
05903 }
05904 if (!res)
05905 res = ast_play_and_wait(chan, "vm-opts");
05906 } else {
05907 if (vms->curmsg)
05908 res = ast_play_and_wait(chan, "vm-prev");
05909 if (!res && !skipadvanced)
05910 res = ast_play_and_wait(chan, "vm-advopts");
05911 if (!res)
05912 res = ast_play_and_wait(chan, "vm-repeat");
05913 if (!res && (vms->curmsg != vms->lastmsg))
05914 res = ast_play_and_wait(chan, "vm-next");
05915 if (!res) {
05916 if (!vms->deleted[vms->curmsg])
05917 res = ast_play_and_wait(chan, "vm-delete");
05918 else
05919 res = ast_play_and_wait(chan, "vm-undelete");
05920 if (!res)
05921 res = ast_play_and_wait(chan, "vm-toforward");
05922 if (!res)
05923 res = ast_play_and_wait(chan, "vm-savemessage");
05924 }
05925 }
05926 if (!res)
05927 res = ast_play_and_wait(chan, "vm-helpexit");
05928 if (!res)
05929 res = ast_waitfordigit(chan, 6000);
05930 if (!res) {
05931 vms->repeats++;
05932 if (vms->repeats > 2) {
05933 res = 't';
05934 }
05935 }
05936 }
05937 return res;
05938 }
05939
05940 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
05941 {
05942 int cmd = 0;
05943 int duration = 0;
05944 int tries = 0;
05945 char newpassword[80] = "";
05946 char newpassword2[80] = "";
05947 char prefile[PATH_MAX] = "";
05948 unsigned char buf[256];
05949 int bytes=0;
05950
05951 if (ast_adsi_available(chan)) {
05952 bytes += adsi_logo(buf + bytes);
05953 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
05954 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
05955 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05956 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05957 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05958 }
05959
05960
05961
05962 for (;;) {
05963 newpassword[1] = '\0';
05964 newpassword[0] = cmd = ast_play_and_wait(chan,"vm-newpassword");
05965 if (cmd == '#')
05966 newpassword[0] = '\0';
05967 if (cmd < 0 || cmd == 't' || cmd == '#')
05968 return cmd;
05969 cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#");
05970 if (cmd < 0 || cmd == 't' || cmd == '#')
05971 return cmd;
05972 newpassword2[1] = '\0';
05973 newpassword2[0] = cmd = ast_play_and_wait(chan,"vm-reenterpassword");
05974 if (cmd == '#')
05975 newpassword2[0] = '\0';
05976 if (cmd < 0 || cmd == 't' || cmd == '#')
05977 return cmd;
05978 cmd = ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#");
05979 if (cmd < 0 || cmd == 't' || cmd == '#')
05980 return cmd;
05981 if (!strcmp(newpassword, newpassword2))
05982 break;
05983 ast_log(LOG_NOTICE,"Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
05984 cmd = ast_play_and_wait(chan, "vm-mismatch");
05985 if (++tries == 3)
05986 return -1;
05987 }
05988 if (ast_strlen_zero(ext_pass_cmd))
05989 vm_change_password(vmu,newpassword);
05990 else
05991 vm_change_password_shell(vmu,newpassword);
05992 if (option_debug > 2)
05993 ast_log(LOG_DEBUG,"User %s set password to %s of length %d\n",vms->username,newpassword,(int)strlen(newpassword));
05994 cmd = ast_play_and_wait(chan,"vm-passchanged");
05995
05996
05997 if (ast_test_flag(vmu, VM_FORCENAME)) {
05998 snprintf(prefile,sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
05999 if (ast_fileexists(prefile, NULL, NULL) < 1) {
06000 #ifndef IMAP_STORAGE
06001 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL);
06002 #else
06003 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
06004 #endif
06005 if (cmd < 0 || cmd == 't' || cmd == '#')
06006 return cmd;
06007 }
06008 }
06009
06010
06011 if (ast_test_flag(vmu, VM_FORCEGREET)) {
06012 snprintf(prefile,sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
06013 if (ast_fileexists(prefile, NULL, NULL) < 1) {
06014 #ifndef IMAP_STORAGE
06015 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL);
06016 #else
06017 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
06018 #endif
06019 if (cmd < 0 || cmd == 't' || cmd == '#')
06020 return cmd;
06021 }
06022
06023 snprintf(prefile,sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
06024 if (ast_fileexists(prefile, NULL, NULL) < 1) {
06025 #ifndef IMAP_STORAGE
06026 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL);
06027 #else
06028 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
06029 #endif
06030 if (cmd < 0 || cmd == 't' || cmd == '#')
06031 return cmd;
06032 }
06033 }
06034
06035 return cmd;
06036 }
06037
06038 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
06039 {
06040 int cmd = 0;
06041 int retries = 0;
06042 int duration = 0;
06043 char newpassword[80] = "";
06044 char newpassword2[80] = "";
06045 char prefile[PATH_MAX] = "";
06046 unsigned char buf[256];
06047 int bytes=0;
06048
06049 if (ast_adsi_available(chan))
06050 {
06051 bytes += adsi_logo(buf + bytes);
06052 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
06053 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
06054 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06055 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06056 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06057 }
06058 while ((cmd >= 0) && (cmd != 't')) {
06059 if (cmd)
06060 retries = 0;
06061 switch (cmd) {
06062 case '1':
06063 snprintf(prefile,sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
06064 #ifndef IMAP_STORAGE
06065 cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL);
06066 #else
06067 cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
06068 #endif
06069 break;
06070 case '2':
06071 snprintf(prefile,sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
06072 #ifndef IMAP_STORAGE
06073 cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL);
06074 #else
06075 cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
06076 #endif
06077 break;
06078 case '3':
06079 snprintf(prefile,sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
06080 #ifndef IMAP_STORAGE
06081 cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL);
06082 #else
06083 cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
06084 #endif
06085 break;
06086 case '4':
06087 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
06088 break;
06089 case '5':
06090 if (vmu->password[0] == '-') {
06091 cmd = ast_play_and_wait(chan, "vm-no");
06092 break;
06093 }
06094 newpassword[1] = '\0';
06095 newpassword[0] = cmd = ast_play_and_wait(chan,"vm-newpassword");
06096 if (cmd == '#')
06097 newpassword[0] = '\0';
06098 else {
06099 if (cmd < 0)
06100 break;
06101 if ((cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#")) < 0) {
06102 break;
06103 }
06104 }
06105 newpassword2[1] = '\0';
06106 newpassword2[0] = cmd = ast_play_and_wait(chan,"vm-reenterpassword");
06107 if (cmd == '#')
06108 newpassword2[0] = '\0';
06109 else {
06110 if (cmd < 0)
06111 break;
06112
06113 if ((cmd = ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#"))) {
06114 break;
06115 }
06116 }
06117 if (strcmp(newpassword, newpassword2)) {
06118 ast_log(LOG_NOTICE,"Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
06119 cmd = ast_play_and_wait(chan, "vm-mismatch");
06120 break;
06121 }
06122 if (ast_strlen_zero(ext_pass_cmd))
06123 vm_change_password(vmu,newpassword);
06124 else
06125 vm_change_password_shell(vmu,newpassword);
06126 if (option_debug > 2)
06127 ast_log(LOG_DEBUG,"User %s set password to %s of length %d\n",vms->username,newpassword,(int)strlen(newpassword));
06128 cmd = ast_play_and_wait(chan,"vm-passchanged");
06129 break;
06130 case '*':
06131 cmd = 't';
06132 break;
06133 default:
06134 cmd = 0;
06135 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
06136 if (ast_fileexists(prefile, NULL, NULL))
06137 cmd = ast_play_and_wait(chan, "vm-tmpexists");
06138 if (!cmd)
06139 cmd = ast_play_and_wait(chan, "vm-options");
06140 if (!cmd)
06141 cmd = ast_waitfordigit(chan,6000);
06142 if (!cmd)
06143 retries++;
06144 if (retries > 3)
06145 cmd = 't';
06146 }
06147 }
06148 if (cmd == 't')
06149 cmd = 0;
06150 return cmd;
06151 }
06152
06153 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
06154 {
06155 int res;
06156 int cmd = 0;
06157 int retries = 0;
06158 int duration = 0;
06159 char prefile[PATH_MAX] = "";
06160 unsigned char buf[256];
06161 char dest[PATH_MAX];
06162 int bytes = 0;
06163
06164 if (ast_adsi_available(chan)) {
06165 bytes += adsi_logo(buf + bytes);
06166 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
06167 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
06168 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06169 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06170 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06171 }
06172
06173 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
06174 if ((res = create_dirpath(dest, sizeof(dest), vmu->context, vms->username, "temp"))) {
06175 ast_log(LOG_WARNING, "Failed to create directory (%s).\n", prefile);
06176 return -1;
06177 }
06178 while ((cmd >= 0) && (cmd != 't')) {
06179 if (cmd)
06180 retries = 0;
06181 RETRIEVE(prefile, -1);
06182 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
06183 #ifndef IMAP_STORAGE
06184 play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL);
06185 #else
06186 play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
06187 #endif
06188 cmd = 't';
06189 } else {
06190 switch (cmd) {
06191 case '1':
06192 #ifndef IMAP_STORAGE
06193 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL);
06194 #else
06195 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
06196 #endif
06197 break;
06198 case '2':
06199 DELETE(prefile, -1, prefile);
06200 ast_play_and_wait(chan, "vm-tempremoved");
06201 cmd = 't';
06202 break;
06203 case '*':
06204 cmd = 't';
06205 break;
06206 default:
06207 cmd = ast_play_and_wait(chan,
06208 ast_fileexists(prefile, NULL, NULL) > 0 ?
06209 "vm-tempgreeting2" : "vm-tempgreeting");
06210 if (!cmd)
06211 cmd = ast_waitfordigit(chan,6000);
06212 if (!cmd)
06213 retries++;
06214 if (retries > 3)
06215 cmd = 't';
06216 }
06217 }
06218 DISPOSE(prefile, -1);
06219 }
06220 if (cmd == 't')
06221 cmd = 0;
06222 return cmd;
06223 }
06224
06225
06226 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
06227 {
06228 int cmd=0;
06229
06230 if (vms->lastmsg > -1) {
06231 cmd = play_message(chan, vmu, vms);
06232 } else {
06233 cmd = ast_play_and_wait(chan, "vm-youhave");
06234 if (!cmd)
06235 cmd = ast_play_and_wait(chan, "vm-no");
06236 if (!cmd) {
06237 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
06238 cmd = ast_play_and_wait(chan, vms->fn);
06239 }
06240 if (!cmd)
06241 cmd = ast_play_and_wait(chan, "vm-messages");
06242 }
06243 return cmd;
06244 }
06245
06246
06247 static int vm_browse_messages_latin(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
06248 {
06249 int cmd=0;
06250
06251 if (vms->lastmsg > -1) {
06252 cmd = play_message(chan, vmu, vms);
06253 } else {
06254 cmd = ast_play_and_wait(chan, "vm-youhaveno");
06255 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
06256 if (!cmd) {
06257 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
06258 cmd = ast_play_and_wait(chan, vms->fn);
06259 }
06260 if (!cmd)
06261 cmd = ast_play_and_wait(chan, "vm-messages");
06262 } else {
06263 if (!cmd)
06264 cmd = ast_play_and_wait(chan, "vm-messages");
06265 if (!cmd) {
06266 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
06267 cmd = ast_play_and_wait(chan, vms->fn);
06268 }
06269 }
06270 }
06271 return cmd;
06272 }
06273
06274 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
06275 {
06276 if (!strncasecmp(chan->language, "es", 2) ||
06277 !strncasecmp(chan->language, "it", 2) ||
06278 !strncasecmp(chan->language, "pt", 2) ||
06279 !strncasecmp(chan->language, "gr", 2)) {
06280 return vm_browse_messages_latin(chan, vms, vmu);
06281 } else {
06282 return vm_browse_messages_en(chan, vms, vmu);
06283 }
06284 }
06285
06286 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
06287 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
06288 int skipuser, int maxlogins, int silent)
06289 {
06290 int useadsi=0, valid=0, logretries=0;
06291 char password[AST_MAX_EXTENSION]="", *passptr;
06292 struct ast_vm_user vmus, *vmu = NULL;
06293
06294
06295 adsi_begin(chan, &useadsi);
06296 if (!skipuser && useadsi)
06297 adsi_login(chan);
06298 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
06299 ast_log(LOG_WARNING, "Couldn't stream login file\n");
06300 return -1;
06301 }
06302
06303
06304
06305 while (!valid && (logretries < maxlogins)) {
06306
06307 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
06308 ast_log(LOG_WARNING, "Couldn't read username\n");
06309 return -1;
06310 }
06311 if (ast_strlen_zero(mailbox)) {
06312 if (chan->cid.cid_num) {
06313 ast_copy_string(mailbox, chan->cid.cid_num, mailbox_size);
06314 } else {
06315 if (option_verbose > 2)
06316 ast_verbose(VERBOSE_PREFIX_3 "Username not entered\n");
06317 return -1;
06318 }
06319 }
06320 if (useadsi)
06321 adsi_password(chan);
06322
06323 if (!ast_strlen_zero(prefix)) {
06324 char fullusername[80] = "";
06325 ast_copy_string(fullusername, prefix, sizeof(fullusername));
06326 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
06327 ast_copy_string(mailbox, fullusername, mailbox_size);
06328 }
06329
06330 if (option_debug)
06331 ast_log(LOG_DEBUG, "Before find user for mailbox %s\n",mailbox);
06332 vmu = find_user(&vmus, context, mailbox);
06333 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
06334
06335 password[0] = '\0';
06336 } else {
06337 if (ast_streamfile(chan, "vm-password", chan->language)) {
06338 ast_log(LOG_WARNING, "Unable to stream password file\n");
06339 return -1;
06340 }
06341 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
06342 ast_log(LOG_WARNING, "Unable to read password\n");
06343 return -1;
06344 }
06345 }
06346
06347 if (vmu) {
06348 passptr = vmu->password;
06349 if (passptr[0] == '-') passptr++;
06350 }
06351 if (vmu && !strcmp(passptr, password))
06352 valid++;
06353 else {
06354 if (option_verbose > 2)
06355 ast_verbose( VERBOSE_PREFIX_3 "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
06356 if (!ast_strlen_zero(prefix))
06357 mailbox[0] = '\0';
06358 }
06359 logretries++;
06360 if (!valid) {
06361 if (skipuser || logretries >= maxlogins) {
06362 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
06363 ast_log(LOG_WARNING, "Unable to stream incorrect message\n");
06364 return -1;
06365 }
06366 } else {
06367 if (useadsi)
06368 adsi_login(chan);
06369 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
06370 ast_log(LOG_WARNING, "Unable to stream incorrect mailbox message\n");
06371 return -1;
06372 }
06373 }
06374 if (ast_waitstream(chan, ""))
06375 return -1;
06376 }
06377 }
06378 if (!valid && (logretries >= maxlogins)) {
06379 ast_stopstream(chan);
06380 ast_play_and_wait(chan, "vm-goodbye");
06381 return -1;
06382 }
06383 if (vmu && !skipuser) {
06384 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
06385 }
06386 return 0;
06387 }
06388
06389 static int vm_execmain(struct ast_channel *chan, void *data)
06390 {
06391
06392
06393
06394 int res=-1;
06395 int cmd=0;
06396 int valid = 0;
06397 struct ast_module_user *u;
06398 char prefixstr[80] ="";
06399 char ext_context[256]="";
06400 int box;
06401 int useadsi = 0;
06402 int skipuser = 0;
06403 struct vm_state vms;
06404 struct ast_vm_user *vmu = NULL, vmus;
06405 char *context=NULL;
06406 int silentexit = 0;
06407 struct ast_flags flags = { 0 };
06408 signed char record_gain = 0;
06409 int play_auto = 0;
06410 int play_folder = 0;
06411 #ifdef IMAP_STORAGE
06412 int deleted = 0;
06413 #endif
06414 u = ast_module_user_add(chan);
06415
06416
06417 memset(&vms, 0, sizeof(vms));
06418 vms.lastmsg = -1;
06419
06420 memset(&vmus, 0, sizeof(vmus));
06421
06422 if (chan->_state != AST_STATE_UP) {
06423 if (option_debug)
06424 ast_log(LOG_DEBUG, "Before ast_answer\n");
06425 ast_answer(chan);
06426 }
06427
06428 if (!ast_strlen_zero(data)) {
06429 char *opts[OPT_ARG_ARRAY_SIZE];
06430 char *parse;
06431 AST_DECLARE_APP_ARGS(args,
06432 AST_APP_ARG(argv0);
06433 AST_APP_ARG(argv1);
06434 );
06435
06436 parse = ast_strdupa(data);
06437
06438 AST_STANDARD_APP_ARGS(args, parse);
06439
06440 if (args.argc == 2) {
06441 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1)) {
06442 ast_module_user_remove(u);
06443 return -1;
06444 }
06445 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
06446 int gain;
06447 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
06448 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%d", &gain) != 1) {
06449 ast_log(LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
06450 ast_module_user_remove(u);
06451 return -1;
06452 } else {
06453 record_gain = (signed char) gain;
06454 }
06455 } else {
06456 ast_log(LOG_WARNING, "Invalid Gain level set with option g\n");
06457 }
06458 }
06459 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
06460 play_auto = 1;
06461 if (opts[OPT_ARG_PLAYFOLDER]) {
06462 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%d", &play_folder) != 1) {
06463 ast_log(LOG_WARNING, "Invalid value '%s' provided for folder autoplay option\n", opts[OPT_ARG_PLAYFOLDER]);
06464 }
06465 } else {
06466 ast_log(LOG_WARNING, "Invalid folder set with option a\n");
06467 }
06468 if ( play_folder > 9 || play_folder < 0) {
06469 ast_log(LOG_WARNING, "Invalid value '%d' provided for folder autoplay option\n", play_folder);
06470 play_folder = 0;
06471 }
06472 }
06473 } else {
06474
06475 while (*(args.argv0)) {
06476 if (*(args.argv0) == 's')
06477 ast_set_flag(&flags, OPT_SILENT);
06478 else if (*(args.argv0) == 'p')
06479 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
06480 else
06481 break;
06482 (args.argv0)++;
06483 }
06484
06485 }
06486
06487 valid = ast_test_flag(&flags, OPT_SILENT);
06488
06489 if ((context = strchr(args.argv0, '@')))
06490 *context++ = '\0';
06491
06492 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
06493 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
06494 else
06495 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
06496
06497 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
06498 skipuser++;
06499 else
06500 valid = 0;
06501 }
06502
06503 if (!valid)
06504 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
06505
06506 if (option_debug)
06507 ast_log(LOG_DEBUG, "After vm_authenticate\n");
06508 if (!res) {
06509 valid = 1;
06510 if (!skipuser)
06511 vmu = &vmus;
06512 } else {
06513 res = 0;
06514 }
06515
06516
06517 adsi_begin(chan, &useadsi);
06518
06519 #ifdef IMAP_STORAGE
06520 vms.interactive = 1;
06521 vms.updated = 1;
06522 vmstate_insert(&vms);
06523 init_vm_state(&vms);
06524 #endif
06525 if (!valid)
06526 goto out;
06527
06528 if (!(vms.deleted = ast_calloc(vmu->maxmsg, sizeof(int)))) {
06529
06530 }
06531 if (!(vms.heard = ast_calloc(vmu->maxmsg, sizeof(int)))) {
06532
06533 }
06534
06535
06536 if (!ast_strlen_zero(vmu->language))
06537 ast_string_field_set(chan, language, vmu->language);
06538 create_dirpath(vms.curdir, sizeof(vms.curdir), vmu->context, vms.username, "");
06539
06540 if (option_debug)
06541 ast_log(LOG_DEBUG, "Before open_mailbox\n");
06542 res = open_mailbox(&vms, vmu, 1);
06543 if (res == ERROR_LOCK_PATH)
06544 goto out;
06545 vms.oldmessages = vms.lastmsg + 1;
06546 if (option_debug > 2)
06547 ast_log(LOG_DEBUG, "Number of old messages: %d\n",vms.oldmessages);
06548
06549 res = open_mailbox(&vms, vmu, 0);
06550 if (res == ERROR_LOCK_PATH)
06551 goto out;
06552 vms.newmessages = vms.lastmsg + 1;
06553 if (option_debug > 2)
06554 ast_log(LOG_DEBUG, "Number of new messages: %d\n",vms.newmessages);
06555
06556
06557 if (play_auto) {
06558 res = open_mailbox(&vms, vmu, play_folder);
06559 if (res == ERROR_LOCK_PATH)
06560 goto out;
06561
06562
06563 if (vms.lastmsg == -1) {
06564 cmd = vm_browse_messages(chan, &vms, vmu);
06565 res = 0;
06566 goto out;
06567 }
06568 } else {
06569 if (!vms.newmessages && vms.oldmessages) {
06570
06571 res = open_mailbox(&vms, vmu, 1);
06572 play_folder = 1;
06573 if (res == ERROR_LOCK_PATH)
06574 goto out;
06575 }
06576 }
06577
06578 if (useadsi)
06579 adsi_status(chan, &vms);
06580 res = 0;
06581
06582
06583 if (!strcasecmp(vmu->mailbox, vmu->password) &&
06584 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
06585 if (ast_play_and_wait(chan, "vm-newuser") == -1)
06586 ast_log(LOG_WARNING, "Couldn't stream new user file\n");
06587 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
06588 if ((cmd == 't') || (cmd == '#')) {
06589
06590 res = 0;
06591 goto out;
06592 } else if (cmd < 0) {
06593
06594 res = -1;
06595 goto out;
06596 }
06597 }
06598 #ifdef IMAP_STORAGE
06599 if (option_debug > 2)
06600 ast_log(LOG_DEBUG, "Checking quotas: comparing %u to %u\n",vms.quota_usage,vms.quota_limit);
06601 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
06602 if (option_debug)
06603 ast_log(LOG_DEBUG, "*** QUOTA EXCEEDED!!\n");
06604 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
06605 }
06606 if (option_debug > 2)
06607 ast_log(LOG_DEBUG, "Checking quotas: User has %d messages and limit is %d.\n",(vms.newmessages + vms.oldmessages),vmu->maxmsg);
06608 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
06609 ast_log(LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n",(vms.newmessages + vms.oldmessages),vmu->maxmsg);
06610 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
06611 }
06612 #endif
06613 if (play_auto) {
06614 cmd = '1';
06615 } else {
06616 cmd = vm_intro(chan, vmu, &vms);
06617 }
06618
06619 vms.repeats = 0;
06620 vms.starting = 1;
06621 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
06622
06623 switch (cmd) {
06624 case '1':
06625 vms.curmsg = 0;
06626
06627 case '5':
06628 cmd = vm_browse_messages(chan, &vms, vmu);
06629 break;
06630 case '2':
06631 if (useadsi)
06632 adsi_folders(chan, 0, "Change to folder...");
06633 cmd = get_folder2(chan, "vm-changeto", 0);
06634 if (cmd == '#') {
06635 cmd = 0;
06636 } else if (cmd > 0) {
06637 cmd = cmd - '0';
06638 res = close_mailbox(&vms, vmu);
06639 if (res == ERROR_LOCK_PATH)
06640 goto out;
06641 res = open_mailbox(&vms, vmu, cmd);
06642 if (res == ERROR_LOCK_PATH)
06643 goto out;
06644 play_folder = cmd;
06645 cmd = 0;
06646 }
06647 if (useadsi)
06648 adsi_status2(chan, &vms);
06649
06650 if (!cmd)
06651 cmd = vm_play_folder_name(chan, vms.vmbox);
06652
06653 vms.starting = 1;
06654 break;
06655 case '3':
06656 cmd = 0;
06657 vms.repeats = 0;
06658 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
06659 switch (cmd) {
06660 case '1':
06661 if (vms.lastmsg > -1 && !vms.starting) {
06662 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
06663 if (cmd == ERROR_LOCK_PATH) {
06664 res = cmd;
06665 goto out;
06666 }
06667 } else
06668 cmd = ast_play_and_wait(chan, "vm-sorry");
06669 cmd = 't';
06670 break;
06671 case '2':
06672 if (option_verbose > 2 && !vms.starting)
06673 ast_verbose( VERBOSE_PREFIX_3 "Callback Requested\n");
06674 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
06675 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
06676 if (cmd == 9) {
06677 silentexit = 1;
06678 goto out;
06679 } else if (cmd == ERROR_LOCK_PATH) {
06680 res = cmd;
06681 goto out;
06682 }
06683 }
06684 else
06685 cmd = ast_play_and_wait(chan, "vm-sorry");
06686 cmd = 't';
06687 break;
06688 case '3':
06689 if (vms.lastmsg > -1 && !vms.starting) {
06690 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
06691 if (cmd == ERROR_LOCK_PATH) {
06692 res = cmd;
06693 goto out;
06694 }
06695 } else
06696 cmd = ast_play_and_wait(chan, "vm-sorry");
06697 cmd = 't';
06698 break;
06699 case '4':
06700 if (!ast_strlen_zero(vmu->dialout)) {
06701 cmd = dialout(chan, vmu, NULL, vmu->dialout);
06702 if (cmd == 9) {
06703 silentexit = 1;
06704 goto out;
06705 }
06706 }
06707 else
06708 cmd = ast_play_and_wait(chan, "vm-sorry");
06709 cmd = 't';
06710 break;
06711
06712 case '5':
06713 if (ast_test_flag(vmu, VM_SVMAIL)) {
06714 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain);
06715 if (cmd == ERROR_LOCK_PATH) {
06716 res = cmd;
06717 ast_log(LOG_WARNING, "forward_message failed to lock path.\n");
06718 goto out;
06719 }
06720 } else
06721 cmd = ast_play_and_wait(chan,"vm-sorry");
06722 cmd='t';
06723 break;
06724
06725 case '*':
06726 cmd = 't';
06727 break;
06728
06729 default:
06730 cmd = 0;
06731 if (!vms.starting) {
06732 cmd = ast_play_and_wait(chan, "vm-toreply");
06733 }
06734 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
06735 cmd = ast_play_and_wait(chan, "vm-tocallback");
06736 }
06737 if (!cmd && !vms.starting) {
06738 cmd = ast_play_and_wait(chan, "vm-tohearenv");
06739 }
06740 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
06741 cmd = ast_play_and_wait(chan, "vm-tomakecall");
06742 }
06743 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd)
06744 cmd=ast_play_and_wait(chan, "vm-leavemsg");
06745 if (!cmd)
06746 cmd = ast_play_and_wait(chan, "vm-starmain");
06747 if (!cmd)
06748 cmd = ast_waitfordigit(chan,6000);
06749 if (!cmd)
06750 vms.repeats++;
06751 if (vms.repeats > 3)
06752 cmd = 't';
06753 }
06754 }
06755 if (cmd == 't') {
06756 cmd = 0;
06757 vms.repeats = 0;
06758 }
06759 break;
06760 case '4':
06761 if (vms.curmsg > 0) {
06762 vms.curmsg--;
06763 cmd = play_message(chan, vmu, &vms);
06764 } else {
06765 cmd = ast_play_and_wait(chan, "vm-nomore");
06766 }
06767 break;
06768 case '6':
06769 if (vms.curmsg < vms.lastmsg) {
06770 vms.curmsg++;
06771 cmd = play_message(chan, vmu, &vms);
06772 } else {
06773 cmd = ast_play_and_wait(chan, "vm-nomore");
06774 }
06775 break;
06776 case '7':
06777 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
06778 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
06779 if (useadsi)
06780 adsi_delete(chan, &vms);
06781 if (vms.deleted[vms.curmsg]) {
06782 if (play_folder == 0)
06783 vms.newmessages--;
06784 else if (play_folder == 1)
06785 vms.oldmessages--;
06786 cmd = ast_play_and_wait(chan, "vm-deleted");
06787 }
06788 else {
06789 if (play_folder == 0)
06790 vms.newmessages++;
06791 else if (play_folder == 1)
06792 vms.oldmessages++;
06793 cmd = ast_play_and_wait(chan, "vm-undeleted");
06794 }
06795 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
06796 if (vms.curmsg < vms.lastmsg) {
06797 vms.curmsg++;
06798 cmd = play_message(chan, vmu, &vms);
06799 } else {
06800 cmd = ast_play_and_wait(chan, "vm-nomore");
06801 }
06802 }
06803 } else
06804 cmd = 0;
06805 #ifdef IMAP_STORAGE
06806 deleted = 1;
06807 #endif
06808 break;
06809
06810 case '8':
06811 if (vms.lastmsg > -1) {
06812 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain);
06813 if (cmd == ERROR_LOCK_PATH) {
06814 res = cmd;
06815 goto out;
06816 }
06817 } else
06818 cmd = ast_play_and_wait(chan, "vm-nomore");
06819 break;
06820 case '9':
06821 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
06822
06823 cmd = 0;
06824 break;
06825 }
06826 if (useadsi)
06827 adsi_folders(chan, 1, "Save to folder...");
06828 cmd = get_folder2(chan, "vm-savefolder", 1);
06829 box = 0;
06830 if (cmd == '#') {
06831 cmd = 0;
06832 break;
06833 } else if (cmd > 0) {
06834 box = cmd = cmd - '0';
06835 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
06836 if (cmd == ERROR_LOCK_PATH) {
06837 res = cmd;
06838 goto out;
06839 #ifdef IMAP_STORAGE
06840 } else if (cmd == 10) {
06841 goto out;
06842 #endif
06843 } else if (!cmd) {
06844 vms.deleted[vms.curmsg] = 1;
06845 } else {
06846 vms.deleted[vms.curmsg] = 0;
06847 vms.heard[vms.curmsg] = 0;
06848 }
06849 }
06850 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
06851 if (useadsi)
06852 adsi_message(chan, &vms);
06853 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(box));
06854 if (!cmd) {
06855 cmd = ast_play_and_wait(chan, "vm-message");
06856 if (!cmd)
06857 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
06858 if (!cmd)
06859 cmd = ast_play_and_wait(chan, "vm-savedto");
06860 if (!cmd)
06861 cmd = vm_play_folder_name(chan, vms.fn);
06862 } else {
06863 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
06864 }
06865 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
06866 if (vms.curmsg < vms.lastmsg) {
06867 vms.curmsg++;
06868 cmd = play_message(chan, vmu, &vms);
06869 } else {
06870 cmd = ast_play_and_wait(chan, "vm-nomore");
06871 }
06872 }
06873 break;
06874 case '*':
06875 if (!vms.starting) {
06876 cmd = ast_play_and_wait(chan, "vm-onefor");
06877 if (!cmd)
06878 cmd = vm_play_folder_name(chan, vms.vmbox);
06879 if (!cmd)
06880 cmd = ast_play_and_wait(chan, "vm-opts");
06881 if (!cmd)
06882 cmd = vm_instructions(chan, &vms, 1);
06883 } else
06884 cmd = 0;
06885 break;
06886 case '0':
06887 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
06888 if (useadsi)
06889 adsi_status(chan, &vms);
06890 break;
06891 default:
06892 cmd = vm_instructions(chan, &vms, 0);
06893 break;
06894 }
06895 }
06896 if ((cmd == 't') || (cmd == '#')) {
06897
06898 res = 0;
06899 } else {
06900
06901 res = -1;
06902 }
06903
06904 out:
06905 if (res > -1) {
06906 ast_stopstream(chan);
06907 adsi_goodbye(chan);
06908 if (valid) {
06909 if (silentexit)
06910 res = ast_play_and_wait(chan, "vm-dialout");
06911 else
06912 res = ast_play_and_wait(chan, "vm-goodbye");
06913 if (res > 0)
06914 res = 0;
06915 }
06916 if (useadsi)
06917 ast_adsi_unload_session(chan);
06918 }
06919 if (vmu)
06920 close_mailbox(&vms, vmu);
06921 if (valid) {
06922 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
06923 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
06924 run_externnotify(vmu->context, vmu->mailbox);
06925 }
06926 #ifdef IMAP_STORAGE
06927
06928 if (option_debug > 2)
06929 ast_log(LOG_DEBUG, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n",deleted,expungeonhangup);
06930 if (vmu && deleted == 1 && expungeonhangup == 1) {
06931 #ifdef HAVE_IMAP_TK2006
06932 if (LEVELUIDPLUS (vms.mailstream)) {
06933 mail_expunge_full(vms.mailstream,NIL,EX_UID);
06934 } else
06935 #endif
06936 mail_expunge(vms.mailstream);
06937 }
06938
06939
06940 vmstate_delete(&vms);
06941 #endif
06942 if (vmu)
06943 free_user(vmu);
06944 if (vms.deleted)
06945 free(vms.deleted);
06946 if (vms.heard)
06947 free(vms.heard);
06948 ast_module_user_remove(u);
06949
06950 return res;
06951 }
06952
06953 static int vm_exec(struct ast_channel *chan, void *data)
06954 {
06955 int res = 0;
06956 struct ast_module_user *u;
06957 char *tmp;
06958 struct leave_vm_options leave_options;
06959 struct ast_flags flags = { 0 };
06960 static int deprecate_warning = 0;
06961 char *opts[OPT_ARG_ARRAY_SIZE];
06962 AST_DECLARE_APP_ARGS(args,
06963 AST_APP_ARG(argv0);
06964 AST_APP_ARG(argv1);
06965 );
06966
06967 u = ast_module_user_add(chan);
06968
06969 memset(&leave_options, 0, sizeof(leave_options));
06970
06971 if (chan->_state != AST_STATE_UP)
06972 ast_answer(chan);
06973
06974 if (!ast_strlen_zero(data)) {
06975 tmp = ast_strdupa(data);
06976 AST_STANDARD_APP_ARGS(args, tmp);
06977 if (args.argc == 2) {
06978 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1)) {
06979 ast_module_user_remove(u);
06980 return -1;
06981 }
06982 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_PRIORITY_JUMP);
06983 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
06984 int gain;
06985
06986 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%d", &gain) != 1) {
06987 ast_log(LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
06988 ast_module_user_remove(u);
06989 return -1;
06990 } else {
06991 leave_options.record_gain = (signed char) gain;
06992 }
06993 }
06994 } else {
06995
06996 int old = 0;
06997 char *orig_argv0 = args.argv0;
06998 while (*(args.argv0)) {
06999 if (*(args.argv0) == 's') {
07000 old = 1;
07001 ast_set_flag(&leave_options, OPT_SILENT);
07002 } else if (*(args.argv0) == 'b') {
07003 old = 1;
07004 ast_set_flag(&leave_options, OPT_BUSY_GREETING);
07005 } else if (*(args.argv0) == 'u') {
07006 old = 1;
07007 ast_set_flag(&leave_options, OPT_UNAVAIL_GREETING);
07008 } else if (*(args.argv0) == 'j') {
07009 old = 1;
07010 ast_set_flag(&leave_options, OPT_PRIORITY_JUMP);
07011 } else
07012 break;
07013 (args.argv0)++;
07014 }
07015 if (!deprecate_warning && old) {
07016 deprecate_warning = 1;
07017 ast_log(LOG_WARNING, "Prefixing the mailbox with an option is deprecated ('%s').\n", orig_argv0);
07018 ast_log(LOG_WARNING, "Please move all leading options to the second argument.\n");
07019 }
07020 }
07021 } else {
07022 char tmp[256];
07023 res = ast_app_getdata(chan, "vm-whichbox", tmp, sizeof(tmp) - 1, 0);
07024 if (res < 0) {
07025 ast_module_user_remove(u);
07026 return res;
07027 }
07028 if (ast_strlen_zero(tmp)) {
07029 ast_module_user_remove(u);
07030 return 0;
07031 }
07032 args.argv0 = ast_strdupa(tmp);
07033 }
07034
07035 res = leave_voicemail(chan, args.argv0, &leave_options);
07036
07037 if (res == ERROR_LOCK_PATH) {
07038 ast_log(LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
07039
07040 if (ast_test_flag(&leave_options, OPT_PRIORITY_JUMP) || ast_opt_priority_jumping)
07041 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101))
07042 ast_log(LOG_WARNING, "Extension %s, priority %d doesn't exist.\n", chan->exten, chan->priority + 101);
07043 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
07044 res = 0;
07045 }
07046
07047 ast_module_user_remove(u);
07048
07049 return res;
07050 }
07051
07052 static struct ast_vm_user *find_or_create(char *context, char *mbox)
07053 {
07054 struct ast_vm_user *vmu;
07055 AST_LIST_TRAVERSE(&users, vmu, list) {
07056 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mbox, vmu->mailbox))
07057 break;
07058 if (context && (!strcasecmp(context, vmu->context)) && (!strcasecmp(mbox, vmu->mailbox)))
07059 break;
07060 }
07061
07062 if (!vmu) {
07063 if ((vmu = ast_calloc(1, sizeof(*vmu)))) {
07064 ast_copy_string(vmu->context, context, sizeof(vmu->context));
07065 ast_copy_string(vmu->mailbox, mbox, sizeof(vmu->mailbox));
07066 AST_LIST_INSERT_TAIL(&users, vmu, list);
07067 }
07068 }
07069 return vmu;
07070 }
07071
07072 static int append_mailbox(char *context, char *mbox, char *data)
07073 {
07074
07075 char *tmp;
07076 char *stringp;
07077 char *s;
07078 struct ast_vm_user *vmu;
07079
07080 tmp = ast_strdupa(data);
07081
07082 if ((vmu = find_or_create(context, mbox))) {
07083 populate_defaults(vmu);
07084
07085 stringp = tmp;
07086 if ((s = strsep(&stringp, ",")))
07087 ast_copy_string(vmu->password, s, sizeof(vmu->password));
07088 if (stringp && (s = strsep(&stringp, ",")))
07089 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
07090 if (stringp && (s = strsep(&stringp, ",")))
07091 ast_copy_string(vmu->email, s, sizeof(vmu->email));
07092 if (stringp && (s = strsep(&stringp, ",")))
07093 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
07094 if (stringp && (s = strsep(&stringp, ",")))
07095 apply_options(vmu, s);
07096 }
07097 return 0;
07098 }
07099
07100 static int vm_box_exists(struct ast_channel *chan, void *data)
07101 {
07102 struct ast_module_user *u;
07103 struct ast_vm_user svm;
07104 char *context, *box;
07105 int priority_jump = 0;
07106 AST_DECLARE_APP_ARGS(args,
07107 AST_APP_ARG(mbox);
07108 AST_APP_ARG(options);
07109 );
07110
07111 if (ast_strlen_zero(data)) {
07112 ast_log(LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
07113 return -1;
07114 }
07115
07116 u = ast_module_user_add(chan);
07117
07118 box = ast_strdupa(data);
07119
07120 AST_STANDARD_APP_ARGS(args, box);
07121
07122 if (args.options) {
07123 if (strchr(args.options, 'j'))
07124 priority_jump = 1;
07125 }
07126
07127 if ((context = strchr(args.mbox, '@'))) {
07128 *context = '\0';
07129 context++;
07130 }
07131
07132 if (find_user(&svm, context, args.mbox)) {
07133 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
07134 if (priority_jump || ast_opt_priority_jumping)
07135 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101))
07136 ast_log(LOG_WARNING, "VM box %s@%s exists, but extension %s, priority %d doesn't exist\n", box, context, chan->exten, chan->priority + 101);
07137 } else
07138 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
07139 ast_module_user_remove(u);
07140 return 0;
07141 }
07142
07143 static int vmauthenticate(struct ast_channel *chan, void *data)
07144 {
07145 struct ast_module_user *u;
07146 char *s = data, *user=NULL, *context=NULL, mailbox[AST_MAX_EXTENSION] = "";
07147 struct ast_vm_user vmus;
07148 char *options = NULL;
07149 int silent = 0, skipuser = 0;
07150 int res = -1;
07151
07152 u = ast_module_user_add(chan);
07153
07154 if (s) {
07155 s = ast_strdupa(s);
07156 user = strsep(&s, "|");
07157 options = strsep(&s, "|");
07158 if (user) {
07159 s = user;
07160 user = strsep(&s, "@");
07161 context = strsep(&s, "");
07162 if (!ast_strlen_zero(user))
07163 skipuser++;
07164 ast_copy_string(mailbox, user, sizeof(mailbox));
07165 }
07166 }
07167
07168 if (options) {
07169 silent = (strchr(options, 's')) != NULL;
07170 }
07171
07172 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
07173 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
07174 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
07175 ast_play_and_wait(chan, "auth-thankyou");
07176 res = 0;
07177 }
07178
07179 ast_module_user_remove(u);
07180 return res;
07181 }
07182
07183 static char voicemail_show_users_help[] =
07184 "Usage: voicemail show users [for <context>]\n"
07185 " Lists all mailboxes currently set up\n";
07186
07187 static char voicemail_show_zones_help[] =
07188 "Usage: voicemail show zones\n"
07189 " Lists zone message formats\n";
07190
07191 static int handle_voicemail_show_users(int fd, int argc, char *argv[])
07192 {
07193 struct ast_vm_user *vmu;
07194 char *output_format = "%-10s %-5s %-25s %-10s %6s\n";
07195
07196 if ((argc < 3) || (argc > 5) || (argc == 4)) return RESULT_SHOWUSAGE;
07197 else if ((argc == 5) && strcmp(argv[3],"for")) return RESULT_SHOWUSAGE;
07198
07199 AST_LIST_LOCK(&users);
07200 if (!AST_LIST_EMPTY(&users)) {
07201 if (argc == 3)
07202 ast_cli(fd, output_format, "Context", "Mbox", "User", "Zone", "NewMsg");
07203 else {
07204 int count = 0;
07205 AST_LIST_TRAVERSE(&users, vmu, list) {
07206 if (!strcmp(argv[4],vmu->context))
07207 count++;
07208 }
07209 if (count) {
07210 ast_cli(fd, output_format, "Context", "Mbox", "User", "Zone", "NewMsg");
07211 } else {
07212 ast_cli(fd, "No such voicemail context \"%s\"\n", argv[4]);
07213 AST_LIST_UNLOCK(&users);
07214 return RESULT_FAILURE;
07215 }
07216 }
07217 AST_LIST_TRAVERSE(&users, vmu, list) {
07218 int newmsgs = 0, oldmsgs = 0;
07219 char count[12], tmp[256] = "";
07220
07221 if ((argc == 3) || ((argc == 5) && !strcmp(argv[4],vmu->context))) {
07222 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
07223 inboxcount(tmp, &newmsgs, &oldmsgs);
07224 snprintf(count,sizeof(count),"%d",newmsgs);
07225 ast_cli(fd, output_format, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
07226 }
07227 }
07228 } else {
07229 ast_cli(fd, "There are no voicemail users currently defined\n");
07230 AST_LIST_UNLOCK(&users);
07231 return RESULT_FAILURE;
07232 }
07233 AST_LIST_UNLOCK(&users);
07234 return RESULT_SUCCESS;
07235 }
07236
07237 static int handle_voicemail_show_zones(int fd, int argc, char *argv[])
07238 {
07239 struct vm_zone *zone;
07240 char *output_format = "%-15s %-20s %-45s\n";
07241 int res = RESULT_SUCCESS;
07242
07243 if (argc != 3)
07244 return RESULT_SHOWUSAGE;
07245
07246 AST_LIST_LOCK(&zones);
07247 if (!AST_LIST_EMPTY(&zones)) {
07248 ast_cli(fd, output_format, "Zone", "Timezone", "Message Format");
07249 AST_LIST_TRAVERSE(&zones, zone, list) {
07250 ast_cli(fd, output_format, zone->name, zone->timezone, zone->msg_format);
07251 }
07252 } else {
07253 ast_cli(fd, "There are no voicemail zones currently defined\n");
07254 res = RESULT_FAILURE;
07255 }
07256 AST_LIST_UNLOCK(&zones);
07257
07258 return res;
07259 }
07260
07261 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
07262 {
07263 int which = 0;
07264 int wordlen;
07265 struct ast_vm_user *vmu;
07266 const char *context = "";
07267
07268
07269 if (pos > 4)
07270 return NULL;
07271 if (pos == 3)
07272 return (state == 0) ? ast_strdup("for") : NULL;
07273 wordlen = strlen(word);
07274 AST_LIST_TRAVERSE(&users, vmu, list) {
07275 if (!strncasecmp(word, vmu->context, wordlen)) {
07276 if (context && strcmp(context, vmu->context) && ++which > state)
07277 return ast_strdup(vmu->context);
07278
07279 context = vmu->context;
07280 }
07281 }
07282 return NULL;
07283 }
07284
07285 static struct ast_cli_entry cli_show_voicemail_users_deprecated = {
07286 { "show", "voicemail", "users", NULL },
07287 handle_voicemail_show_users, NULL,
07288 NULL, complete_voicemail_show_users };
07289
07290 static struct ast_cli_entry cli_show_voicemail_zones_deprecated = {
07291 { "show", "voicemail", "zones", NULL },
07292 handle_voicemail_show_zones, NULL,
07293 NULL, NULL };
07294
07295 static struct ast_cli_entry cli_voicemail[] = {
07296 { { "voicemail", "show", "users", NULL },
07297 handle_voicemail_show_users, "List defined voicemail boxes",
07298 voicemail_show_users_help, complete_voicemail_show_users, &cli_show_voicemail_users_deprecated },
07299
07300 { { "voicemail", "show", "zones", NULL },
07301 handle_voicemail_show_zones, "List zone message formats",
07302 voicemail_show_zones_help, NULL, &cli_show_voicemail_zones_deprecated },
07303 };
07304
07305 static int load_config(void)
07306 {
07307 struct ast_vm_user *cur;
07308 struct vm_zone *zcur;
07309 struct ast_config *cfg, *ucfg;
07310 char *cat;
07311 struct ast_variable *var;
07312 const char *notifystr = NULL;
07313 const char *smdistr = NULL;
07314 const char *astattach;
07315 const char *astsearch;
07316 const char *astsaycid;
07317 const char *send_voicemail;
07318 #ifdef IMAP_STORAGE
07319 const char *imap_server;
07320 const char *imap_port;
07321 const char *imap_flags;
07322 const char *imap_folder;
07323 const char *auth_user;
07324 const char *auth_password;
07325 const char *expunge_on_hangup;
07326 #endif
07327 const char *astcallop;
07328 const char *astreview;
07329 const char *asttempgreetwarn;
07330 const char *astskipcmd;
07331 const char *asthearenv;
07332 const char *astsaydurationinfo;
07333 const char *astsaydurationminfo;
07334 const char *silencestr;
07335 const char *maxmsgstr;
07336 const char *astdirfwd;
07337 const char *thresholdstr;
07338 const char *fmt;
07339 const char *astemail;
07340 const char *ucontext;
07341 const char *astmailcmd = SENDMAIL;
07342 const char *astforcename;
07343 const char *astforcegreet;
07344 const char *s;
07345 char *q,*stringp;
07346 const char *dialoutcxt = NULL;
07347 const char *callbackcxt = NULL;
07348 const char *exitcxt = NULL;
07349 const char *extpc;
07350 const char *emaildateformatstr;
07351 const char *volgainstr;
07352 int x;
07353 int tmpadsi[4];
07354
07355 cfg = ast_config_load(VOICEMAIL_CONFIG);
07356
07357 AST_LIST_LOCK(&users);
07358 while ((cur = AST_LIST_REMOVE_HEAD(&users, list))) {
07359 ast_set_flag(cur, VM_ALLOCED);
07360 free_user(cur);
07361 }
07362
07363 AST_LIST_LOCK(&zones);
07364 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
07365 free_zone(zcur);
07366 AST_LIST_UNLOCK(&zones);
07367
07368 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
07369
07370 if (cfg) {
07371
07372
07373 if (!(ucontext = ast_variable_retrieve(cfg, "general", "userscontext")))
07374 ucontext = "default";
07375 ast_copy_string(userscontext, ucontext, sizeof(userscontext));
07376
07377 if (!(astattach = ast_variable_retrieve(cfg, "general", "attach")))
07378 astattach = "yes";
07379 ast_set2_flag((&globalflags), ast_true(astattach), VM_ATTACH);
07380
07381 if (!(astsearch = ast_variable_retrieve(cfg, "general", "searchcontexts")))
07382 astsearch = "no";
07383 ast_set2_flag((&globalflags), ast_true(astsearch), VM_SEARCH);
07384
07385 volgain = 0.0;
07386 if ((volgainstr = ast_variable_retrieve(cfg, "general", "volgain")))
07387 sscanf(volgainstr, "%lf", &volgain);
07388
07389 #ifdef ODBC_STORAGE
07390 strcpy(odbc_database, "asterisk");
07391 if ((thresholdstr = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
07392 ast_copy_string(odbc_database, thresholdstr, sizeof(odbc_database));
07393 }
07394 strcpy(odbc_table, "voicemessages");
07395 if ((thresholdstr = ast_variable_retrieve(cfg, "general", "odbctable"))) {
07396 ast_copy_string(odbc_table, thresholdstr, sizeof(odbc_table));
07397 }
07398 #endif
07399
07400 strcpy(mailcmd, SENDMAIL);
07401 if ((astmailcmd = ast_variable_retrieve(cfg, "general", "mailcmd")))
07402 ast_copy_string(mailcmd, astmailcmd, sizeof(mailcmd));
07403
07404 maxsilence = 0;
07405 if ((silencestr = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
07406 maxsilence = atoi(silencestr);
07407 if (maxsilence > 0)
07408 maxsilence *= 1000;
07409 }
07410
07411 if (!(maxmsgstr = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
07412 maxmsg = MAXMSG;
07413 } else {
07414 maxmsg = atoi(maxmsgstr);
07415 if (maxmsg <= 0) {
07416 ast_log(LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", maxmsgstr, MAXMSG);
07417 maxmsg = MAXMSG;
07418 } else if (maxmsg > MAXMSGLIMIT) {
07419 ast_log(LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, maxmsgstr);
07420 maxmsg = MAXMSGLIMIT;
07421 }
07422 }
07423
07424
07425 if ((emaildateformatstr = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
07426 ast_copy_string(emaildateformat, emaildateformatstr, sizeof(emaildateformat));
07427 }
07428
07429
07430 if ((extpc = ast_variable_retrieve(cfg, "general", "externpass"))) {
07431 ast_copy_string(ext_pass_cmd,extpc,sizeof(ext_pass_cmd));
07432 }
07433 #ifdef IMAP_STORAGE
07434
07435 if ((imap_server = ast_variable_retrieve(cfg, "general", "imapserver"))) {
07436 ast_copy_string(imapserver, imap_server, sizeof(imapserver));
07437 } else {
07438 ast_copy_string(imapserver,"localhost", sizeof(imapserver));
07439 }
07440
07441 if ((imap_port = ast_variable_retrieve(cfg, "general", "imapport"))) {
07442 ast_copy_string(imapport, imap_port, sizeof(imapport));
07443 } else {
07444 ast_copy_string(imapport,"143", sizeof(imapport));
07445 }
07446
07447 if ((imap_flags = ast_variable_retrieve(cfg, "general", "imapflags"))) {
07448 ast_copy_string(imapflags, imap_flags, sizeof(imapflags));
07449 }
07450
07451 if ((auth_user = ast_variable_retrieve(cfg, "general", "authuser"))) {
07452 ast_copy_string(authuser, auth_user, sizeof(authuser));
07453 }
07454
07455 if ((auth_password = ast_variable_retrieve(cfg, "general", "authpassword"))) {
07456 ast_copy_string(authpassword, auth_password, sizeof(authpassword));
07457 }
07458
07459 if ((expunge_on_hangup = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
07460 if (ast_false(expunge_on_hangup))
07461 expungeonhangup = 0;
07462 else
07463 expungeonhangup = 1;
07464 } else {
07465 expungeonhangup = 1;
07466 }
07467
07468 if ((imap_folder = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
07469 ast_copy_string(imapfolder, imap_folder, sizeof(imapfolder));
07470 } else {
07471 ast_copy_string(imapfolder,"INBOX", sizeof(imapfolder));
07472 }
07473 #endif
07474
07475
07476 if ((notifystr = ast_variable_retrieve(cfg, "general", "externnotify"))) {
07477 ast_copy_string(externnotify, notifystr, sizeof(externnotify));
07478 if (option_debug > 2)
07479 ast_log(LOG_DEBUG, "found externnotify: %s\n", externnotify);
07480 if (!strcasecmp(externnotify, "smdi")) {
07481 if (option_debug)
07482 ast_log(LOG_DEBUG, "Using SMDI for external voicemail notification\n");
07483 if ((smdistr = ast_variable_retrieve(cfg, "general", "smdiport"))) {
07484 smdi_iface = ast_smdi_interface_find(smdistr);
07485 } else {
07486 if (option_debug)
07487 ast_log(LOG_DEBUG, "No SMDI interface set, trying default (/dev/ttyS0)\n");
07488 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
07489 }
07490
07491 if (!smdi_iface) {
07492 ast_log(LOG_ERROR, "No valid SMDI interface specfied, disabling external voicemail notification\n");
07493 externnotify[0] = '\0';
07494 }
07495 }
07496 } else {
07497 externnotify[0] = '\0';
07498 }
07499
07500
07501 silencethreshold = 256;
07502 if ((thresholdstr = ast_variable_retrieve(cfg, "general", "silencethreshold")))
07503 silencethreshold = atoi(thresholdstr);
07504
07505 if (!(astemail = ast_variable_retrieve(cfg, "general", "serveremail")))
07506 astemail = ASTERISK_USERNAME;
07507 ast_copy_string(serveremail, astemail, sizeof(serveremail));
07508
07509 vmmaxmessage = 0;
07510 if ((s = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
07511 if (sscanf(s, "%d", &x) == 1) {
07512 vmmaxmessage = x;
07513 } else {
07514 ast_log(LOG_WARNING, "Invalid max message time length\n");
07515 }
07516 }
07517
07518 vmminmessage = 0;
07519 if ((s = ast_variable_retrieve(cfg, "general", "minmessage"))) {
07520 if (sscanf(s, "%d", &x) == 1) {
07521 vmminmessage = x;
07522 if (maxsilence <= vmminmessage)
07523 ast_log(LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
07524 } else {
07525 ast_log(LOG_WARNING, "Invalid min message time length\n");
07526 }
07527 }
07528 fmt = ast_variable_retrieve(cfg, "general", "format");
07529 if (!fmt)
07530 fmt = "wav";
07531 ast_copy_string(vmfmts, fmt, sizeof(vmfmts));
07532
07533 skipms = 3000;
07534 if ((s = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
07535 if (sscanf(s, "%d", &x) == 1) {
07536 maxgreet = x;
07537 } else {
07538 ast_log(LOG_WARNING, "Invalid max message greeting length\n");
07539 }
07540 }
07541
07542 if ((s = ast_variable_retrieve(cfg, "general", "skipms"))) {
07543 if (sscanf(s, "%d", &x) == 1) {
07544 skipms = x;
07545 } else {
07546 ast_log(LOG_WARNING, "Invalid skipms value\n");
07547 }
07548 }
07549
07550 maxlogins = 3;
07551 if ((s = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
07552 if (sscanf(s, "%d", &x) == 1) {
07553 maxlogins = x;
07554 } else {
07555 ast_log(LOG_WARNING, "Invalid max failed login attempts\n");
07556 }
07557 }
07558
07559
07560 if (!(astforcename = ast_variable_retrieve(cfg, "general", "forcename")))
07561 astforcename = "no";
07562 ast_set2_flag((&globalflags), ast_true(astforcename), VM_FORCENAME);
07563
07564
07565 if (!(astforcegreet = ast_variable_retrieve(cfg, "general", "forcegreetings")))
07566 astforcegreet = "no";
07567 ast_set2_flag((&globalflags), ast_true(astforcegreet), VM_FORCEGREET);
07568
07569 if ((s = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))){
07570 if (option_debug > 2)
07571 ast_log(LOG_DEBUG,"VM_CID Internal context string: %s\n",s);
07572 stringp = ast_strdupa(s);
07573 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
07574 if (!ast_strlen_zero(stringp)) {
07575 q = strsep(&stringp,",");
07576 while ((*q == ' ')||(*q == '\t'))
07577 q++;
07578 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
07579 if (option_debug > 2)
07580 ast_log(LOG_DEBUG,"VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
07581 } else {
07582 cidinternalcontexts[x][0] = '\0';
07583 }
07584 }
07585 }
07586 if (!(astreview = ast_variable_retrieve(cfg, "general", "review"))){
07587 if (option_debug)
07588 ast_log(LOG_DEBUG,"VM Review Option disabled globally\n");
07589 astreview = "no";
07590 }
07591 ast_set2_flag((&globalflags), ast_true(astreview), VM_REVIEW);
07592
07593
07594 if (!(asttempgreetwarn = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
07595 if (option_debug)
07596 ast_log(LOG_DEBUG, "VM Temperary Greeting Reminder Option disabled globally\n");
07597 asttempgreetwarn = "no";
07598 } else {
07599 if (option_debug)
07600 ast_log(LOG_DEBUG, "VM Temperary Greeting Reminder Option enabled globally\n");
07601 }
07602 ast_set2_flag((&globalflags), ast_true(asttempgreetwarn), VM_TEMPGREETWARN);
07603
07604 if (!(astcallop = ast_variable_retrieve(cfg, "general", "operator"))){
07605 if (option_debug)
07606 ast_log(LOG_DEBUG,"VM Operator break disabled globally\n");
07607 astcallop = "no";
07608 }
07609 ast_set2_flag((&globalflags), ast_true(astcallop), VM_OPERATOR);
07610
07611 if (!(astsaycid = ast_variable_retrieve(cfg, "general", "saycid"))) {
07612 if (option_debug)
07613 ast_log(LOG_DEBUG,"VM CID Info before msg disabled globally\n");
07614 astsaycid = "no";
07615 }
07616 ast_set2_flag((&globalflags), ast_true(astsaycid), VM_SAYCID);
07617
07618 if (!(send_voicemail = ast_variable_retrieve(cfg,"general", "sendvoicemail"))){
07619 if (option_debug)
07620 ast_log(LOG_DEBUG,"Send Voicemail msg disabled globally\n");
07621 send_voicemail = "no";
07622 }
07623 ast_set2_flag((&globalflags), ast_true(send_voicemail), VM_SVMAIL);
07624
07625 if (!(asthearenv = ast_variable_retrieve(cfg, "general", "envelope"))) {
07626 if (option_debug)
07627 ast_log(LOG_DEBUG,"ENVELOPE before msg enabled globally\n");
07628 asthearenv = "yes";
07629 }
07630 ast_set2_flag((&globalflags), ast_true(asthearenv), VM_ENVELOPE);
07631
07632 if (!(astsaydurationinfo = ast_variable_retrieve(cfg, "general", "sayduration"))) {
07633 if (option_debug)
07634 ast_log(LOG_DEBUG,"Duration info before msg enabled globally\n");
07635 astsaydurationinfo = "yes";
07636 }
07637 ast_set2_flag((&globalflags), ast_true(astsaydurationinfo), VM_SAYDURATION);
07638
07639 saydurationminfo = 2;
07640 if ((astsaydurationminfo = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
07641 if (sscanf(astsaydurationminfo, "%d", &x) == 1) {
07642 saydurationminfo = x;
07643 } else {
07644 ast_log(LOG_WARNING, "Invalid min duration for say duration\n");
07645 }
07646 }
07647
07648 if (!(astskipcmd = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
07649 if (option_debug)
07650 ast_log(LOG_DEBUG,"We are not going to skip to the next msg after save/delete\n");
07651 astskipcmd = "no";
07652 }
07653 ast_set2_flag((&globalflags), ast_true(astskipcmd), VM_SKIPAFTERCMD);
07654
07655 if ((dialoutcxt = ast_variable_retrieve(cfg, "general", "dialout"))) {
07656 ast_copy_string(dialcontext, dialoutcxt, sizeof(dialcontext));
07657 if (option_debug)
07658 ast_log(LOG_DEBUG, "found dialout context: %s\n", dialcontext);
07659 } else {
07660 dialcontext[0] = '\0';
07661 }
07662
07663 if ((callbackcxt = ast_variable_retrieve(cfg, "general", "callback"))) {
07664 ast_copy_string(callcontext, callbackcxt, sizeof(callcontext));
07665 if (option_debug)
07666 ast_log(LOG_DEBUG, "found callback context: %s\n", callcontext);
07667 } else {
07668 callcontext[0] = '\0';
07669 }
07670
07671 if ((exitcxt = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
07672 ast_copy_string(exitcontext, exitcxt, sizeof(exitcontext));
07673 if (option_debug)
07674 ast_log(LOG_DEBUG, "found operator context: %s\n", exitcontext);
07675 } else {
07676 exitcontext[0] = '\0';
07677 }
07678
07679 if (!(astdirfwd = ast_variable_retrieve(cfg, "general", "usedirectory")))
07680 astdirfwd = "no";
07681 ast_set2_flag((&globalflags), ast_true(astdirfwd), VM_DIRECFORWARD);
07682 if ((ucfg = ast_config_load("users.conf"))) {
07683 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
07684 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
07685 continue;
07686 if ((cur = find_or_create(userscontext, cat))) {
07687 populate_defaults(cur);
07688 apply_options_full(cur, ast_variable_browse(ucfg, cat));
07689 ast_copy_string(cur->context, userscontext, sizeof(cur->context));
07690 }
07691 }
07692 ast_config_destroy(ucfg);
07693 }
07694 cat = ast_category_browse(cfg, NULL);
07695 while (cat) {
07696 if (strcasecmp(cat, "general")) {
07697 var = ast_variable_browse(cfg, cat);
07698 if (strcasecmp(cat, "zonemessages")) {
07699
07700 while (var) {
07701 append_mailbox(cat, var->name, var->value);
07702 var = var->next;
07703 }
07704 } else {
07705
07706 while (var) {
07707 struct vm_zone *z;
07708 if ((z = ast_malloc(sizeof(*z)))) {
07709 char *msg_format, *timezone;
07710 msg_format = ast_strdupa(var->value);
07711 timezone = strsep(&msg_format, "|");
07712 if (msg_format) {
07713 ast_copy_string(z->name, var->name, sizeof(z->name));
07714 ast_copy_string(z->timezone, timezone, sizeof(z->timezone));
07715 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
07716 AST_LIST_LOCK(&zones);
07717 AST_LIST_INSERT_HEAD(&zones, z, list);
07718 AST_LIST_UNLOCK(&zones);
07719 } else {
07720 ast_log(LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
07721 free(z);
07722 }
07723 } else {
07724 free(z);
07725 AST_LIST_UNLOCK(&users);
07726 ast_config_destroy(cfg);
07727 return -1;
07728 }
07729 var = var->next;
07730 }
07731 }
07732 }
07733 cat = ast_category_browse(cfg, cat);
07734 }
07735 memset(fromstring,0,sizeof(fromstring));
07736 memset(pagerfromstring,0,sizeof(pagerfromstring));
07737 memset(emailtitle,0,sizeof(emailtitle));
07738 strcpy(charset, "ISO-8859-1");
07739 if (emailbody) {
07740 free(emailbody);
07741 emailbody = NULL;
07742 }
07743 if (emailsubject) {
07744 free(emailsubject);
07745 emailsubject = NULL;
07746 }
07747 if (pagerbody) {
07748 free(pagerbody);
07749 pagerbody = NULL;
07750 }
07751 if (pagersubject) {
07752 free(pagersubject);
07753 pagersubject = NULL;
07754 }
07755 if ((s = ast_variable_retrieve(cfg, "general", "pbxskip")))
07756 ast_set2_flag((&globalflags), ast_true(s), VM_PBXSKIP);
07757 if ((s = ast_variable_retrieve(cfg, "general", "fromstring")))
07758 ast_copy_string(fromstring,s,sizeof(fromstring));
07759 if ((s = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
07760 ast_copy_string(pagerfromstring,s,sizeof(pagerfromstring));
07761 if ((s = ast_variable_retrieve(cfg, "general", "charset")))
07762 ast_copy_string(charset,s,sizeof(charset));
07763 if ((s = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
07764 sscanf(s, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
07765 for (x = 0; x < 4; x++) {
07766 memcpy(&adsifdn[x], &tmpadsi[x], 1);
07767 }
07768 }
07769 if ((s = ast_variable_retrieve(cfg, "general", "adsisec"))) {
07770 sscanf(s, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
07771 for (x = 0; x < 4; x++) {
07772 memcpy(&adsisec[x], &tmpadsi[x], 1);
07773 }
07774 }
07775 if ((s = ast_variable_retrieve(cfg, "general", "adsiver")))
07776 if (atoi(s)) {
07777 adsiver = atoi(s);
07778 }
07779 if ((s = ast_variable_retrieve(cfg, "general", "emailtitle"))) {
07780 ast_log(LOG_NOTICE, "Keyword 'emailtitle' is DEPRECATED, please use 'emailsubject' instead.\n");
07781 ast_copy_string(emailtitle,s,sizeof(emailtitle));
07782 }
07783 if ((s = ast_variable_retrieve(cfg, "general", "emailsubject")))
07784 emailsubject = ast_strdup(s);
07785 if ((s = ast_variable_retrieve(cfg, "general", "emailbody"))) {
07786 char *tmpread, *tmpwrite;
07787 emailbody = ast_strdup(s);
07788
07789
07790 tmpread = tmpwrite = emailbody;
07791 while ((tmpwrite = strchr(tmpread,'\\'))) {
07792 switch (tmpwrite[1]) {
07793 case 'r':
07794 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
07795 *tmpwrite = '\r';
07796 break;
07797 case 'n':
07798 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
07799 *tmpwrite = '\n';
07800 break;
07801 case 't':
07802 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
07803 *tmpwrite = '\t';
07804 break;
07805 default:
07806 ast_log(LOG_NOTICE, "Substitution routine does not support this character: %c\n", tmpwrite[1]);
07807 }
07808 tmpread = tmpwrite + 1;
07809 }
07810 }
07811 if ((s = ast_variable_retrieve(cfg, "general", "pagersubject")))
07812 pagersubject = ast_strdup(s);
07813 if ((s = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
07814 char *tmpread, *tmpwrite;
07815 pagerbody = ast_strdup(s);
07816
07817
07818 tmpread = tmpwrite = pagerbody;
07819 while ((tmpwrite = strchr(tmpread, '\\'))) {
07820 switch (tmpwrite[1]) {
07821 case 'r':
07822 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
07823 *tmpwrite = '\r';
07824 break;
07825 case 'n':
07826 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
07827 *tmpwrite = '\n';
07828 break;
07829 case 't':
07830 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
07831 *tmpwrite = '\t';
07832 break;
07833 default:
07834 ast_log(LOG_NOTICE, "Substitution routine does not support this character: %c\n", tmpwrite[1]);
07835 }
07836 tmpread = tmpwrite + 1;
07837 }
07838 }
07839 AST_LIST_UNLOCK(&users);
07840 ast_config_destroy(cfg);
07841 return 0;
07842 } else {
07843 AST_LIST_UNLOCK(&users);
07844 ast_log(LOG_WARNING, "Failed to load configuration file.\n");
07845 return 0;
07846 }
07847 }
07848
07849 static int reload(void)
07850 {
07851 return(load_config());
07852 }
07853
07854 static int unload_module(void)
07855 {
07856 int res;
07857
07858 res = ast_unregister_application(app);
07859 res |= ast_unregister_application(app2);
07860 res |= ast_unregister_application(app3);
07861 res |= ast_unregister_application(app4);
07862 ast_cli_unregister_multiple(cli_voicemail, sizeof(cli_voicemail) / sizeof(struct ast_cli_entry));
07863 ast_uninstall_vm_functions();
07864
07865 ast_module_user_hangup_all();
07866
07867 return res;
07868 }
07869
07870 static int load_module(void)
07871 {
07872 int res;
07873 char *adsi_loaded = ast_module_helper("", "res_adsi.so", 0, 0, 0, 0);
07874 free(adsi_loaded);
07875 if (!adsi_loaded) {
07876
07877 adsi_loaded = ast_module_helper("", "res_adsi", 0, 0, 0, 0);
07878 ast_free(adsi_loaded);
07879 if (!adsi_loaded) {
07880 ast_log(LOG_ERROR, "app_voicemail.so depends upon res_adsi.so\n");
07881 return AST_MODULE_LOAD_DECLINE;
07882 }
07883 }
07884
07885 my_umask = umask(0);
07886 umask(my_umask);
07887 res = ast_register_application(app, vm_exec, synopsis_vm, descrip_vm);
07888 res |= ast_register_application(app2, vm_execmain, synopsis_vmain, descrip_vmain);
07889 res |= ast_register_application(app3, vm_box_exists, synopsis_vm_box_exists, descrip_vm_box_exists);
07890 res |= ast_register_application(app4, vmauthenticate, synopsis_vmauthenticate, descrip_vmauthenticate);
07891 if (res)
07892 return(res);
07893
07894 if ((res=load_config())) {
07895 return(res);
07896 }
07897
07898 ast_cli_register_multiple(cli_voicemail, sizeof(cli_voicemail) / sizeof(struct ast_cli_entry));
07899
07900
07901 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
07902
07903 ast_install_vm_functions(has_voicemail, inboxcount, messagecount);
07904
07905 return res;
07906 }
07907
07908 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
07909 {
07910 int cmd = 0;
07911 char destination[80] = "";
07912 int retries = 0;
07913
07914 if (!num) {
07915 if (option_verbose > 2)
07916 ast_verbose( VERBOSE_PREFIX_3 "Destination number will be entered manually\n");
07917 while (retries < 3 && cmd != 't') {
07918 destination[1] = '\0';
07919 destination[0] = cmd = ast_play_and_wait(chan,"vm-enter-num-to-call");
07920 if (!cmd)
07921 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
07922 if (!cmd)
07923 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
07924 if (!cmd) {
07925 cmd = ast_waitfordigit(chan, 6000);
07926 if (cmd)
07927 destination[0] = cmd;
07928 }
07929 if (!cmd) {
07930 retries++;
07931 } else {
07932
07933 if (cmd < 0)
07934 return 0;
07935 if (cmd == '*') {
07936 if (option_verbose > 2)
07937 ast_verbose( VERBOSE_PREFIX_3 "User hit '*' to cancel outgoing call\n");
07938 return 0;
07939 }
07940 if ((cmd = ast_readstring(chan,destination + strlen(destination),sizeof(destination)-1,6000,10000,"#")) < 0)
07941 retries++;
07942 else
07943 cmd = 't';
07944 }
07945 }
07946 if (retries >= 3) {
07947 return 0;
07948 }
07949
07950 } else {
07951 if (option_verbose > 2)
07952 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
07953 ast_copy_string(destination, num, sizeof(destination));
07954 }
07955
07956 if (!ast_strlen_zero(destination)) {
07957 if (destination[strlen(destination) -1 ] == '*')
07958 return 0;
07959 if (option_verbose > 2)
07960 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
07961 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
07962 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
07963 chan->priority = 0;
07964 return 9;
07965 }
07966 return 0;
07967 }
07968
07969 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)
07970 {
07971 int res = 0;
07972 #ifdef IMAP_STORAGE
07973 char origtimeS[256],cidS[256],contextS[256];
07974 char *header_content,*temp;
07975 #endif
07976 char filename[PATH_MAX];
07977 struct ast_config *msg_cfg = NULL;
07978 const char *origtime, *context;
07979 char *cid, *name, *num;
07980 int retries = 0;
07981
07982 vms->starting = 0;
07983 #ifdef IMAP_STORAGE
07984
07985
07986 if (option_debug > 2)
07987 ast_log (LOG_DEBUG,"Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n",vms->curmsg, vms->msgArray[vms->curmsg]);
07988 if (vms->msgArray[vms->curmsg] == 0) {
07989 ast_log (LOG_WARNING,"Trying to access unknown message\n");
07990 return -1;
07991 }
07992
07993
07994 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[vms->curmsg]);
07995
07996 if (ast_strlen_zero(header_content)) {
07997 ast_log (LOG_ERROR,"Could not fetch header for message number %ld\n",vms->msgArray[vms->curmsg]);
07998 return -1;
07999 }
08000
08001
08002 temp = get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:");
08003
08004 if (temp)
08005 ast_copy_string(cidS,temp, sizeof(cidS));
08006 else
08007 cidS[0] = '\0';
08008
08009 cid = &cidS[0];
08010 temp = get_header_by_tag(header_content, "X-Asterisk-VM-Context:");
08011
08012 if (temp)
08013 ast_copy_string(contextS,temp, sizeof(contextS));
08014 else
08015 contextS[0] = '\0';
08016
08017 context = &contextS[0];
08018 temp = get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:");
08019
08020 if (temp)
08021 ast_copy_string(origtimeS,temp, sizeof(origtimeS));
08022 else
08023 origtimeS[0] = '\0';
08024
08025 origtime = &origtimeS[0];
08026
08027 ast_copy_string(filename, "IMAP_STORAGE", sizeof(filename));
08028 #else
08029 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
08030
08031
08032
08033 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
08034 snprintf(filename,sizeof(filename), "%s.txt", vms->fn2);
08035 RETRIEVE(vms->curdir, vms->curmsg);
08036 msg_cfg = ast_config_load(filename);
08037 DISPOSE(vms->curdir, vms->curmsg);
08038 if (!msg_cfg) {
08039 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
08040 return 0;
08041 }
08042
08043 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
08044 ast_config_destroy(msg_cfg);
08045 return 0;
08046 }
08047
08048 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
08049
08050 context = ast_variable_retrieve(msg_cfg, "message", "context");
08051 if (!strncasecmp("macro",context,5))
08052 context = ast_variable_retrieve(msg_cfg, "message","macrocontext");
08053 #endif
08054 switch (option) {
08055 case 3:
08056 if (!res)
08057 res = play_message_datetime(chan, vmu, origtime, filename);
08058 if (!res)
08059 res = play_message_callerid(chan, vms, cid, context, 0);
08060
08061 res = 't';
08062 break;
08063
08064 case 2:
08065
08066 if (ast_strlen_zero(cid))
08067 break;
08068
08069 ast_callerid_parse(cid, &name, &num);
08070 while ((res > -1) && (res != 't')) {
08071 switch (res) {
08072 case '1':
08073 if (num) {
08074
08075 res = dialout(chan, vmu, num, vmu->callback);
08076 if (res) {
08077 ast_config_destroy(msg_cfg);
08078 return 9;
08079 }
08080 } else {
08081 res = '2';
08082 }
08083 break;
08084
08085 case '2':
08086
08087 if (!ast_strlen_zero(vmu->dialout)) {
08088 res = dialout(chan, vmu, NULL, vmu->dialout);
08089 if (res) {
08090 ast_config_destroy(msg_cfg);
08091 return 9;
08092 }
08093 } else {
08094 if (option_verbose > 2)
08095 ast_verbose( VERBOSE_PREFIX_3 "Caller can not specify callback number - no dialout context available\n");
08096 res = ast_play_and_wait(chan, "vm-sorry");
08097 }
08098 ast_config_destroy(msg_cfg);
08099 return res;
08100 case '*':
08101 res = 't';
08102 break;
08103 case '3':
08104 case '4':
08105 case '5':
08106 case '6':
08107 case '7':
08108 case '8':
08109 case '9':
08110 case '0':
08111
08112 res = ast_play_and_wait(chan, "vm-sorry");
08113 retries++;
08114 break;
08115 default:
08116 if (num) {
08117 if (option_verbose > 2)
08118 ast_verbose( VERBOSE_PREFIX_3 "Confirm CID number '%s' is number to use for callback\n", num);
08119 res = ast_play_and_wait(chan, "vm-num-i-have");
08120 if (!res)
08121 res = play_message_callerid(chan, vms, num, vmu->context, 1);
08122 if (!res)
08123 res = ast_play_and_wait(chan, "vm-tocallnum");
08124
08125 if (!ast_strlen_zero(vmu->dialout)) {
08126 if (!res)
08127 res = ast_play_and_wait(chan, "vm-calldiffnum");
08128 }
08129 } else {
08130 res = ast_play_and_wait(chan, "vm-nonumber");
08131 if (!ast_strlen_zero(vmu->dialout)) {
08132 if (!res)
08133 res = ast_play_and_wait(chan, "vm-toenternumber");
08134 }
08135 }
08136 if (!res)
08137 res = ast_play_and_wait(chan, "vm-star-cancel");
08138 if (!res)
08139 res = ast_waitfordigit(chan, 6000);
08140 if (!res) {
08141 retries++;
08142 if (retries > 3)
08143 res = 't';
08144 }
08145 break;
08146
08147 }
08148 if (res == 't')
08149 res = 0;
08150 else if (res == '*')
08151 res = -1;
08152 }
08153 break;
08154
08155 case 1:
08156
08157 if (ast_strlen_zero(cid))
08158 break;
08159
08160 ast_callerid_parse(cid, &name, &num);
08161 if (!num) {
08162 if (option_verbose > 2)
08163 ast_verbose(VERBOSE_PREFIX_3 "No CID number available, no reply sent\n");
08164 if (!res)
08165 res = ast_play_and_wait(chan, "vm-nonumber");
08166 ast_config_destroy(msg_cfg);
08167 return res;
08168 } else {
08169 struct ast_vm_user vmu2;
08170 if (find_user(&vmu2, vmu->context, num)) {
08171 struct leave_vm_options leave_options;
08172 char mailbox[AST_MAX_EXTENSION * 2 + 2];
08173 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
08174
08175 if (option_verbose > 2)
08176 ast_verbose(VERBOSE_PREFIX_3 "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
08177
08178 memset(&leave_options, 0, sizeof(leave_options));
08179 leave_options.record_gain = record_gain;
08180 res = leave_voicemail(chan, mailbox, &leave_options);
08181 if (!res)
08182 res = 't';
08183 ast_config_destroy(msg_cfg);
08184 return res;
08185 } else {
08186
08187 if (option_verbose > 2)
08188 ast_verbose( VERBOSE_PREFIX_3 "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
08189 ast_play_and_wait(chan, "vm-nobox");
08190 res = 't';
08191 ast_config_destroy(msg_cfg);
08192 return res;
08193 }
08194 }
08195 res = 0;
08196
08197 break;
08198 }
08199
08200 #ifndef IMAP_STORAGE
08201 ast_config_destroy(msg_cfg);
08202
08203 if (!res) {
08204 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
08205 vms->heard[msg] = 1;
08206 res = wait_file(chan, vms, vms->fn);
08207 }
08208 #endif
08209 return res;
08210 }
08211
08212 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
08213 int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
08214 signed char record_gain, struct vm_state *vms)
08215 {
08216
08217 int res = 0;
08218 int cmd = 0;
08219 int max_attempts = 3;
08220 int attempts = 0;
08221 int recorded = 0;
08222 int message_exists = 0;
08223 signed char zero_gain = 0;
08224 char tempfile[PATH_MAX];
08225 char *acceptdtmf = "#";
08226 char *canceldtmf = "";
08227
08228
08229
08230
08231 if (duration == NULL) {
08232 ast_log(LOG_WARNING, "Error play_record_review called without duration pointer\n");
08233 return -1;
08234 }
08235
08236 if (!outsidecaller)
08237 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
08238 else
08239 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
08240
08241 cmd = '3';
08242
08243 while ((cmd >= 0) && (cmd != 't')) {
08244 switch (cmd) {
08245 case '1':
08246 if (!message_exists) {
08247
08248 cmd = '3';
08249 break;
08250 } else {
08251
08252 if (option_verbose > 2)
08253 ast_verbose(VERBOSE_PREFIX_3 "Saving message as is\n");
08254 if (!outsidecaller)
08255 ast_filerename(tempfile, recordfile, NULL);
08256 ast_stream_and_wait(chan, "vm-msgsaved", chan->language, "");
08257 if (!outsidecaller) {
08258 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms);
08259 DISPOSE(recordfile, -1);
08260 }
08261 cmd = 't';
08262 return res;
08263 }
08264 case '2':
08265
08266 if (option_verbose > 2)
08267 ast_verbose(VERBOSE_PREFIX_3 "Reviewing the message\n");
08268 cmd = ast_stream_and_wait(chan, tempfile, chan->language, AST_DIGIT_ANY);
08269 break;
08270 case '3':
08271 message_exists = 0;
08272
08273 if (recorded == 1) {
08274 if (option_verbose > 2)
08275 ast_verbose(VERBOSE_PREFIX_3 "Re-recording the message\n");
08276 } else {
08277 if (option_verbose > 2)
08278 ast_verbose(VERBOSE_PREFIX_3 "Recording the message\n");
08279 }
08280 if (recorded && outsidecaller) {
08281 cmd = ast_play_and_wait(chan, INTRO);
08282 cmd = ast_play_and_wait(chan, "beep");
08283 }
08284 recorded = 1;
08285
08286 if (record_gain)
08287 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
08288 if (ast_test_flag(vmu, VM_OPERATOR))
08289 canceldtmf = "0";
08290 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
08291 if (record_gain)
08292 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
08293 if (cmd == -1) {
08294
08295 if (!outsidecaller) {
08296
08297 ast_filedelete(tempfile, NULL);
08298 }
08299 return cmd;
08300 }
08301 if (cmd == '0') {
08302 break;
08303 } else if (cmd == '*') {
08304 break;
08305 }
08306 #if 0
08307 else if (vmu->review && (*duration < 5)) {
08308
08309 if (option_verbose > 2)
08310 ast_verbose(VERBOSE_PREFIX_3 "Message too short\n");
08311 cmd = ast_play_and_wait(chan, "vm-tooshort");
08312 cmd = ast_filedelete(tempfile, NULL);
08313 break;
08314 }
08315 else if (vmu->review && (cmd == 2 && *duration < (maxsilence + 3))) {
08316
08317 if (option_verbose > 2)
08318 ast_verbose(VERBOSE_PREFIX_3 "Nothing recorded\n");
08319 cmd = ast_filedelete(tempfile, NULL);
08320 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
08321 if (!cmd)
08322 cmd = ast_play_and_wait(chan, "vm-speakup");
08323 break;
08324 }
08325 #endif
08326 else {
08327
08328 message_exists = 1;
08329 cmd = 0;
08330 }
08331 break;
08332 case '4':
08333 case '5':
08334 case '6':
08335 case '7':
08336 case '8':
08337 case '9':
08338 case '*':
08339 case '#':
08340 cmd = ast_play_and_wait(chan, "vm-sorry");
08341 break;
08342 #if 0
08343
08344
08345 case '*':
08346
08347 cmd = ast_play_and_wait(chan, "vm-deleted");
08348 cmd = ast_filedelete(tempfile, NULL);
08349 if (outsidecaller) {
08350 res = vm_exec(chan, NULL);
08351 return res;
08352 }
08353 else
08354 return 1;
08355 #endif
08356 case '0':
08357 if (!ast_test_flag(vmu, VM_OPERATOR)) {
08358 cmd = ast_play_and_wait(chan, "vm-sorry");
08359 break;
08360 }
08361 if (message_exists || recorded) {
08362 cmd = ast_play_and_wait(chan, "vm-saveoper");
08363 if (!cmd)
08364 cmd = ast_waitfordigit(chan, 3000);
08365 if (cmd == '1') {
08366 ast_play_and_wait(chan, "vm-msgsaved");
08367 cmd = '0';
08368 } else {
08369 ast_play_and_wait(chan, "vm-deleted");
08370 DELETE(recordfile, -1, recordfile);
08371 cmd = '0';
08372 }
08373 }
08374 return cmd;
08375 default:
08376
08377
08378
08379 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
08380 return cmd;
08381 if (message_exists) {
08382 cmd = ast_play_and_wait(chan, "vm-review");
08383 }
08384 else {
08385 cmd = ast_play_and_wait(chan, "vm-torerecord");
08386 if (!cmd)
08387 cmd = ast_waitfordigit(chan, 600);
08388 }
08389
08390 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
08391 cmd = ast_play_and_wait(chan, "vm-reachoper");
08392 if (!cmd)
08393 cmd = ast_waitfordigit(chan, 600);
08394 }
08395 #if 0
08396 if (!cmd)
08397 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
08398 #endif
08399 if (!cmd)
08400 cmd = ast_waitfordigit(chan, 6000);
08401 if (!cmd) {
08402 attempts++;
08403 }
08404 if (attempts > max_attempts) {
08405 cmd = 't';
08406 }
08407 }
08408 }
08409 if (outsidecaller)
08410 ast_play_and_wait(chan, "vm-goodbye");
08411 if (cmd == 't')
08412 cmd = 0;
08413 return cmd;
08414 }
08415
08416 #ifdef IMAP_STORAGE
08417
08418 static void write_file(char *filename, char *buffer, unsigned long len)
08419 {
08420 FILE *output;
08421
08422 output = fopen (filename, "w");
08423 fwrite (buffer, len, 1, output);
08424 fclose (output);
08425 }
08426
08427 void mm_searched(MAILSTREAM *stream, unsigned long number)
08428 {
08429 struct vm_state *vms;
08430 char *mailbox;
08431 char *user;
08432 mailbox = stream->mailbox;
08433 user = get_user_by_mailbox(mailbox);
08434 vms = get_vm_state_by_imapuser(user,2);
08435 if (vms) {
08436 if (option_debug > 2)
08437 ast_log (LOG_DEBUG, "saving mailbox message number %lu as message %d. Interactive set to %d\n",number,vms->vmArrayIndex,vms->interactive);
08438 vms->msgArray[vms->vmArrayIndex++] = number;
08439 } else {
08440 ast_log (LOG_ERROR, "No state found.\n");
08441 }
08442 }
08443
08444
08445 #if 0
08446
08447
08448
08449 static void status(MAILSTREAM *stream)
08450 {
08451 unsigned long i;
08452 char *s, date[MAILTMPLEN];
08453 THREADER *thr;
08454 AUTHENTICATOR *auth;
08455 rfc822_date (date);
08456 ast_log (LOG_NOTICE,"%s\n",date);
08457 if (stream) {
08458 if (stream->mailbox)
08459 ast_log (LOG_NOTICE," %s mailbox: %s, %lu messages, %lu recent\n",
08460 stream->dtb->name, stream->mailbox, stream->nmsgs,stream->recent);
08461 else
08462 ast_log (LOG_NOTICE,"No mailbox is open on this stream\n");
08463 if (stream->user_flags[0]) {
08464 ast_log (LOG_NOTICE,"Keywords: %s\n", stream->user_flags[0]);
08465 for (i = 1; i < NUSERFLAGS && stream->user_flags[i]; ++i)
08466 ast_log (LOG_NOTICE," %s\n", stream->user_flags[i]);
08467 }
08468 if (!strcmp (stream->dtb->name, "imap")) {
08469 if (LEVELIMAP4rev1 (stream))
08470 s = "IMAP4rev1 (RFC 3501)";
08471 else if (LEVEL1730 (stream))
08472 s = "IMAP4 (RFC 1730)";
08473 else if (LEVELIMAP2bis (stream))
08474 s = "IMAP2bis";
08475 else if (LEVEL1176 (stream))
08476 s = "IMAP2 (RFC 1176)";
08477 else
08478 s = "IMAP2 (RFC 1064)";
08479 ast_log (LOG_NOTICE,"%s server %s\n", s, imap_host (stream));
08480 if (LEVELIMAP4 (stream)) {
08481 if ((i = (imap_cap(stream)->auth))) {
08482 s = "";
08483 ast_log (LOG_NOTICE,"Mutually-supported SASL mechanisms:\n");
08484 while ((auth = mail_lookup_auth (find_rightmost_bit (&i) + 1))) {
08485 ast_log (LOG_NOTICE," %s\n", auth->name);
08486 if (!strcmp (auth->name, "PLAIN"))
08487 s = "\n [LOGIN will not be listed here if PLAIN is supported]\n";
08488 }
08489 ast_log (LOG_NOTICE,s);
08490 }
08491 ast_log (LOG_NOTICE,"Supported standard extensions:\n");
08492 if (LEVELACL (stream))
08493 ast_log (LOG_NOTICE," Access Control lists (RFC 2086)\n");
08494 if (LEVELQUOTA (stream))
08495 ast_log (LOG_NOTICE," Quotas (RFC 2087)\n");
08496 if (LEVELLITERALPLUS (stream))
08497 ast_log (LOG_NOTICE," Non-synchronizing literals (RFC 2088)\n");
08498 if (LEVELIDLE (stream))
08499 ast_log (LOG_NOTICE," IDLE unsolicited update (RFC 2177)\n");
08500 if (LEVELMBX_REF (stream))
08501 ast_log (LOG_NOTICE," Mailbox referrals (RFC 2193)\n");
08502 if (LEVELLOG_REF (stream))
08503 ast_log (LOG_NOTICE," Login referrals (RFC 2221)\n");
08504 if (LEVELANONYMOUS (stream))
08505 ast_log (LOG_NOTICE," Anonymous access (RFC 2245)\n");
08506 if (LEVELNAMESPACE (stream))
08507 ast_log (LOG_NOTICE," Multiple namespaces (RFC 2342)\n");
08508 if (LEVELUIDPLUS (stream))
08509 ast_log (LOG_NOTICE," Extended UID behavior (RFC 2359)\n");
08510 if (LEVELSTARTTLS (stream))
08511 ast_log (LOG_NOTICE," Transport Layer Security (RFC 2595)\n");
08512 if (LEVELLOGINDISABLED (stream))
08513 ast_log (LOG_NOTICE," LOGIN command disabled (RFC 2595)\n");
08514 if (LEVELID (stream))
08515 ast_log (LOG_NOTICE," Implementation identity negotiation (RFC 2971)\n");
08516 if (LEVELCHILDREN (stream))
08517 ast_log (LOG_NOTICE," LIST children announcement (RFC 3348)\n");
08518 if (LEVELMULTIAPPEND (stream))
08519 ast_log (LOG_NOTICE," Atomic multiple APPEND (RFC 3502)\n");
08520 if (LEVELBINARY (stream))
08521 ast_log (LOG_NOTICE," Binary body content (RFC 3516)\n");
08522 ast_log (LOG_NOTICE,"Supported draft extensions:\n");
08523 if (LEVELUNSELECT (stream))
08524 ast_log (LOG_NOTICE," Mailbox unselect\n");
08525 if (LEVELSASLIR (stream))
08526 ast_log (LOG_NOTICE," SASL initial client response\n");
08527 if (LEVELSORT (stream))
08528 ast_log (LOG_NOTICE," Server-based sorting\n");
08529 if (LEVELTHREAD (stream)) {
08530 ast_log (LOG_NOTICE," Server-based threading:\n");
08531 for (thr = imap_cap(stream)->threader; thr; thr = thr->next)
08532 ast_log (LOG_NOTICE," %s\n", thr->name);
08533 }
08534 if (LEVELSCAN (stream))
08535 ast_log (LOG_NOTICE," Mailbox text scan\n");
08536 if ((i = imap_cap(stream)->extlevel)) {
08537 ast_log (LOG_NOTICE,"Supported BODYSTRUCTURE extensions:\n");
08538 switch (i) {
08539 case BODYEXTLOC:
08540 ast_log (LOG_NOTICE," location\n");
08541 case BODYEXTLANG:
08542 ast_log (LOG_NOTICE," language\n");
08543 case BODYEXTDSP:
08544 ast_log (LOG_NOTICE," disposition\n");
08545 case BODYEXTMD5:
08546 ast_log (LOG_NOTICE," MD5\n");
08547 }
08548 }
08549 }else
08550 ast_log (LOG_NOTICE,"\n");
08551 }
08552 }
08553 }
08554 #endif
08555
08556 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
08557 {
08558 struct ast_variable *var;
08559 struct ast_vm_user *vmu;
08560
08561 vmu = ast_calloc(1, sizeof *vmu);
08562 if (!vmu)
08563 return NULL;
08564 ast_set_flag(vmu, VM_ALLOCED);
08565 populate_defaults(vmu);
08566
08567 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
08568 if (var) {
08569 apply_options_full(vmu, var);
08570 ast_variables_destroy(var);
08571 return vmu;
08572 } else {
08573 free(vmu);
08574 return NULL;
08575 }
08576 }
08577
08578
08579
08580 void mm_exists(MAILSTREAM * stream, unsigned long number)
08581 {
08582
08583 if (option_debug > 3)
08584 ast_log (LOG_DEBUG, "Entering EXISTS callback for message %ld\n", number);
08585 if (number == 0) return;
08586 set_update(stream);
08587 }
08588
08589
08590 void mm_expunged(MAILSTREAM * stream, unsigned long number)
08591 {
08592
08593 if (option_debug > 3)
08594 ast_log (LOG_DEBUG, "Entering EXPUNGE callback for message %ld\n", number);
08595 if (number == 0) return;
08596 set_update(stream);
08597 }
08598
08599
08600 void mm_flags(MAILSTREAM * stream, unsigned long number)
08601 {
08602
08603 if (option_debug > 3)
08604 ast_log (LOG_DEBUG, "Entering FLAGS callback for message %ld\n", number);
08605 if (number == 0) return;
08606 set_update(stream);
08607 }
08608
08609
08610 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
08611 {
08612 mm_log (string, errflg);
08613 }
08614
08615
08616 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
08617 {
08618 if (delimiter == '\0') {
08619 delimiter = delim;
08620 }
08621 if (option_debug > 4) {
08622 ast_log(LOG_DEBUG, "Delimiter set to %c and mailbox %s\n",delim, mailbox);
08623 if (attributes & LATT_NOINFERIORS)
08624 ast_log(LOG_DEBUG, "no inferiors\n");
08625 if (attributes & LATT_NOSELECT)
08626 ast_log(LOG_DEBUG, "no select\n");
08627 if (attributes & LATT_MARKED)
08628 ast_log(LOG_DEBUG, "marked\n");
08629 if (attributes & LATT_UNMARKED)
08630 ast_log(LOG_DEBUG, "unmarked\n");
08631 }
08632 }
08633
08634
08635 void mm_lsub(MAILSTREAM * stream, int delimiter, char *mailbox, long attributes)
08636 {
08637 if (option_debug > 4) {
08638 ast_log(LOG_DEBUG, "Delimiter set to %c and mailbox %s\n",delimiter, mailbox);
08639 if (attributes & LATT_NOINFERIORS)
08640 ast_log(LOG_DEBUG, "no inferiors\n");
08641 if (attributes & LATT_NOSELECT)
08642 ast_log(LOG_DEBUG, "no select\n");
08643 if (attributes & LATT_MARKED)
08644 ast_log(LOG_DEBUG, "marked\n");
08645 if (attributes & LATT_UNMARKED)
08646 ast_log(LOG_DEBUG, "unmarked\n");
08647 }
08648 }
08649
08650
08651 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
08652 {
08653 ast_log (LOG_NOTICE," Mailbox %s", mailbox);
08654 if (status->flags & SA_MESSAGES)
08655 ast_log (LOG_NOTICE,", %lu messages", status->messages);
08656 if (status->flags & SA_RECENT)
08657 ast_log (LOG_NOTICE,", %lu recent", status->recent);
08658 if (status->flags & SA_UNSEEN)
08659 ast_log (LOG_NOTICE,", %lu unseen", status->unseen);
08660 if (status->flags & SA_UIDVALIDITY)
08661 ast_log (LOG_NOTICE,", %lu UID validity", status->uidvalidity);
08662 if (status->flags & SA_UIDNEXT)
08663 ast_log (LOG_NOTICE,", %lu next UID", status->uidnext);
08664 ast_log (LOG_NOTICE,"\n");
08665 }
08666
08667
08668 void mm_log(char *string, long errflg)
08669 {
08670 switch ((short) errflg) {
08671 case NIL:
08672 if (option_debug)
08673 ast_log(LOG_DEBUG,"IMAP Info: %s\n", string);
08674 break;
08675 case PARSE:
08676 case WARN:
08677 ast_log (LOG_WARNING,"IMAP Warning: %s\n", string);
08678 break;
08679 case ERROR:
08680 ast_log (LOG_ERROR,"IMAP Error: %s\n", string);
08681 break;
08682 }
08683 }
08684
08685
08686 void mm_dlog(char *string)
08687 {
08688 ast_log (LOG_NOTICE, "%s\n", string);
08689 }
08690
08691
08692 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
08693 {
08694 struct ast_vm_user *vmu;
08695
08696 if (option_debug > 3)
08697 ast_log(LOG_DEBUG, "Entering callback mm_login\n");
08698
08699 ast_copy_string(user, mb->user, MAILTMPLEN);
08700
08701
08702 if (!ast_strlen_zero(authpassword)) {
08703 ast_copy_string(pwd, authpassword, MAILTMPLEN);
08704 } else {
08705 AST_LIST_TRAVERSE(&users, vmu, list) {
08706 if (!strcasecmp(mb->user, vmu->imapuser)) {
08707 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
08708 break;
08709 }
08710 }
08711 if (!vmu) {
08712 if ((vmu = find_user_realtime_imapuser(mb->user))) {
08713 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
08714 free_user(vmu);
08715 }
08716 }
08717 }
08718 }
08719
08720
08721 void mm_critical(MAILSTREAM * stream)
08722 {
08723 }
08724
08725
08726 void mm_nocritical(MAILSTREAM * stream)
08727 {
08728 }
08729
08730
08731 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
08732 {
08733 kill (getpid (), SIGSTOP);
08734 return NIL;
08735 }
08736
08737
08738 void mm_fatal(char *string)
08739 {
08740 ast_log(LOG_ERROR,"IMAP access FATAL error: %s\n", string);
08741 }
08742
08743
08744 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
08745 {
08746 struct vm_state *vms;
08747 char *mailbox;
08748 char *user;
08749 unsigned long usage = 0;
08750 unsigned long limit = 0;
08751
08752 while (pquota) {
08753 usage = pquota->usage;
08754 limit = pquota->limit;
08755 pquota = pquota->next;
08756 }
08757
08758 mailbox = stream->mailbox;
08759 user = get_user_by_mailbox(mailbox);
08760 vms = get_vm_state_by_imapuser(user,2);
08761 if (vms) {
08762 if (option_debug > 2)
08763 ast_log (LOG_DEBUG, "User %s usage is %lu, limit is %lu\n",user,usage,limit);
08764 vms->quota_usage = usage;
08765 vms->quota_limit = limit;
08766 } else {
08767 ast_log (LOG_ERROR, "No state found.\n");
08768 }
08769 }
08770
08771 static char *get_header_by_tag(char *header, char *tag)
08772 {
08773 char *start;
08774 int taglen;
08775 char *eol_pnt;
08776
08777 if (!header || !tag)
08778 return NULL;
08779
08780 taglen = strlen(tag) + 1;
08781 if (taglen < 1)
08782 return NULL;
08783
08784 start = strstr(header, tag);
08785 if (!start)
08786 return NULL;
08787
08788 ast_mutex_lock(&imaptemp_lock);
08789 ast_copy_string(imaptemp, start+taglen, sizeof(imaptemp));
08790 ast_mutex_unlock(&imaptemp_lock);
08791 if ((eol_pnt = strchr(imaptemp,'\r')) || (eol_pnt = strchr(imaptemp,'\n')))
08792 *eol_pnt = '\0';
08793 return imaptemp;
08794 }
08795
08796 static char *get_user_by_mailbox(char *mailbox)
08797 {
08798 char *start, *quote;
08799 char *eol_pnt;
08800
08801 if (!mailbox)
08802 return NULL;
08803
08804 start = strstr(mailbox,"/user=");
08805 if (!start)
08806 return NULL;
08807
08808 ast_mutex_lock(&imaptemp_lock);
08809 ast_copy_string(imaptemp, start+6, sizeof(imaptemp));
08810 ast_mutex_unlock(&imaptemp_lock);
08811
08812 quote = strchr(imaptemp,'\"');
08813 if (!quote) {
08814 eol_pnt = strchr(imaptemp,'/');
08815 if (!eol_pnt) {
08816 eol_pnt = strchr(imaptemp,'}');
08817 }
08818 *eol_pnt = '\0';
08819 return imaptemp;
08820 } else {
08821 eol_pnt = strchr(imaptemp+1,'\"');
08822 *eol_pnt = '\0';
08823 return imaptemp+1;
08824 }
08825 }
08826
08827 static struct vm_state *get_vm_state_by_imapuser(char *user, int interactive)
08828 {
08829 struct vmstate *vlist = NULL;
08830
08831 ast_mutex_lock(&vmstate_lock);
08832 vlist = vmstates;
08833 while (vlist) {
08834 if (vlist->vms) {
08835 if (vlist->vms->imapuser) {
08836 if (!strcmp(vlist->vms->imapuser,user)) {
08837 if (interactive == 2) {
08838 ast_mutex_unlock(&vmstate_lock);
08839 return vlist->vms;
08840 } else if (vlist->vms->interactive == interactive) {
08841 ast_mutex_unlock(&vmstate_lock);
08842 return vlist->vms;
08843 }
08844 }
08845 } else {
08846 if (option_debug > 2)
08847 ast_log(LOG_DEBUG, " error: imapuser is NULL for %s\n",user);
08848 }
08849 } else {
08850 if (option_debug > 2)
08851 ast_log(LOG_DEBUG, " error: vms is NULL for %s\n",user);
08852 }
08853 vlist = vlist->next;
08854 }
08855 ast_mutex_unlock(&vmstate_lock);
08856 if (option_debug > 2)
08857 ast_log(LOG_DEBUG, "%s not found in vmstates\n",user);
08858 return NULL;
08859 }
08860
08861 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, int interactive)
08862 {
08863 struct vmstate *vlist = NULL;
08864
08865 ast_mutex_lock(&vmstate_lock);
08866 vlist = vmstates;
08867 if (option_debug > 2)
08868 ast_log(LOG_DEBUG, "Mailbox set to %s\n",mailbox);
08869 while (vlist) {
08870 if (vlist->vms) {
08871 if (vlist->vms->username) {
08872 if (option_debug > 2)
08873 ast_log(LOG_DEBUG, " comparing mailbox %s (i=%d) to vmstate mailbox %s (i=%d)\n",mailbox,interactive,vlist->vms->username,vlist->vms->interactive);
08874 if (!strcmp(vlist->vms->username,mailbox) && vlist->vms->interactive == interactive) {
08875 if (option_debug > 2)
08876 ast_log(LOG_DEBUG, " Found it!\n");
08877 ast_mutex_unlock(&vmstate_lock);
08878 return vlist->vms;
08879 }
08880 } else {
08881 if (option_debug > 2)
08882 ast_log(LOG_DEBUG, " error: username is NULL for %s\n",mailbox);
08883 }
08884 } else {
08885 if (option_debug > 2)
08886 ast_log(LOG_DEBUG, " error: vms is NULL for %s\n",mailbox);
08887 }
08888 vlist = vlist->next;
08889 }
08890 ast_mutex_unlock(&vmstate_lock);
08891 if (option_debug > 2)
08892 ast_log(LOG_DEBUG, "%s not found in vmstates\n",mailbox);
08893 return NULL;
08894 }
08895
08896 static void vmstate_insert(struct vm_state *vms)
08897 {
08898 struct vmstate *v;
08899 struct vm_state *altvms;
08900
08901
08902
08903
08904 if (vms->interactive == 1) {
08905 altvms = get_vm_state_by_mailbox(vms->username,0);
08906 if (altvms) {
08907 if (option_debug > 2)
08908 ast_log(LOG_DEBUG, "Duplicate mailbox %s, copying message info...\n",vms->username);
08909 vms->newmessages = altvms->newmessages;
08910 vms->oldmessages = altvms->oldmessages;
08911 if (option_debug > 2)
08912 ast_log(LOG_DEBUG, "check_msgArray before memcpy\n");
08913 check_msgArray(vms);
08914
08915 copy_msgArray(vms, altvms);
08916 if (option_debug > 2)
08917 ast_log(LOG_DEBUG, "check_msgArray after memcpy\n");
08918 check_msgArray(vms);
08919 vms->vmArrayIndex = altvms->vmArrayIndex;
08920 vms->lastmsg = altvms->lastmsg;
08921 vms->curmsg = altvms->curmsg;
08922
08923 vms->persist_vms = altvms;
08924
08925 vms->mailstream = altvms->mailstream;
08926
08927 }
08928 }
08929
08930 v = (struct vmstate *)malloc(sizeof(struct vmstate));
08931 if (!v) {
08932 ast_log(LOG_ERROR, "Out of memory\n");
08933 }
08934 if (option_debug > 2)
08935 ast_log(LOG_DEBUG, "Inserting vm_state for user:%s, mailbox %s\n",vms->imapuser,vms->username);
08936 ast_mutex_lock(&vmstate_lock);
08937 v->vms = vms;
08938 v->next = vmstates;
08939 vmstates = v;
08940 ast_mutex_unlock(&vmstate_lock);
08941 }
08942
08943 static void vmstate_delete(struct vm_state *vms)
08944 {
08945 struct vmstate *vc, *vf = NULL, *vl = NULL;
08946 struct vm_state *altvms;
08947
08948
08949
08950 if (vms->interactive == 1) {
08951 altvms = vms->persist_vms;
08952 if (altvms) {
08953 if (option_debug > 2)
08954 ast_log(LOG_DEBUG, "Duplicate mailbox %s, copying message info...\n",vms->username);
08955 altvms->newmessages = vms->newmessages;
08956 altvms->oldmessages = vms->oldmessages;
08957 altvms->updated = 1;
08958 }
08959 }
08960
08961 ast_mutex_lock(&vmstate_lock);
08962 vc = vmstates;
08963 if (option_debug > 2)
08964 ast_log(LOG_DEBUG, "Removing vm_state for user:%s, mailbox %s\n",vms->imapuser,vms->username);
08965 while (vc) {
08966 if (vc->vms == vms) {
08967 vf = vc;
08968 if (vl)
08969 vl->next = vc->next;
08970 else
08971 vmstates = vc->next;
08972 break;
08973 }
08974 vl = vc;
08975 vc = vc->next;
08976 }
08977 if (!vf) {
08978 ast_log(LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n",vms->imapuser,vms->username);
08979 } else {
08980 ast_mutex_destroy(&vf->vms->lock);
08981 free(vf);
08982 }
08983 ast_mutex_unlock(&vmstate_lock);
08984 }
08985
08986 static void set_update(MAILSTREAM * stream)
08987 {
08988 struct vm_state *vms;
08989 char *mailbox;
08990 char *user;
08991
08992 mailbox = stream->mailbox;
08993 user = get_user_by_mailbox(mailbox);
08994 vms = get_vm_state_by_imapuser(user, 0);
08995 if (vms) {
08996 if (option_debug > 2)
08997 ast_log (LOG_DEBUG, "User %s mailbox set for update.\n",user);
08998 vms->updated = 1;
08999 } else {
09000 if (option_debug > 2)
09001 ast_log (LOG_WARNING, "User %s mailbox not found for update.\n",user);
09002 }
09003 }
09004
09005 static void init_vm_state(struct vm_state *vms)
09006 {
09007 int x;
09008 vms->vmArrayIndex = 0;
09009 for (x = 0; x < 256; x++) {
09010 vms->msgArray[x] = 0;
09011 }
09012 ast_mutex_init(&vms->lock);
09013 }
09014
09015 static void check_msgArray(struct vm_state *vms)
09016 {
09017 int x;
09018 for (x = 0; x<256; x++) {
09019 if (vms->msgArray[x]!=0) {
09020 if (option_debug)
09021 ast_log (LOG_DEBUG, "Item %d set to %ld\n",x,vms->msgArray[x]);
09022 }
09023 }
09024 }
09025
09026 static void copy_msgArray(struct vm_state *dst, struct vm_state *src)
09027 {
09028 int x;
09029 for (x = 0; x<256; x++) {
09030 dst->msgArray[x] = src->msgArray[x];
09031 }
09032 }
09033
09034 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format)
09035 {
09036 char *body_content;
09037 char *body_decoded;
09038 unsigned long len;
09039 unsigned long newlen;
09040 char filename[256];
09041
09042 if (!body || body == NIL)
09043 return -1;
09044 body_content = mail_fetchbody (vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
09045 if (body_content != NIL) {
09046 snprintf(filename, sizeof(filename), "%s.%s", vms->fn, format);
09047
09048 body_decoded = rfc822_base64 ((unsigned char *)body_content, len, &newlen);
09049 write_file (filename, (char *) body_decoded, newlen);
09050 }
09051 return 0;
09052 }
09053
09054
09055 static void get_mailbox_delimiter(MAILSTREAM *stream) {
09056 char tmp[50];
09057 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
09058 mail_list(stream, tmp, "*");
09059 }
09060
09061
09062 static void check_quota(struct vm_state *vms, char *mailbox) {
09063 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
09064 if (option_debug > 2)
09065 ast_log(LOG_DEBUG, "Mailbox name set to: %s, about to check quotas\n", mailbox);
09066 if (vms && vms->mailstream != NULL) {
09067 imap_getquotaroot(vms->mailstream, mailbox);
09068 } else {
09069 ast_log(LOG_WARNING,"Mailstream not available for mailbox: %s\n",mailbox);
09070 }
09071 }
09072
09073 #endif
09074
09075
09076
09077
09078
09079 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
09080 .load = load_module,
09081 .unload = unload_module,
09082 .reload = reload,
09083 );