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