Bug Summary

File:apps/app_voicemail.c
Location:line 13142, column 3
Description:String copy function overflows destination buffer

Annotated Source Code

1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2006, Digium, Inc.
5 *
6 * Mark Spencer <markster@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*!
20 * \file
21 * \author Mark Spencer <markster@digium.com>
22 * \brief Comedian Mail - Voicemail System
23 *
24 * unixODBC (http://www.unixodbc.org/)
25 * A source distribution of University of Washington's IMAP c-client
26 * (http://www.washington.edu/imap/)
27 *
28 * \par See also
29 * \arg \ref Config_vm
30 * \note For information about voicemail IMAP storage, https://wiki.asterisk.org/wiki/display/AST/IMAP+Voicemail+Storage
31 * \ingroup applications
32 * \todo This module requires res_adsi to load. This needs to be optional
33 * during compilation.
34 *
35 * \todo This file is now almost impossible to work with, due to all \#ifdefs.
36 * Feels like the database code before realtime. Someone - please come up
37 * with a plan to clean this up.
38 */
39
40/*! \li \ref app_voicemail.c uses configuration file \ref voicemail.conf
41 * \addtogroup configuration_file Configuration Files
42 */
43
44/*!
45 * \page voicemail.conf voicemail.conf
46 * \verbinclude voicemail.conf.sample
47 */
48
49/*** MODULEINFO
50 <defaultenabled>yes</defaultenabled>
51 <use type="module">res_adsi</use>
52 <use type="module">res_smdi</use>
53 <support_level>core</support_level>
54 ***/
55
56/*** MAKEOPTS
57<category name="MENUSELECT_OPTS_app_voicemail" displayname="Voicemail Build Options" positive_output="yes" touch_on_change="apps/app_voicemail.c apps/app_directory.c">
58 <member name="FILE_STORAGE" displayname="Storage of Voicemail using filesystem">
59 <conflict>ODBC_STORAGE</conflict>
60 <conflict>IMAP_STORAGE</conflict>
61 <defaultenabled>yes</defaultenabled>
62 <support_level>core</support_level>
63 </member>
64 <member name="ODBC_STORAGE" displayname="Storage of Voicemail using ODBC">
65 <depend>generic_odbc</depend>
66 <depend>ltdl</depend>
67 <conflict>IMAP_STORAGE</conflict>
68 <conflict>FILE_STORAGE</conflict>
69 <defaultenabled>no</defaultenabled>
70 <support_level>core</support_level>
71 </member>
72 <member name="IMAP_STORAGE" displayname="Storage of Voicemail using IMAP4">
73 <depend>imap_tk</depend>
74 <conflict>ODBC_STORAGE</conflict>
75 <conflict>FILE_STORAGE</conflict>
76 <use type="external">openssl</use>
77 <defaultenabled>no</defaultenabled>
78 <support_level>core</support_level>
79 </member>
80</category>
81***/
82
83#include "asterisk.h"
84
85#ifdef IMAP_STORAGE
86#include <ctype.h>
87#include <signal.h>
88#include <pwd.h>
89#ifdef USE_SYSTEM_IMAP
90#include <imap/c-client.h>
91#include <imap/imap4r1.h>
92#include <imap/linkage.h>
93#elif defined (USE_SYSTEM_CCLIENT)
94#include <c-client/c-client.h>
95#include <c-client/imap4r1.h>
96#include <c-client/linkage.h>
97#else
98#include "c-client.h"
99#include "imap4r1.h"
100#include "linkage.h"
101#endif
102#endif
103
104ASTERISK_REGISTER_FILE()static void __attribute__((constructor)) __register_file_version
(void) { __ast_register_file("app_voicemail.c"); } static void
__attribute__((destructor)) __unregister_file_version(void) {
__ast_unregister_file("app_voicemail.c"); }
105
106#include "asterisk/paths.h" /* use ast_config_AST_SPOOL_DIR */
107#include <sys/time.h>
108#include <sys/stat.h>
109#include <sys/mman.h>
110#include <time.h>
111#include <dirent.h>
112#if defined(__FreeBSD__) || defined(__OpenBSD__)
113#include <sys/wait.h>
114#endif
115
116#include "asterisk/logger.h"
117#include "asterisk/lock.h"
118#include "asterisk/file.h"
119#include "asterisk/channel.h"
120#include "asterisk/pbx.h"
121#include "asterisk/config.h"
122#include "asterisk/say.h"
123#include "asterisk/module.h"
124#include "asterisk/adsi.h"
125#include "asterisk/app.h"
126#include "asterisk/manager.h"
127#include "asterisk/dsp.h"
128#include "asterisk/localtime.h"
129#include "asterisk/cli.h"
130#include "asterisk/utils.h"
131#include "asterisk/stringfields.h"
132#include "asterisk/strings.h"
133#include "asterisk/smdi.h"
134#include "asterisk/astobj2.h"
135#include "asterisk/taskprocessor.h"
136#include "asterisk/test.h"
137#include "asterisk/format_cache.h"
138
139#ifdef ODBC_STORAGE
140#include "asterisk/res_odbc.h"
141#endif
142
143#ifdef IMAP_STORAGE
144#include "asterisk/threadstorage.h"
145#endif
146
147/*** DOCUMENTATION
148 <application name="VoiceMail" language="en_US">
149 <synopsis>
150 Leave a Voicemail message.
151 </synopsis>
152 <syntax>
153 <parameter name="mailboxs" argsep="&amp;" required="true">
154 <argument name="mailbox1" argsep="@" required="true">
155 <argument name="mailbox" required="true" />
156 <argument name="context" />
157 </argument>
158 <argument name="mailbox2" argsep="@" multiple="true">
159 <argument name="mailbox" required="true" />
160 <argument name="context" />
161 </argument>
162 </parameter>
163 <parameter name="options">
164 <optionlist>
165 <option name="b">
166 <para>Play the <literal>busy</literal> greeting to the calling party.</para>
167 </option>
168 <option name="d">
169 <argument name="c" />
170 <para>Accept digits for a new extension in context <replaceable>c</replaceable>,
171 if played during the greeting. Context defaults to the current context.</para>
172 </option>
173 <option name="g">
174 <argument name="#" required="true" />
175 <para>Use the specified amount of gain when recording the voicemail
176 message. The units are whole-number decibels (dB). Only works on supported
177 technologies, which is DAHDI only.</para>
178 </option>
179 <option name="s">
180 <para>Skip the playback of instructions for leaving a message to the
181 calling party.</para>
182 </option>
183 <option name="u">
184 <para>Play the <literal>unavailable</literal> greeting.</para>
185 </option>
186 <option name="U">
187 <para>Mark message as <literal>URGENT</literal>.</para>
188 </option>
189 <option name="P">
190 <para>Mark message as <literal>PRIORITY</literal>.</para>
191 </option>
192 </optionlist>
193 </parameter>
194 </syntax>
195 <description>
196 <para>This application allows the calling party to leave a message for the specified
197 list of mailboxes. When multiple mailboxes are specified, the greeting will be taken from
198 the first mailbox specified. Dialplan execution will stop if the specified mailbox does not
199 exist.</para>
200 <para>The Voicemail application will exit if any of the following DTMF digits are received:</para>
201 <enumlist>
202 <enum name="0">
203 <para>Jump to the <literal>o</literal> extension in the current dialplan context.</para>
204 </enum>
205 <enum name="*">
206 <para>Jump to the <literal>a</literal> extension in the current dialplan context.</para>
207 </enum>
208 </enumlist>
209 <para>This application will set the following channel variable upon completion:</para>
210 <variablelist>
211 <variable name="VMSTATUS">
212 <para>This indicates the status of the execution of the VoiceMail application.</para>
213 <value name="SUCCESS" />
214 <value name="USEREXIT" />
215 <value name="FAILED" />
216 </variable>
217 </variablelist>
218 </description>
219 <see-also>
220 <ref type="application">VoiceMailMain</ref>
221 </see-also>
222 </application>
223 <application name="VoiceMailMain" language="en_US">
224 <synopsis>
225 Check Voicemail messages.
226 </synopsis>
227 <syntax>
228 <parameter name="mailbox" required="true" argsep="@">
229 <argument name="mailbox" />
230 <argument name="context" />
231 </parameter>
232 <parameter name="options">
233 <optionlist>
234 <option name="p">
235 <para>Consider the <replaceable>mailbox</replaceable> parameter as a prefix to
236 the mailbox that is entered by the caller.</para>
237 </option>
238 <option name="g">
239 <argument name="#" required="true" />
240 <para>Use the specified amount of gain when recording a voicemail message.
241 The units are whole-number decibels (dB).</para>
242 </option>
243 <option name="s">
244 <para>Skip checking the passcode for the mailbox.</para>
245 </option>
246 <option name="a">
247 <argument name="folder" required="true" />
248 <para>Skip folder prompt and go directly to <replaceable>folder</replaceable> specified.
249 Defaults to <literal>INBOX</literal> (or <literal>0</literal>).</para>
250 <enumlist>
251 <enum name="0"><para>INBOX</para></enum>
252 <enum name="1"><para>Old</para></enum>
253 <enum name="2"><para>Work</para></enum>
254 <enum name="3"><para>Family</para></enum>
255 <enum name="4"><para>Friends</para></enum>
256 <enum name="5"><para>Cust1</para></enum>
257 <enum name="6"><para>Cust2</para></enum>
258 <enum name="7"><para>Cust3</para></enum>
259 <enum name="8"><para>Cust4</para></enum>
260 <enum name="9"><para>Cust5</para></enum>
261 </enumlist>
262 </option>
263 </optionlist>
264 </parameter>
265 </syntax>
266 <description>
267 <para>This application allows the calling party to check voicemail messages. A specific
268 <replaceable>mailbox</replaceable>, and optional corresponding <replaceable>context</replaceable>,
269 may be specified. If a <replaceable>mailbox</replaceable> is not provided, the calling party will
270 be prompted to enter one. If a <replaceable>context</replaceable> is not specified, the
271 <literal>default</literal> context will be used.</para>
272 <para>The VoiceMailMain application will exit if the following DTMF digit is entered as Mailbox
273 or Password, and the extension exists:</para>
274 <enumlist>
275 <enum name="*">
276 <para>Jump to the <literal>a</literal> extension in the current dialplan context.</para>
277 </enum>
278 </enumlist>
279 </description>
280 <see-also>
281 <ref type="application">VoiceMail</ref>
282 </see-also>
283 </application>
284 <application name="MailboxExists" language="en_US">
285 <synopsis>
286 Check to see if Voicemail mailbox exists.
287 </synopsis>
288 <syntax>
289 <parameter name="mailbox" required="true" argsep="@">
290 <argument name="mailbox" required="true" />
291 <argument name="context" />
292 </parameter>
293 <parameter name="options">
294 <para>None options.</para>
295 </parameter>
296 </syntax>
297 <description>
298 <note><para>DEPRECATED. Use VM_INFO(mailbox[@context],exists) instead.</para></note>
299 <para>Check to see if the specified <replaceable>mailbox</replaceable> exists. If no voicemail
300 <replaceable>context</replaceable> is specified, the <literal>default</literal> context
301 will be used.</para>
302 <para>This application will set the following channel variable upon completion:</para>
303 <variablelist>
304 <variable name="VMBOXEXISTSSTATUS">
305 <para>This will contain the status of the execution of the MailboxExists application.
306 Possible values include:</para>
307 <value name="SUCCESS" />
308 <value name="FAILED" />
309 </variable>
310 </variablelist>
311 </description>
312 <see-also>
313 <ref type="function">VM_INFO</ref>
314 </see-also>
315 </application>
316 <application name="VMAuthenticate" language="en_US">
317 <synopsis>
318 Authenticate with Voicemail passwords.
319 </synopsis>
320 <syntax>
321 <parameter name="mailbox" required="true" argsep="@">
322 <argument name="mailbox" />
323 <argument name="context" />
324 </parameter>
325 <parameter name="options">
326 <optionlist>
327 <option name="s">
328 <para>Skip playing the initial prompts.</para>
329 </option>
330 </optionlist>
331 </parameter>
332 </syntax>
333 <description>
334 <para>This application behaves the same way as the Authenticate application, but the passwords
335 are taken from <filename>voicemail.conf</filename>. If the <replaceable>mailbox</replaceable> is
336 specified, only that mailbox's password will be considered valid. If the <replaceable>mailbox</replaceable>
337 is not specified, the channel variable <variable>AUTH_MAILBOX</variable> will be set with the authenticated
338 mailbox.</para>
339 <para>The VMAuthenticate application will exit if the following DTMF digit is entered as Mailbox
340 or Password, and the extension exists:</para>
341 <enumlist>
342 <enum name="*">
343 <para>Jump to the <literal>a</literal> extension in the current dialplan context.</para>
344 </enum>
345 </enumlist>
346 </description>
347 </application>
348 <application name="VoiceMailPlayMsg" language="en_US">
349 <synopsis>
350 Play a single voice mail msg from a mailbox by msg id.
351 </synopsis>
352 <syntax>
353 <parameter name="mailbox" required="true" argsep="@">
354 <argument name="mailbox" />
355 <argument name="context" />
356 </parameter>
357 <parameter name="msg_id" required="true">
358 <para>The msg id of the msg to play back. </para>
359 </parameter>
360 </syntax>
361 <description>
362 <para>This application sets the following channel variable upon completion:</para>
363 <variablelist>
364 <variable name="VOICEMAIL_PLAYBACKSTATUS">
365 <para>The status of the playback attempt as a text string.</para>
366 <value name="SUCCESS"/>
367 <value name="FAILED"/>
368 </variable>
369 </variablelist>
370 </description>
371 </application>
372 <application name="VMSayName" language="en_US">
373 <synopsis>
374 Play the name of a voicemail user
375 </synopsis>
376 <syntax>
377 <parameter name="mailbox" required="true" argsep="@">
378 <argument name="mailbox" />
379 <argument name="context" />
380 </parameter>
381 </syntax>
382 <description>
383 <para>This application will say the recorded name of the voicemail user specified as the
384 argument to this application. If no context is provided, <literal>default</literal> is assumed.</para>
385 </description>
386 </application>
387 <function name="MAILBOX_EXISTS" language="en_US">
388 <synopsis>
389 Tell if a mailbox is configured.
390 </synopsis>
391 <syntax argsep="@">
392 <parameter name="mailbox" required="true" />
393 <parameter name="context" />
394 </syntax>
395 <description>
396 <note><para>DEPRECATED. Use VM_INFO(mailbox[@context],exists) instead.</para></note>
397 <para>Returns a boolean of whether the corresponding <replaceable>mailbox</replaceable> exists.
398 If <replaceable>context</replaceable> is not specified, defaults to the <literal>default</literal>
399 context.</para>
400 </description>
401 <see-also>
402 <ref type="function">VM_INFO</ref>
403 </see-also>
404 </function>
405 <function name="VM_INFO" language="en_US">
406 <synopsis>
407 Returns the selected attribute from a mailbox.
408 </synopsis>
409 <syntax argsep=",">
410 <parameter name="mailbox" argsep="@" required="true">
411 <argument name="mailbox" required="true" />
412 <argument name="context" />
413 </parameter>
414 <parameter name="attribute" required="true">
415 <optionlist>
416 <option name="count">
417 <para>Count of messages in specified <replaceable>folder</replaceable>.
418 If <replaceable>folder</replaceable> is not specified, defaults to <literal>INBOX</literal>.</para>
419 </option>
420 <option name="email">
421 <para>E-mail address associated with the mailbox.</para>
422 </option>
423 <option name="exists">
424 <para>Returns a boolean of whether the corresponding <replaceable>mailbox</replaceable> exists.</para>
425 </option>
426 <option name="fullname">
427 <para>Full name associated with the mailbox.</para>
428 </option>
429 <option name="language">
430 <para>Mailbox language if overridden, otherwise the language of the channel.</para>
431 </option>
432 <option name="locale">
433 <para>Mailbox locale if overridden, otherwise global locale.</para>
434 </option>
435 <option name="pager">
436 <para>Pager e-mail address associated with the mailbox.</para>
437 </option>
438 <option name="password">
439 <para>Mailbox access password.</para>
440 </option>
441 <option name="tz">
442 <para>Mailbox timezone if overridden, otherwise global timezone</para>
443 </option>
444 </optionlist>
445 </parameter>
446 <parameter name="folder" required="false">
447 <para>If not specified, <literal>INBOX</literal> is assumed.</para>
448 </parameter>
449 </syntax>
450 <description>
451 <para>Returns the selected attribute from the specified <replaceable>mailbox</replaceable>.
452 If <replaceable>context</replaceable> is not specified, defaults to the <literal>default</literal>
453 context. Where the <replaceable>folder</replaceable> can be specified, common folders
454 include <literal>INBOX</literal>, <literal>Old</literal>, <literal>Work</literal>,
455 <literal>Family</literal> and <literal>Friends</literal>.</para>
456 </description>
457 </function>
458 <manager name="VoicemailUsersList" language="en_US">
459 <synopsis>
460 List All Voicemail User Information.
461 </synopsis>
462 <syntax>
463 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
464 </syntax>
465 <description>
466 </description>
467 </manager>
468 <manager name="VoicemailRefresh" language="en_US">
469 <synopsis>
470 Tell Asterisk to poll mailboxes for a change
471 </synopsis>
472 <syntax>
473 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
474 <parameter name="Context" />
475 <parameter name="Mailbox" />
476 </syntax>
477 <description>
478 <para>Normally, MWI indicators are only sent when Asterisk itself
479 changes a mailbox. With external programs that modify the content
480 of a mailbox from outside the application, an option exists called
481 <literal>pollmailboxes</literal> that will cause voicemail to
482 continually scan all mailboxes on a system for changes. This can
483 cause a large amount of load on a system. This command allows
484 external applications to signal when a particular mailbox has
485 changed, thus permitting external applications to modify mailboxes
486 and MWI to work without introducing considerable CPU load.</para>
487 <para>If <replaceable>Context</replaceable> is not specified, all
488 mailboxes on the system will be polled for changes. If
489 <replaceable>Context</replaceable> is specified, but
490 <replaceable>Mailbox</replaceable> is omitted, then all mailboxes
491 within <replaceable>Context</replaceable> will be polled.
492 Otherwise, only a single mailbox will be polled for changes.</para>
493 </description>
494 </manager>
495 ***/
496
497#ifdef IMAP_STORAGE
498static char imapserver[48];
499static char imapport[8];
500static char imapflags[128];
501static char imapfolder[64];
502static char imapparentfolder[64] = "\0";
503static char greetingfolder[64];
504static char authuser[32];
505static char authpassword[42];
506static int imapversion = 1;
507
508static int expungeonhangup = 1;
509static int imapgreetings = 0;
510static char delimiter = '\0';
511
512/* mail_open cannot be protected on a stream basis */
513ast_mutex_t mail_open_lock;
514
515struct vm_state;
516struct ast_vm_user;
517
518AST_THREADSTORAGE(ts_vmstate)static void __init_ts_vmstate(void); static struct ast_threadstorage
ts_vmstate = { .once = 0, .key_init = __init_ts_vmstate, .custom_init
= ((void*)0), }; static void __init_ts_vmstate(void) { pthread_key_create
(&(ts_vmstate).key, free); }
;
519
520/* Forward declarations for IMAP */
521static int init_mailstream(struct vm_state *vms, int box);
522static void write_file(char *filename, char *buffer, unsigned long len);
523static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len);
524static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu);
525static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len);
526static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive);
527static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive);
528static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu);
529static void vmstate_insert(struct vm_state *vms);
530static void vmstate_delete(struct vm_state *vms);
531static void set_update(MAILSTREAM * stream);
532static void init_vm_state(struct vm_state *vms);
533static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro);
534static void get_mailbox_delimiter(struct vm_state *vms, MAILSTREAM *stream);
535static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
536static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
537static int imap_store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms, const char *flag, const char *msg_id);
538static void vm_imap_update_msg_id(char *dir, int msgnum, const char *msg_id, struct ast_vm_user *vmu, struct ast_config *msg_cfg, int folder);
539static void update_messages_by_imapuser(const char *user, unsigned long number);
540static int vm_delete(char *file);
541
542static int imap_remove_file (char *dir, int msgnum);
543static int imap_retrieve_file (const char *dir, const int msgnum, const char *mailbox, const char *context);
544static int imap_delete_old_greeting (char *dir, struct vm_state *vms);
545static void check_quota(struct vm_state *vms, char *mailbox);
546static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
547struct vmstate {
548 struct vm_state *vms;
549 AST_LIST_ENTRY(vmstate)struct { struct vmstate *next; } list;
550};
551
552static AST_LIST_HEAD_STATIC(vmstates, vmstate)struct vmstates { struct vmstate *first; struct vmstate *last
; ast_mutex_t lock; } vmstates = { .first = ((void*)0), .last
= ((void*)0), .lock = { { { 0, 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP
, 0, 0, { 0, 0 } } }, ((void*)0), 1 }, }
;
553
554#endif
555
556#define SMDI_MWI_WAIT_TIMEOUT1000 1000 /* 1 second */
557
558#define COMMAND_TIMEOUT5000 5000
559/* Don't modify these here; set your umask at runtime instead */
560#define VOICEMAIL_DIR_MODE0777 0777
561#define VOICEMAIL_FILE_MODE0666 0666
562#define CHUNKSIZE65536 65536
563
564#define VOICEMAIL_CONFIG"voicemail.conf" "voicemail.conf"
565#define ASTERISK_USERNAME"asterisk" "asterisk"
566
567/* Define fast-forward, pause, restart, and reverse keys
568 * while listening to a voicemail message - these are
569 * strings, not characters */
570#define DEFAULT_LISTEN_CONTROL_FORWARD_KEY"#" "#"
571#define DEFAULT_LISTEN_CONTROL_REVERSE_KEY"*" "*"
572#define DEFAULT_LISTEN_CONTROL_PAUSE_KEY"0" "0"
573#define DEFAULT_LISTEN_CONTROL_RESTART_KEY"2" "2"
574#define DEFAULT_LISTEN_CONTROL_STOP_KEY"13456789" "13456789"
575#define VALID_DTMF"1234567890*#" "1234567890*#" /* Yes ABCD are valid dtmf but what phones have those? */
576
577/* Default mail command to mail voicemail. Change it with the
578 * mailcmd= command in voicemail.conf */
579#define SENDMAIL"/usr/sbin/sendmail -t" "/usr/sbin/sendmail -t"
580
581#define INTRO"vm-intro" "vm-intro"
582
583#define MAX_MAIL_BODY_CONTENT_SIZE134217728L 134217728L // 128 Mbyte
584
585#define MAXMSG100 100
586#define MAXMSGLIMIT9999 9999
587
588#define MINPASSWORD0 0 /*!< Default minimum mailbox password length */
589
590#define BASELINELEN72 72
591#define BASEMAXINLINE256 256
592#ifdef IMAP_STORAGE
593#define ENDL"\n" "\r\n"
594#else
595#define ENDL"\n" "\n"
596#endif
597
598#define MAX_DATETIME_FORMAT512 512
599#define MAX_NUM_CID_CONTEXTS10 10
600
601#define VM_REVIEW(1 << 0) (1 << 0) /*!< After recording, permit the caller to review the recording before saving */
602#define VM_OPERATOR(1 << 1) (1 << 1) /*!< Allow 0 to be pressed to go to 'o' extension */
603#define VM_SAYCID(1 << 2) (1 << 2) /*!< Repeat the CallerID info during envelope playback */
604#define VM_SVMAIL(1 << 3) (1 << 3) /*!< Allow the user to compose a new VM from within VoicemailMain */
605#define VM_ENVELOPE(1 << 4) (1 << 4) /*!< Play the envelope information (who-from, time received, etc.) */
606#define VM_SAYDURATION(1 << 5) (1 << 5) /*!< Play the length of the message during envelope playback */
607#define VM_SKIPAFTERCMD(1 << 6) (1 << 6) /*!< After deletion, assume caller wants to go to the next message */
608#define VM_FORCENAME(1 << 7) (1 << 7) /*!< Have new users record their name */
609#define VM_FORCEGREET(1 << 8) (1 << 8) /*!< Have new users record their greetings */
610#define VM_PBXSKIP(1 << 9) (1 << 9) /*!< Skip the [PBX] preamble in the Subject line of emails */
611#define VM_DIRECFORWARD(1 << 10) (1 << 10) /*!< Permit caller to use the Directory app for selecting to which mailbox to forward a VM */
612#define VM_ATTACH(1 << 11) (1 << 11) /*!< Attach message to voicemail notifications? */
613#define VM_DELETE(1 << 12) (1 << 12) /*!< Delete message after sending notification */
614#define VM_ALLOCED(1 << 13) (1 << 13) /*!< Structure was malloc'ed, instead of placed in a return (usually static) buffer */
615#define VM_SEARCH(1 << 14) (1 << 14) /*!< Search all contexts for a matching mailbox */
616#define VM_TEMPGREETWARN(1 << 15) (1 << 15) /*!< Remind user tempgreeting is set */
617#define VM_MOVEHEARD(1 << 16) (1 << 16) /*!< Move a "heard" message to Old after listening to it */
618#define VM_MESSAGEWRAP(1 << 17) (1 << 17) /*!< Wrap around from the last message to the first, and vice-versa */
619#define VM_FWDURGAUTO(1 << 18) (1 << 18) /*!< Autoset of Urgent flag on forwarded Urgent messages set globally */
620#define ERROR_LOCK_PATH-100 -100
621#define ERROR_MAX_MSGS-101 -101
622#define OPERATOR_EXIT300 300
623
624enum vm_box {
625 NEW_FOLDER = 0,
626 OLD_FOLDER = 1,
627 WORK_FOLDER = 2,
628 FAMILY_FOLDER = 3,
629 FRIENDS_FOLDER = 4,
630 GREETINGS_FOLDER = -1
631};
632
633enum vm_option_flags {
634 OPT_SILENT = (1 << 0),
635 OPT_BUSY_GREETING = (1 << 1),
636 OPT_UNAVAIL_GREETING = (1 << 2),
637 OPT_RECORDGAIN = (1 << 3),
638 OPT_PREPEND_MAILBOX = (1 << 4),
639 OPT_AUTOPLAY = (1 << 6),
640 OPT_DTMFEXIT = (1 << 7),
641 OPT_MESSAGE_Urgent = (1 << 8),
642 OPT_MESSAGE_PRIORITY = (1 << 9)
643};
644
645enum vm_option_args {
646 OPT_ARG_RECORDGAIN = 0,
647 OPT_ARG_PLAYFOLDER = 1,
648 OPT_ARG_DTMFEXIT = 2,
649 /* This *must* be the last value in this enum! */
650 OPT_ARG_ARRAY_SIZE = 3,
651};
652
653enum vm_passwordlocation {
654 OPT_PWLOC_VOICEMAILCONF = 0,
655 OPT_PWLOC_SPOOLDIR = 1,
656 OPT_PWLOC_USERSCONF = 2,
657};
658
659AST_APP_OPTIONS(vm_app_options, {static const struct ast_app_option vm_app_options[128] = { ['s'
] = { .flag = OPT_SILENT }, ['b'] = { .flag = OPT_BUSY_GREETING
}, ['u'] = { .flag = OPT_UNAVAIL_GREETING }, ['g'] = { .flag
= OPT_RECORDGAIN, .arg_index = OPT_ARG_RECORDGAIN + 1 }, ['d'
] = { .flag = OPT_DTMFEXIT, .arg_index = OPT_ARG_DTMFEXIT + 1
}, ['p'] = { .flag = OPT_PREPEND_MAILBOX }, ['a'] = { .flag =
OPT_AUTOPLAY, .arg_index = OPT_ARG_PLAYFOLDER + 1 }, ['U'] =
{ .flag = OPT_MESSAGE_Urgent }, ['P'] = { .flag = OPT_MESSAGE_PRIORITY
}}
660 AST_APP_OPTION('s', OPT_SILENT),static const struct ast_app_option vm_app_options[128] = { ['s'
] = { .flag = OPT_SILENT }, ['b'] = { .flag = OPT_BUSY_GREETING
}, ['u'] = { .flag = OPT_UNAVAIL_GREETING }, ['g'] = { .flag
= OPT_RECORDGAIN, .arg_index = OPT_ARG_RECORDGAIN + 1 }, ['d'
] = { .flag = OPT_DTMFEXIT, .arg_index = OPT_ARG_DTMFEXIT + 1
}, ['p'] = { .flag = OPT_PREPEND_MAILBOX }, ['a'] = { .flag =
OPT_AUTOPLAY, .arg_index = OPT_ARG_PLAYFOLDER + 1 }, ['U'] =
{ .flag = OPT_MESSAGE_Urgent }, ['P'] = { .flag = OPT_MESSAGE_PRIORITY
}}
661 AST_APP_OPTION('b', OPT_BUSY_GREETING),static const struct ast_app_option vm_app_options[128] = { ['s'
] = { .flag = OPT_SILENT }, ['b'] = { .flag = OPT_BUSY_GREETING
}, ['u'] = { .flag = OPT_UNAVAIL_GREETING }, ['g'] = { .flag
= OPT_RECORDGAIN, .arg_index = OPT_ARG_RECORDGAIN + 1 }, ['d'
] = { .flag = OPT_DTMFEXIT, .arg_index = OPT_ARG_DTMFEXIT + 1
}, ['p'] = { .flag = OPT_PREPEND_MAILBOX }, ['a'] = { .flag =
OPT_AUTOPLAY, .arg_index = OPT_ARG_PLAYFOLDER + 1 }, ['U'] =
{ .flag = OPT_MESSAGE_Urgent }, ['P'] = { .flag = OPT_MESSAGE_PRIORITY
}}
662 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),static const struct ast_app_option vm_app_options[128] = { ['s'
] = { .flag = OPT_SILENT }, ['b'] = { .flag = OPT_BUSY_GREETING
}, ['u'] = { .flag = OPT_UNAVAIL_GREETING }, ['g'] = { .flag
= OPT_RECORDGAIN, .arg_index = OPT_ARG_RECORDGAIN + 1 }, ['d'
] = { .flag = OPT_DTMFEXIT, .arg_index = OPT_ARG_DTMFEXIT + 1
}, ['p'] = { .flag = OPT_PREPEND_MAILBOX }, ['a'] = { .flag =
OPT_AUTOPLAY, .arg_index = OPT_ARG_PLAYFOLDER + 1 }, ['U'] =
{ .flag = OPT_MESSAGE_Urgent }, ['P'] = { .flag = OPT_MESSAGE_PRIORITY
}}
663 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),static const struct ast_app_option vm_app_options[128] = { ['s'
] = { .flag = OPT_SILENT }, ['b'] = { .flag = OPT_BUSY_GREETING
}, ['u'] = { .flag = OPT_UNAVAIL_GREETING }, ['g'] = { .flag
= OPT_RECORDGAIN, .arg_index = OPT_ARG_RECORDGAIN + 1 }, ['d'
] = { .flag = OPT_DTMFEXIT, .arg_index = OPT_ARG_DTMFEXIT + 1
}, ['p'] = { .flag = OPT_PREPEND_MAILBOX }, ['a'] = { .flag =
OPT_AUTOPLAY, .arg_index = OPT_ARG_PLAYFOLDER + 1 }, ['U'] =
{ .flag = OPT_MESSAGE_Urgent }, ['P'] = { .flag = OPT_MESSAGE_PRIORITY
}}
664 AST_APP_OPTION_ARG('d', OPT_DTMFEXIT, OPT_ARG_DTMFEXIT),static const struct ast_app_option vm_app_options[128] = { ['s'
] = { .flag = OPT_SILENT }, ['b'] = { .flag = OPT_BUSY_GREETING
}, ['u'] = { .flag = OPT_UNAVAIL_GREETING }, ['g'] = { .flag
= OPT_RECORDGAIN, .arg_index = OPT_ARG_RECORDGAIN + 1 }, ['d'
] = { .flag = OPT_DTMFEXIT, .arg_index = OPT_ARG_DTMFEXIT + 1
}, ['p'] = { .flag = OPT_PREPEND_MAILBOX }, ['a'] = { .flag =
OPT_AUTOPLAY, .arg_index = OPT_ARG_PLAYFOLDER + 1 }, ['U'] =
{ .flag = OPT_MESSAGE_Urgent }, ['P'] = { .flag = OPT_MESSAGE_PRIORITY
}}
665 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),static const struct ast_app_option vm_app_options[128] = { ['s'
] = { .flag = OPT_SILENT }, ['b'] = { .flag = OPT_BUSY_GREETING
}, ['u'] = { .flag = OPT_UNAVAIL_GREETING }, ['g'] = { .flag
= OPT_RECORDGAIN, .arg_index = OPT_ARG_RECORDGAIN + 1 }, ['d'
] = { .flag = OPT_DTMFEXIT, .arg_index = OPT_ARG_DTMFEXIT + 1
}, ['p'] = { .flag = OPT_PREPEND_MAILBOX }, ['a'] = { .flag =
OPT_AUTOPLAY, .arg_index = OPT_ARG_PLAYFOLDER + 1 }, ['U'] =
{ .flag = OPT_MESSAGE_Urgent }, ['P'] = { .flag = OPT_MESSAGE_PRIORITY
}}
666 AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),static const struct ast_app_option vm_app_options[128] = { ['s'
] = { .flag = OPT_SILENT }, ['b'] = { .flag = OPT_BUSY_GREETING
}, ['u'] = { .flag = OPT_UNAVAIL_GREETING }, ['g'] = { .flag
= OPT_RECORDGAIN, .arg_index = OPT_ARG_RECORDGAIN + 1 }, ['d'
] = { .flag = OPT_DTMFEXIT, .arg_index = OPT_ARG_DTMFEXIT + 1
}, ['p'] = { .flag = OPT_PREPEND_MAILBOX }, ['a'] = { .flag =
OPT_AUTOPLAY, .arg_index = OPT_ARG_PLAYFOLDER + 1 }, ['U'] =
{ .flag = OPT_MESSAGE_Urgent }, ['P'] = { .flag = OPT_MESSAGE_PRIORITY
}}
667 AST_APP_OPTION('U', OPT_MESSAGE_Urgent),static const struct ast_app_option vm_app_options[128] = { ['s'
] = { .flag = OPT_SILENT }, ['b'] = { .flag = OPT_BUSY_GREETING
}, ['u'] = { .flag = OPT_UNAVAIL_GREETING }, ['g'] = { .flag
= OPT_RECORDGAIN, .arg_index = OPT_ARG_RECORDGAIN + 1 }, ['d'
] = { .flag = OPT_DTMFEXIT, .arg_index = OPT_ARG_DTMFEXIT + 1
}, ['p'] = { .flag = OPT_PREPEND_MAILBOX }, ['a'] = { .flag =
OPT_AUTOPLAY, .arg_index = OPT_ARG_PLAYFOLDER + 1 }, ['U'] =
{ .flag = OPT_MESSAGE_Urgent }, ['P'] = { .flag = OPT_MESSAGE_PRIORITY
}}
668 AST_APP_OPTION('P', OPT_MESSAGE_PRIORITY)static const struct ast_app_option vm_app_options[128] = { ['s'
] = { .flag = OPT_SILENT }, ['b'] = { .flag = OPT_BUSY_GREETING
}, ['u'] = { .flag = OPT_UNAVAIL_GREETING }, ['g'] = { .flag
= OPT_RECORDGAIN, .arg_index = OPT_ARG_RECORDGAIN + 1 }, ['d'
] = { .flag = OPT_DTMFEXIT, .arg_index = OPT_ARG_DTMFEXIT + 1
}, ['p'] = { .flag = OPT_PREPEND_MAILBOX }, ['a'] = { .flag =
OPT_AUTOPLAY, .arg_index = OPT_ARG_PLAYFOLDER + 1 }, ['U'] =
{ .flag = OPT_MESSAGE_Urgent }, ['P'] = { .flag = OPT_MESSAGE_PRIORITY
}}
669})static const struct ast_app_option vm_app_options[128] = { ['s'
] = { .flag = OPT_SILENT }, ['b'] = { .flag = OPT_BUSY_GREETING
}, ['u'] = { .flag = OPT_UNAVAIL_GREETING }, ['g'] = { .flag
= OPT_RECORDGAIN, .arg_index = OPT_ARG_RECORDGAIN + 1 }, ['d'
] = { .flag = OPT_DTMFEXIT, .arg_index = OPT_ARG_DTMFEXIT + 1
}, ['p'] = { .flag = OPT_PREPEND_MAILBOX }, ['a'] = { .flag =
OPT_AUTOPLAY, .arg_index = OPT_ARG_PLAYFOLDER + 1 }, ['U'] =
{ .flag = OPT_MESSAGE_Urgent }, ['P'] = { .flag = OPT_MESSAGE_PRIORITY
}}
;
670
671static const char * const mailbox_folders[] = {
672#ifdef IMAP_STORAGE
673 imapfolder,
674#else
675 "INBOX",
676#endif
677 "Old",
678 "Work",
679 "Family",
680 "Friends",
681 "Cust1",
682 "Cust2",
683 "Cust3",
684 "Cust4",
685 "Cust5",
686 "Deleted",
687 "Urgent",
688};
689
690static int load_config(int reload);
691#ifdef TEST_FRAMEWORK
692static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg);
693#endif
694static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg);
695
696/*! \page vmlang Voicemail Language Syntaxes Supported
697
698 \par Syntaxes supported, not really language codes.
699 \arg \b en - English
700 \arg \b de - German
701 \arg \b es - Spanish
702 \arg \b fr - French
703 \arg \b it - Italian
704 \arg \b nl - Dutch
705 \arg \b pt - Portuguese
706 \arg \b pt_BR - Portuguese (Brazil)
707 \arg \b gr - Greek
708 \arg \b no - Norwegian
709 \arg \b se - Swedish
710 \arg \b tw - Chinese (Taiwan)
711 \arg \b ua - Ukrainian
712
713German requires the following additional soundfile:
714\arg \b 1F einE (feminine)
715
716Spanish requires the following additional soundfile:
717\arg \b 1M un (masculine)
718
719Dutch, Portuguese & Spanish require the following additional soundfiles:
720\arg \b vm-INBOXs singular of 'new'
721\arg \b vm-Olds singular of 'old/heard/read'
722
723NB these are plural:
724\arg \b vm-INBOX nieuwe (nl)
725\arg \b vm-Old oude (nl)
726
727Polish uses:
728\arg \b vm-new-a 'new', feminine singular accusative
729\arg \b vm-new-e 'new', feminine plural accusative
730\arg \b vm-new-ych 'new', feminine plural genitive
731\arg \b vm-old-a 'old', feminine singular accusative
732\arg \b vm-old-e 'old', feminine plural accusative
733\arg \b vm-old-ych 'old', feminine plural genitive
734\arg \b digits/1-a 'one', not always same as 'digits/1'
735\arg \b digits/2-ie 'two', not always same as 'digits/2'
736
737Swedish uses:
738\arg \b vm-nytt singular of 'new'
739\arg \b vm-nya plural of 'new'
740\arg \b vm-gammalt singular of 'old'
741\arg \b vm-gamla plural of 'old'
742\arg \b digits/ett 'one', not always same as 'digits/1'
743
744Norwegian uses:
745\arg \b vm-ny singular of 'new'
746\arg \b vm-nye plural of 'new'
747\arg \b vm-gammel singular of 'old'
748\arg \b vm-gamle plural of 'old'
749
750Dutch also uses:
751\arg \b nl-om 'at'?
752
753Spanish also uses:
754\arg \b vm-youhaveno
755
756Italian requires the following additional soundfile:
757
758For vm_intro_it:
759\arg \b vm-nuovo new
760\arg \b vm-nuovi new plural
761\arg \b vm-vecchio old
762\arg \b vm-vecchi old plural
763
764Japanese requires the following additional soundfile:
765\arg \b jp-arimasu there is
766\arg \b jp-arimasen there is not
767\arg \b jp-oshitekudasai please press
768\arg \b jp-ni article ni
769\arg \b jp-ga article ga
770\arg \b jp-wa article wa
771\arg \b jp-wo article wo
772
773Chinese (Taiwan) requires the following additional soundfile:
774\arg \b vm-tong A class-word for call (tong1)
775\arg \b vm-ri A class-word for day (ri4)
776\arg \b vm-you You (ni3)
777\arg \b vm-haveno Have no (mei2 you3)
778\arg \b vm-have Have (you3)
779\arg \b vm-listen To listen (yao4 ting1)
780
781
782\note Don't use vm-INBOX or vm-Old, because they are the name of the INBOX and Old folders,
783spelled among others when you have to change folder. For the above reasons, vm-INBOX
784and vm-Old are spelled plural, to make them sound more as folder name than an adjective.
785
786*/
787
788struct baseio {
789 int iocp;
790 int iolen;
791 int linelength;
792 int ateof;
793 unsigned char iobuf[BASEMAXINLINE256];
794};
795
796/*! Structure for linked list of users
797 * Use ast_vm_user_destroy() to free one of these structures. */
798struct ast_vm_user {
799 char context[AST_MAX_CONTEXT80]; /*!< Voicemail context */
800 char mailbox[AST_MAX_EXTENSION80]; /*!< Mailbox id, unique within vm context */
801 char password[80]; /*!< Secret pin code, numbers only */
802 char fullname[80]; /*!< Full name, for directory app */
803 char *email; /*!< E-mail address */
804 char *emailsubject; /*!< E-mail subject */
805 char *emailbody; /*!< E-mail body */
806 char pager[80]; /*!< E-mail address to pager (no attachment) */
807 char serveremail[80]; /*!< From: Mail address */
808 char language[MAX_LANGUAGE40]; /*!< Config: Language setting */
809 char zonetag[80]; /*!< Time zone */
810 char locale[20]; /*!< The locale (for presentation of date/time) */
811 char callback[80];
812 char dialout[80];
813 char uniqueid[80]; /*!< Unique integer identifier */
814 char exit[80];
815 char attachfmt[20]; /*!< Attachment format */
816 unsigned int flags; /*!< VM_ flags */
817 int saydurationm;
818 int minsecs; /*!< Minimum number of seconds per message for this mailbox */
819 int maxmsg; /*!< Maximum number of msgs per folder for this mailbox */
820 int maxdeletedmsg; /*!< Maximum number of deleted msgs saved for this mailbox */
821 int maxsecs; /*!< Maximum number of seconds per message for this mailbox */
822 int passwordlocation; /*!< Storage location of the password */
823#ifdef IMAP_STORAGE
824 char imapserver[48]; /*!< IMAP server address */
825 char imapport[8]; /*!< IMAP server port */
826 char imapflags[128]; /*!< IMAP optional flags */
827 char imapuser[80]; /*!< IMAP server login */
828 char imappassword[80]; /*!< IMAP server password if authpassword not defined */
829 char imapfolder[64]; /*!< IMAP voicemail folder */
830 char imapvmshareid[80]; /*!< Shared mailbox ID to use rather than the dialed one */
831 int imapversion; /*!< If configuration changes, use the new values */
832#endif
833 double volgain; /*!< Volume gain for voicemails sent via email */
834 AST_LIST_ENTRY(ast_vm_user)struct { struct ast_vm_user *next; } list;
835};
836
837/*! Voicemail time zones */
838struct vm_zone {
839 AST_LIST_ENTRY(vm_zone)struct { struct vm_zone *next; } list;
840 char name[80];
841 char timezone[80];
842 char msg_format[512];
843};
844
845#define VMSTATE_MAX_MSG_ARRAY256 256
846
847/*! Voicemail mailbox state */
848struct vm_state {
849 char curbox[80];
850 char username[80];
851 char context[80];
852 char curdir[PATH_MAX4096];
853 char vmbox[PATH_MAX4096];
854 char fn[PATH_MAX4096];
855 char intro[PATH_MAX4096];
856 int *deleted;
857 int *heard;
858 int dh_arraysize; /* used for deleted / heard allocation */
859 int curmsg;
860 int lastmsg;
861 int newmessages;
862 int oldmessages;
863 int urgentmessages;
864 int starting;
865 int repeats;
866#ifdef IMAP_STORAGE
867 ast_mutex_t lock;
868 int updated; /*!< decremented on each mail check until 1 -allows delay */
869 long *msgArray;
870 unsigned msg_array_max;
871 MAILSTREAM *mailstream;
872 int vmArrayIndex;
873 char imapuser[80]; /*!< IMAP server login */
874 char imapfolder[64]; /*!< IMAP voicemail folder */
875 char imapserver[48]; /*!< IMAP server address */
876 char imapport[8]; /*!< IMAP server port */
877 char imapflags[128]; /*!< IMAP optional flags */
878 int imapversion;
879 int interactive;
880 char introfn[PATH_MAX4096]; /*!< Name of prepended file */
881 unsigned int quota_limit;
882 unsigned int quota_usage;
883 struct vm_state *persist_vms;
884#endif
885};
886
887#ifdef ODBC_STORAGE
888static char odbc_database[80];
889static char odbc_table[80];
890#define RETRIEVE(a,b,c,d) retrieve_file(a,b)
891#define DISPOSE(a,b) remove_file(a,b)
892#define STORE(a,b,c,d,e,f,g,h,i,j,k) store_file(a,b,c,d)
893#define EXISTS(a,b,c,d)(ast_fileexists(c,((void*)0),d) > 0) (message_exists(a,b))
894#define RENAME(a,b,c,d,e,f,g,h)(rename_file(g,h)); (rename_file(a,b,c,d,e,f))
895#define COPY(a,b,c,d,e,f,g,h)(copy_plain_file(g,h)); (copy_file(a,b,c,d,e,f))
896#define DELETE(a,b,c,d)(vm_delete(c)) (delete_file(a,b))
897#define UPDATE_MSG_ID(a, b, c, d, e, f) (odbc_update_msg_id((a), (b), (c)))
898#else
899#ifdef IMAP_STORAGE
900#define DISPOSE(a,b) (imap_remove_file(a,b))
901#define STORE(a,b,c,d,e,f,g,h,i,j,k) (imap_store_file(a,b,c,d,e,f,g,h,i,j,k))
902#define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
903#define EXISTS(a,b,c,d)(ast_fileexists(c,((void*)0),d) > 0) (ast_fileexists(c,NULL((void*)0),d) > 0)
904#define RENAME(a,b,c,d,e,f,g,h)(rename_file(g,h)); (rename_file(g,h));
905#define COPY(a,b,c,d,e,f,g,h)(copy_plain_file(g,h)); (copy_file(g,h));
906#define DELETE(a,b,c,d)(vm_delete(c)) (vm_imap_delete(a,b,d))
907#define UPDATE_MSG_ID(a, b, c, d, e, f) (vm_imap_update_msg_id((a), (b), (c), (d), (e), (f)))
908#else
909#define RETRIEVE(a,b,c,d)
910#define DISPOSE(a,b)
911#define STORE(a,b,c,d,e,f,g,h,i,j,k)
912#define EXISTS(a,b,c,d)(ast_fileexists(c,((void*)0),d) > 0) (ast_fileexists(c,NULL((void*)0),d) > 0)
913#define RENAME(a,b,c,d,e,f,g,h)(rename_file(g,h)); (rename_file(g,h));
914#define COPY(a,b,c,d,e,f,g,h)(copy_plain_file(g,h)); (copy_plain_file(g,h));
915#define DELETE(a,b,c,d)(vm_delete(c)) (vm_delete(c))
916#define UPDATE_MSG_ID(a, b, c, d, e, f)
917#endif
918#endif
919
920static char VM_SPOOL_DIR[PATH_MAX4096];
921
922static char ext_pass_cmd[128];
923static char ext_pass_check_cmd[128];
924
925static int my_umask;
926
927#define PWDCHANGE_INTERNAL(1 << 1) (1 << 1)
928#define PWDCHANGE_EXTERNAL(1 << 2) (1 << 2)
929static int pwdchange = PWDCHANGE_INTERNAL(1 << 1);
930
931#ifdef ODBC_STORAGE
932#define tdesc"Comedian Mail (Voicemail System)" "Comedian Mail (Voicemail System) with ODBC Storage"
933#else
934# ifdef IMAP_STORAGE
935# define tdesc"Comedian Mail (Voicemail System)" "Comedian Mail (Voicemail System) with IMAP Storage"
936# else
937# define tdesc"Comedian Mail (Voicemail System)" "Comedian Mail (Voicemail System)"
938# endif
939#endif
940
941static char userscontext[AST_MAX_EXTENSION80] = "default";
942
943static char *addesc = "Comedian Mail";
944
945/* Leave a message */
946static char *app = "VoiceMail";
947
948/* Check mail, control, etc */
949static char *app2 = "VoiceMailMain";
950
951static char *app3 = "MailboxExists";
952static char *app4 = "VMAuthenticate";
953
954static char *playmsg_app = "VoiceMailPlayMsg";
955
956static char *sayname_app = "VMSayName";
957
958static AST_LIST_HEAD_STATIC(users, ast_vm_user)struct users { struct ast_vm_user *first; struct ast_vm_user *
last; ast_mutex_t lock; } users = { .first = ((void*)0), .last
= ((void*)0), .lock = { { { 0, 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP
, 0, 0, { 0, 0 } } }, ((void*)0), 1 }, }
;
959static AST_LIST_HEAD_STATIC(zones, vm_zone)struct zones { struct vm_zone *first; struct vm_zone *last; ast_mutex_t
lock; } zones = { .first = ((void*)0), .last = ((void*)0), .
lock = { { { 0, 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, 0, 0, { 0
, 0 } } }, ((void*)0), 1 }, }
;
960static char zonetag[80];
961static char locale[20];
962static int maxsilence;
963static int maxmsg;
964static int maxdeletedmsg;
965static int silencethreshold = 128;
966static char serveremail[80];
967static char mailcmd[160]; /* Configurable mail cmd */
968static char externnotify[160];
969static struct ast_smdi_interface *smdi_iface = NULL((void*)0);
970static char vmfmts[80];
971static double volgain;
972static int vmminsecs;
973static int vmmaxsecs;
974static int maxgreet;
975static int skipms;
976static int maxlogins;
977static int minpassword;
978static int passwordlocation;
979
980/*! Poll mailboxes for changes since there is something external to
981 * app_voicemail that may change them. */
982static unsigned int poll_mailboxes;
983
984/*! Polling frequency */
985static unsigned int poll_freq;
986/*! By default, poll every 30 seconds */
987#define DEFAULT_POLL_FREQ30 30
988
989AST_MUTEX_DEFINE_STATIC(poll_lock)static ast_mutex_t poll_lock = { { { 0, 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP
, 0, 0, { 0, 0 } } }, ((void*)0), 1 }
;
990static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER{ { 0, 0, 0, 0, 0, (void *) 0, 0, 0 } };
991static pthread_t poll_thread = AST_PTHREADT_NULL(pthread_t) -1;
992static unsigned char poll_thread_run;
993
994/*! Subscription to MWI event subscription changes */
995static struct stasis_subscription *mwi_sub_sub;
996
997/*!
998 * \brief An MWI subscription
999 *
1000 * This is so we can keep track of which mailboxes are subscribed to.
1001 * This way, we know which mailboxes to poll when the pollmailboxes
1002 * option is being used.
1003 */
1004struct mwi_sub {
1005 AST_RWLIST_ENTRY(mwi_sub)struct { struct mwi_sub *next; } entry;
1006 int old_urgent;
1007 int old_new;
1008 int old_old;
1009 char *uniqueid;
1010 char mailbox[1];
1011};
1012
1013struct mwi_sub_task {
1014 const char *mailbox;
1015 const char *context;
1016 const char *uniqueid;
1017};
1018
1019static void mwi_sub_task_dtor(struct mwi_sub_task *mwist)
1020{
1021 ast_freefree((void *) mwist->mailbox);
1022 ast_freefree((void *) mwist->context);
1023 ast_freefree((void *) mwist->uniqueid);
1024 ast_freefree(mwist);
1025}
1026
1027static struct ast_taskprocessor *mwi_subscription_tps;
1028
1029static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub)struct mwi_subs { struct mwi_sub *first; struct mwi_sub *last
; ast_rwlock_t lock; } mwi_subs = { .first = ((void*)0), .last
= ((void*)0), .lock = { { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
}, ((void*)0), 1 }, }
;
1030
1031/* custom audio control prompts for voicemail playback */
1032static char listen_control_forward_key[12];
1033static char listen_control_reverse_key[12];
1034static char listen_control_pause_key[12];
1035static char listen_control_restart_key[12];
1036static char listen_control_stop_key[12];
1037
1038/* custom password sounds */
1039static char vm_password[80] = "vm-password";
1040static char vm_newpassword[80] = "vm-newpassword";
1041static char vm_passchanged[80] = "vm-passchanged";
1042static char vm_reenterpassword[80] = "vm-reenterpassword";
1043static char vm_mismatch[80] = "vm-mismatch";
1044static char vm_invalid_password[80] = "vm-invalid-password";
1045static char vm_pls_try_again[80] = "vm-pls-try-again";
1046
1047/*
1048 * XXX If we have the time, motivation, etc. to fix up this prompt, one of the following would be appropriate:
1049 * 1. create a sound along the lines of "Please try again. When done, press the pound key" which could be spliced
1050 * from existing sound clips. This would require some programming changes in the area of vm_forward options and also
1051 * app.c's __ast_play_and_record function
1052 * 2. create a sound prompt saying "Please try again. When done recording, press any key to stop and send the prepended
1053 * message." At the time of this comment, I think this would require new voice work to be commissioned.
1054 * 3. Something way different like providing instructions before a time out or a post-recording menu. This would require
1055 * more effort than either of the other two.
1056 */
1057static char vm_prepend_timeout[80] = "vm-then-pound";
1058
1059static struct ast_flags globalflags = {0};
1060
1061static int saydurationminfo;
1062
1063static char dialcontext[AST_MAX_CONTEXT80] = "";
1064static char callcontext[AST_MAX_CONTEXT80] = "";
1065static char exitcontext[AST_MAX_CONTEXT80] = "";
1066
1067static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS10][64];
1068
1069
1070static char *emailbody = NULL((void*)0);
1071static char *emailsubject = NULL((void*)0);
1072static char *pagerbody = NULL((void*)0);
1073static char *pagersubject = NULL((void*)0);
1074static char fromstring[100];
1075static char pagerfromstring[100];
1076static char charset[32] = "ISO-8859-1";
1077
1078static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
1079static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
1080static int adsiver = 1;
1081static char emaildateformat[32] = "%A, %B %d, %Y at %r";
1082static char pagerdateformat[32] = "%A, %B %d, %Y at %r";
1083
1084/* Forward declarations - generic */
1085static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
1086static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu);
1087static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, int option, signed char record_gain);
1088static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
1089static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
1090 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
1091 signed char record_gain, struct vm_state *vms, char *flag, const char *msg_id, int forwardintro);
1092static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
1093static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
1094static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msgnum, long duration, char *fmt, char *cidnum, char *cidname, const char *flag);
1095static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap, const char *flag, const char *msg_id);
1096static void apply_options(struct ast_vm_user *vmu, const char *options);
1097static int add_email_attachment(FILE *p, struct ast_vm_user *vmu, char *format, char *attach, char *greeting_attachment, char *mailbox, char *bound, char *filename, int last, int msgnum);
1098static int is_valid_dtmf(const char *key);
1099static void read_password_from_file(const char *secretfn, char *password, int passwordlen);
1100static int write_password_to_file(const char *secretfn, const char *password);
1101static const char *substitute_escapes(const char *value);
1102static int message_range_and_existence_check(struct vm_state *vms, const char *msg_ids [], size_t num_msgs, int *msg_nums, struct ast_vm_user *vmu);
1103static void notify_new_state(struct ast_vm_user *vmu);
1104
1105/*!
1106 * Place a message in the indicated folder
1107 *
1108 * \param vmu Voicemail user
1109 * \param vms Current voicemail state for the user
1110 * \param msg The message number to save
1111 * \param box The folder into which the message should be saved
1112 * \param[out] newmsg The new message number of the saved message
1113 * \param move Tells whether to copy or to move the message
1114 *
1115 * \note the "move" parameter is only honored for IMAP voicemail presently
1116 * \retval 0 Success
1117 * \retval other Failure
1118 */
1119static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box, int *newmsg, int move);
1120
1121static struct ast_vm_mailbox_snapshot *vm_mailbox_snapshot_create(const char *mailbox, const char *context, const char *folder, int descending, enum ast_vm_snapshot_sort_val sort_val, int combine_INBOX_and_OLD);
1122static struct ast_vm_mailbox_snapshot *vm_mailbox_snapshot_destroy(struct ast_vm_mailbox_snapshot *mailbox_snapshot);
1123
1124static int vm_msg_forward(const char *from_mailbox, const char *from_context, const char *from_folder, const char *to_mailbox, const char *to_context, const char *to_folder, size_t num_msgs, const char *msg_ids[], int delete_old);
1125static int vm_msg_move(const char *mailbox, const char *context, size_t num_msgs, const char *oldfolder, const char *old_msg_ids[], const char *newfolder);
1126static int vm_msg_remove(const char *mailbox, const char *context, size_t num_msgs, const char *folder, const char *msgs[]);
1127static int vm_msg_play(struct ast_channel *chan, const char *mailbox, const char *context, const char *folder, const char *msg_num, ast_vm_msg_play_cb cb);
1128
1129#ifdef TEST_FRAMEWORK
1130static int vm_test_destroy_user(const char *context, const char *mailbox);
1131static int vm_test_create_user(const char *context, const char *mailbox);
1132#endif
1133
1134/*!
1135 * \internal
1136 * \brief Parse the given mailbox_id into mailbox and context.
1137 * \since 12.0.0
1138 *
1139 * \param mailbox_id The mailbox@context string to separate.
1140 * \param mailbox Where the mailbox part will start.
1141 * \param context Where the context part will start. ("default" if not present)
1142 *
1143 * \retval 0 on success.
1144 * \retval -1 on error.
1145 */
1146static int separate_mailbox(char *mailbox_id, char **mailbox, char **context)
1147{
1148 if (ast_strlen_zero(mailbox_id)_ast_strlen_zero(mailbox_id, "app_voicemail.c", __PRETTY_FUNCTION__
, 1148)
|| !mailbox || !context) {
1149 return -1;
1150 }
1151 *context = mailbox_id;
1152 *mailbox = strsep(context, "@");
1153 if (ast_strlen_zero(*mailbox)_ast_strlen_zero(*mailbox, "app_voicemail.c", __PRETTY_FUNCTION__
, 1153)
) {
1154 return -1;
1155 }
1156 if (ast_strlen_zero(*context)_ast_strlen_zero(*context, "app_voicemail.c", __PRETTY_FUNCTION__
, 1156)
) {
1157 *context = "default";
1158 }
1159 return 0;
1160}
1161
1162struct ao2_container *inprocess_container;
1163
1164struct inprocess {
1165 int count;
1166 char *context;
1167 char mailbox[0];
1168};
1169
1170static int inprocess_hash_fn(const void *obj, const int flags)
1171{
1172 const struct inprocess *i = obj;
1173 return atoi(i->mailbox);
1174}
1175
1176static int inprocess_cmp_fn(void *obj, void *arg, int flags)
1177{
1178 struct inprocess *i = obj, *j = arg;
1179 if (strcmp(i->mailbox, j->mailbox)) {
1180 return 0;
1181 }
1182 return !strcmp(i->context, j->context) ? CMP_MATCH : 0;
1183}
1184
1185static int inprocess_count(const char *context, const char *mailbox, int delta)
1186{
1187 struct inprocess *i, *arg = ast_alloca(sizeof(*arg) + strlen(context) + strlen(mailbox) + 2)__builtin_alloca(sizeof(*arg) + strlen(context) + strlen(mailbox
) + 2)
;
1188 arg->context = arg->mailbox + strlen(mailbox) + 1;
1189 strcpy(arg->mailbox, mailbox); /* SAFE */
1190 strcpy(arg->context, context); /* SAFE */
1191 ao2_lock(inprocess_container)__ao2_lock(inprocess_container, AO2_LOCK_REQ_MUTEX, "app_voicemail.c"
, __PRETTY_FUNCTION__, 1191, "inprocess_container")
;
1192 if ((i = ao2_find(inprocess_container, arg, 0)__ao2_find((inprocess_container), (arg), (0), "", "app_voicemail.c"
, 1192, __PRETTY_FUNCTION__)
)) {
1193 int ret = ast_atomic_fetchadd_int(&i->count, delta);
1194 ao2_unlock(inprocess_container)__ao2_unlock(inprocess_container, "app_voicemail.c", __PRETTY_FUNCTION__
, 1194, "inprocess_container")
;
1195 ao2_ref(i, -1)__ao2_ref((i), (-1), "", "app_voicemail.c", 1195, __PRETTY_FUNCTION__
)
;
1196 return ret;
1197 }
1198 if (delta < 0) {
1199 ast_log(LOG_WARNING3, "app_voicemail.c", 1199, __PRETTY_FUNCTION__, "BUG: ref count decrement on non-existing object???\n");
1200 }
1201 if (!(i = ao2_alloc(sizeof(*i) + strlen(context) + strlen(mailbox) + 2, NULL)__ao2_alloc((sizeof(*i) + strlen(context) + strlen(mailbox) +
2), (((void*)0)), AO2_ALLOC_OPT_LOCK_MUTEX, "", "app_voicemail.c"
, 1201, __PRETTY_FUNCTION__)
)) {
1202 ao2_unlock(inprocess_container)__ao2_unlock(inprocess_container, "app_voicemail.c", __PRETTY_FUNCTION__
, 1202, "inprocess_container")
;
1203 return 0;
1204 }
1205 i->context = i->mailbox + strlen(mailbox) + 1;
1206 strcpy(i->mailbox, mailbox); /* SAFE */
1207 strcpy(i->context, context); /* SAFE */
1208 i->count = delta;
1209 ao2_link(inprocess_container, i)__ao2_link((inprocess_container), (i), 0, "", "app_voicemail.c"
, 1209, __PRETTY_FUNCTION__)
;
1210 ao2_unlock(inprocess_container)__ao2_unlock(inprocess_container, "app_voicemail.c", __PRETTY_FUNCTION__
, 1210, "inprocess_container")
;
1211 ao2_ref(i, -1)__ao2_ref((i), (-1), "", "app_voicemail.c", 1211, __PRETTY_FUNCTION__
)
;
1212 return 0;
1213}
1214
1215#if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
1216static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
1217#endif
1218
1219/*!
1220 * \brief Strips control and non 7-bit clean characters from input string.
1221 *
1222 * \note To map control and none 7-bit characters to a 7-bit clean characters
1223 * please use ast_str_encode_mine().
1224 */
1225static char *strip_control_and_high(const char *input, char *buf, size_t buflen)
1226{
1227 char *bufptr = buf;
1228 for (; *input; input++) {
1229 if (*input < 32) {
1230 continue;
1231 }
1232 *bufptr++ = *input;
1233 if (bufptr == buf + buflen - 1) {
1234 break;
1235 }
1236 }
1237 *bufptr = '\0';
1238 return buf;
1239}
1240
1241
1242/*!
1243 * \brief Sets default voicemail system options to a voicemail user.
1244 *
1245 * This applies select global settings to a newly created (dynamic) instance of a voicemail user.
1246 * - all the globalflags
1247 * - the saydurationminfo
1248 * - the callcontext
1249 * - the dialcontext
1250 * - the exitcontext
1251 * - vmmaxsecs, vmmaxmsg, maxdeletedmsg
1252 * - volume gain.
1253 * - emailsubject, emailbody set to NULL
1254 */
1255static void populate_defaults(struct ast_vm_user *vmu)
1256{
1257 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL)do { typeof ((vmu)->flags) __d = (vmu)->flags; typeof (
((&globalflags))->flags) __s = ((&globalflags))->
flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void) (&
__d == &__x); (void) (&__s == &__x); (vmu)->flags
&= ~((2147483647 *2U +1U)); (vmu)->flags |= (((&globalflags
))->flags & ((2147483647 *2U +1U))); } while (0)
;
1258 vmu->passwordlocation = passwordlocation;
1259 if (saydurationminfo) {
1260 vmu->saydurationm = saydurationminfo;
1261 }
1262 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
1263 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
1264 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
1265 ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
1266 ast_copy_string(vmu->locale, locale, sizeof(vmu->locale));
1267 if (vmminsecs) {
1268 vmu->minsecs = vmminsecs;
1269 }
1270 if (vmmaxsecs) {
1271 vmu->maxsecs = vmmaxsecs;
1272 }
1273 if (maxmsg) {
1274 vmu->maxmsg = maxmsg;
1275 }
1276 if (maxdeletedmsg) {
1277 vmu->maxdeletedmsg = maxdeletedmsg;
1278 }
1279 vmu->volgain = volgain;
1280 ast_freefree(vmu->email);
1281 vmu->email = NULL((void*)0);
1282 ast_freefree(vmu->emailsubject);
1283 vmu->emailsubject = NULL((void*)0);
1284 ast_freefree(vmu->emailbody);
1285 vmu->emailbody = NULL((void*)0);
1286#ifdef IMAP_STORAGE
1287 ast_copy_string(vmu->imapfolder, imapfolder, sizeof(vmu->imapfolder));
1288 ast_copy_string(vmu->imapserver, imapserver, sizeof(vmu->imapserver));
1289 ast_copy_string(vmu->imapport, imapport, sizeof(vmu->imapport));
1290 ast_copy_string(vmu->imapflags, imapflags, sizeof(vmu->imapflags));
1291#endif
1292}
1293
1294/*!
1295 * \brief Sets a a specific property value.
1296 * \param vmu The voicemail user object to work with.
1297 * \param var The name of the property to be set.
1298 * \param value The value to be set to the property.
1299 *
1300 * The property name must be one of the understood properties. See the source for details.
1301 */
1302static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
1303{
1304 int x;
1305 if (!strcasecmp(var, "attach")) {
1306 ast_set2_flag(vmu, ast_true(value), VM_ATTACH)do { typeof ((vmu)->flags) __p = (vmu)->flags; typeof (
__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); if (ast_true(value)) (vmu)->flags |= ((1 << 11
)); else (vmu)->flags &= ~((1 << 11)); } while (
0)
;
1307 } else if (!strcasecmp(var, "attachfmt")) {
1308 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
1309 } else if (!strcasecmp(var, "serveremail")) {
1310 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
1311 } else if (!strcasecmp(var, "emailbody")) {
1312 ast_freefree(vmu->emailbody);
1313 vmu->emailbody = ast_strdup(substitute_escapes(value))_ast_strdup((substitute_escapes(value)), "app_voicemail.c", 1313
, __PRETTY_FUNCTION__)
;
1314 } else if (!strcasecmp(var, "emailsubject")) {
1315 ast_freefree(vmu->emailsubject);
1316 vmu->emailsubject = ast_strdup(substitute_escapes(value))_ast_strdup((substitute_escapes(value)), "app_voicemail.c", 1316
, __PRETTY_FUNCTION__)
;
1317 } else if (!strcasecmp(var, "language")) {
1318 ast_copy_string(vmu->language, value, sizeof(vmu->language));
1319 } else if (!strcasecmp(var, "tz")) {
1320 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
1321 } else if (!strcasecmp(var, "locale")) {
1322 ast_copy_string(vmu->locale, value, sizeof(vmu->locale));
1323#ifdef IMAP_STORAGE
1324 } else if (!strcasecmp(var, "imapuser")) {
1325 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
1326 vmu->imapversion = imapversion;
1327 } else if (!strcasecmp(var, "imapserver")) {
1328 ast_copy_string(vmu->imapserver, value, sizeof(vmu->imapserver));
1329 vmu->imapversion = imapversion;
1330 } else if (!strcasecmp(var, "imapport")) {
1331 ast_copy_string(vmu->imapport, value, sizeof(vmu->imapport));
1332 vmu->imapversion = imapversion;
1333 } else if (!strcasecmp(var, "imapflags")) {
1334 ast_copy_string(vmu->imapflags, value, sizeof(vmu->imapflags));
1335 vmu->imapversion = imapversion;
1336 } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
1337 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
1338 vmu->imapversion = imapversion;
1339 } else if (!strcasecmp(var, "imapfolder")) {
1340 ast_copy_string(vmu->imapfolder, value, sizeof(vmu->imapfolder));
1341 vmu->imapversion = imapversion;
1342 } else if (!strcasecmp(var, "imapvmshareid")) {
1343 ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
1344 vmu->imapversion = imapversion;
1345#endif
1346 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
1347 ast_set2_flag(vmu, ast_true(value), VM_DELETE)do { typeof ((vmu)->flags) __p = (vmu)->flags; typeof (
__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); if (ast_true(value)) (vmu)->flags |= ((1 << 12
)); else (vmu)->flags &= ~((1 << 12)); } while (
0)
;
1348 } else if (!strcasecmp(var, "saycid")){
1349 ast_set2_flag(vmu, ast_true(value), VM_SAYCID)do { typeof ((vmu)->flags) __p = (vmu)->flags; typeof (
__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); if (ast_true(value)) (vmu)->flags |= ((1 << 2)
); else (vmu)->flags &= ~((1 << 2)); } while (0)
;
1350 } else if (!strcasecmp(var, "sendvoicemail")){
1351 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL)do { typeof ((vmu)->flags) __p = (vmu)->flags; typeof (
__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); if (ast_true(value)) (vmu)->flags |= ((1 << 3)
); else (vmu)->flags &= ~((1 << 3)); } while (0)
;
1352 } else if (!strcasecmp(var, "review")){
1353 ast_set2_flag(vmu, ast_true(value), VM_REVIEW)do { typeof ((vmu)->flags) __p = (vmu)->flags; typeof (
__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); if (ast_true(value)) (vmu)->flags |= ((1 << 0)
); else (vmu)->flags &= ~((1 << 0)); } while (0)
;
1354 } else if (!strcasecmp(var, "tempgreetwarn")){
1355 ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN)do { typeof ((vmu)->flags) __p = (vmu)->flags; typeof (
__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); if (ast_true(value)) (vmu)->flags |= ((1 << 15
)); else (vmu)->flags &= ~((1 << 15)); } while (
0)
;
1356 } else if (!strcasecmp(var, "messagewrap")){
1357 ast_set2_flag(vmu, ast_true(value), VM_MESSAGEWRAP)do { typeof ((vmu)->flags) __p = (vmu)->flags; typeof (
__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); if (ast_true(value)) (vmu)->flags |= ((1 << 17
)); else (vmu)->flags &= ~((1 << 17)); } while (
0)
;
1358 } else if (!strcasecmp(var, "operator")) {
1359 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR)do { typeof ((vmu)->flags) __p = (vmu)->flags; typeof (
__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); if (ast_true(value)) (vmu)->flags |= ((1 << 1)
); else (vmu)->flags &= ~((1 << 1)); } while (0)
;
1360 } else if (!strcasecmp(var, "envelope")){
1361 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE)do { typeof ((vmu)->flags) __p = (vmu)->flags; typeof (
__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); if (ast_true(value)) (vmu)->flags |= ((1 << 4)
); else (vmu)->flags &= ~((1 << 4)); } while (0)
;
1362 } else if (!strcasecmp(var, "moveheard")){
1363 ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD)do { typeof ((vmu)->flags) __p = (vmu)->flags; typeof (
__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); if (ast_true(value)) (vmu)->flags |= ((1 << 16
)); else (vmu)->flags &= ~((1 << 16)); } while (
0)
;
1364 } else if (!strcasecmp(var, "sayduration")){
1365 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION)do { typeof ((vmu)->flags) __p = (vmu)->flags; typeof (
__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); if (ast_true(value)) (vmu)->flags |= ((1 << 5)
); else (vmu)->flags &= ~((1 << 5)); } while (0)
;
1366 } else if (!strcasecmp(var, "saydurationm")){
1367 if (sscanf(value, "%30d", &x) == 1) {
1368 vmu->saydurationm = x;
1369 } else {
1370 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 1370, __PRETTY_FUNCTION__, "Invalid min duration for say duration\n");
1371 }
1372 } else if (!strcasecmp(var, "forcename")){
1373 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME)do { typeof ((vmu)->flags) __p = (vmu)->flags; typeof (
__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); if (ast_true(value)) (vmu)->flags |= ((1 << 7)
); else (vmu)->flags &= ~((1 << 7)); } while (0)
;
1374 } else if (!strcasecmp(var, "forcegreetings")){
1375 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET)do { typeof ((vmu)->flags) __p = (vmu)->flags; typeof (
__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); if (ast_true(value)) (vmu)->flags |= ((1 << 8)
); else (vmu)->flags &= ~((1 << 8)); } while (0)
;
1376 } else if (!strcasecmp(var, "callback")) {
1377 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
1378 } else if (!strcasecmp(var, "dialout")) {
1379 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
1380 } else if (!strcasecmp(var, "exitcontext")) {
1381 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
1382 } else if (!strcasecmp(var, "minsecs")) {
1383 if (sscanf(value, "%30d", &x) == 1 && x >= 0) {
1384 vmu->minsecs = x;
1385 } else {
1386 ast_log(LOG_WARNING3, "app_voicemail.c", 1386, __PRETTY_FUNCTION__, "Invalid min message length of %s. Using global value %d\n", value, vmminsecs);
1387 vmu->minsecs = vmminsecs;
1388 }
1389 } else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
1390 vmu->maxsecs = atoi(value);
1391 if (vmu->maxsecs <= 0) {
1392 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 1392, __PRETTY_FUNCTION__, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
1393 vmu->maxsecs = vmmaxsecs;
1394 } else {
1395 vmu->maxsecs = atoi(value);
1396 }
1397 if (!strcasecmp(var, "maxmessage"))
1398 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 1398, __PRETTY_FUNCTION__, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
1399 } else if (!strcasecmp(var, "maxmsg")) {
1400 vmu->maxmsg = atoi(value);
1401 /* Accept maxmsg=0 (Greetings only voicemail) */
1402 if (vmu->maxmsg < 0) {
1403 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 1403, __PRETTY_FUNCTION__, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG100);
1404 vmu->maxmsg = MAXMSG100;
1405 } else if (vmu->maxmsg > MAXMSGLIMIT9999) {
1406 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 1406, __PRETTY_FUNCTION__, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT9999, value);
1407 vmu->maxmsg = MAXMSGLIMIT9999;
1408 }
1409 } else if (!strcasecmp(var, "nextaftercmd")) {
1410 ast_set2_flag(vmu, ast_true(value), VM_SKIPAFTERCMD)do { typeof ((vmu)->flags) __p = (vmu)->flags; typeof (
__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); if (ast_true(value)) (vmu)->flags |= ((1 << 6)
); else (vmu)->flags &= ~((1 << 6)); } while (0)
;
1411 } else if (!strcasecmp(var, "backupdeleted")) {
1412 if (sscanf(value, "%30d", &x) == 1)
1413 vmu->maxdeletedmsg = x;
1414 else if (ast_true(value))
1415 vmu->maxdeletedmsg = MAXMSG100;
1416 else
1417 vmu->maxdeletedmsg = 0;
1418
1419 if (vmu->maxdeletedmsg < 0) {
1420 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 1420, __PRETTY_FUNCTION__, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG100);
1421 vmu->maxdeletedmsg = MAXMSG100;
1422 } else if (vmu->maxdeletedmsg > MAXMSGLIMIT9999) {
1423 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 1423, __PRETTY_FUNCTION__, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT9999, value);
1424 vmu->maxdeletedmsg = MAXMSGLIMIT9999;
1425 }
1426 } else if (!strcasecmp(var, "volgain")) {
1427 sscanf(value, "%30lf", &vmu->volgain);
1428 } else if (!strcasecmp(var, "passwordlocation")) {
1429 if (!strcasecmp(value, "spooldir")) {
1430 vmu->passwordlocation = OPT_PWLOC_SPOOLDIR;
1431 } else {
1432 vmu->passwordlocation = OPT_PWLOC_VOICEMAILCONF;
1433 }
1434 } else if (!strcasecmp(var, "options")) {
1435 apply_options(vmu, value);
1436 }
1437}
1438
1439static char *vm_check_password_shell(char *command, char *buf, size_t len)
1440{
1441 int fds[2], pid = 0;
1442
1443 memset(buf, 0, len);
1444
1445 if (pipe(fds)) {
1446 snprintf(buf, len, "FAILURE: Pipe failed: %s", strerror(errno(*__errno_location ())));
1447 } else {
1448 /* good to go*/
1449 pid = ast_safe_fork(0);
1450
1451 if (pid < 0) {
1452 /* ok maybe not */
1453 close(fds[0]);
1454 close(fds[1]);
1455 snprintf(buf, len, "FAILURE: Fork failed");
1456 } else if (pid) {
1457 /* parent */
1458 close(fds[1]);
1459 if (read(fds[0], buf, len) < 0) {
1460 ast_log(LOG_WARNING3, "app_voicemail.c", 1460, __PRETTY_FUNCTION__, "read() failed: %s\n", strerror(errno(*__errno_location ())));
1461 }
1462 close(fds[0]);
1463 } else {
1464 /* child */
1465 AST_DECLARE_APP_ARGS(arg,struct { unsigned int argc; char *argv[0]; char *v[20]; } arg
= { 0, }
1466 AST_APP_ARG(v)[20];struct { unsigned int argc; char *argv[0]; char *v[20]; } arg
= { 0, }
1467 )struct { unsigned int argc; char *argv[0]; char *v[20]; } arg
= { 0, }
;
1468 char *mycmd = ast_strdupa(command)(__extension__ ({ const char *__old = (command); size_t __len
= strlen(__old) + 1; char *__new = __builtin_alloca(__len); memcpy
(__new, __old, __len); __new; }))
;
1469
1470 close(fds[0]);
1471 dup2(fds[1], STDOUT_FILENO1);
1472 close(fds[1]);
1473 ast_close_fds_above_n(STDOUT_FILENO1);
1474
1475 AST_NONSTANDARD_APP_ARGS(arg, mycmd, ' ')arg.argc = __ast_app_separate_args(mycmd, ' ', 1, arg.argv, (
(sizeof(arg) - __builtin_offsetof(typeof(arg), argv)) / sizeof
(arg.argv[0])))
;
1476
1477 execv(arg.v[0], arg.v);
1478 printf("FAILURE: %s", strerror(errno(*__errno_location ())));
1479 _exit(0);
1480 }
1481 }
1482 return buf;
1483}
1484
1485/*!
1486 * \brief Check that password meets minimum required length
1487 * \param vmu The voicemail user to change the password for.
1488 * \param password The password string to check
1489 *
1490 * \return zero on ok, 1 on not ok.
1491 */
1492static int check_password(struct ast_vm_user *vmu, char *password)
1493{
1494 /* check minimum length */
1495 if (strlen(password) < minpassword)
1496 return 1;
1497 /* check that password does not contain '*' character */
1498 if (!ast_strlen_zero(password)_ast_strlen_zero(password, "app_voicemail.c", __PRETTY_FUNCTION__
, 1498)
&& password[0] == '*')
1499 return 1;
1500 if (!ast_strlen_zero(ext_pass_check_cmd)_ast_strlen_zero(ext_pass_check_cmd, "app_voicemail.c", __PRETTY_FUNCTION__
, 1500)
) {
1501 char cmd[255], buf[255];
1502
1503 ast_debug(1, "Verify password policies for %s\n", password)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 1503, __PRETTY_FUNCTION__, "Verify password policies for %s\n"
, password); } } while (0)
;
1504
1505 snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
1506 if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
1507 ast_debug(5, "Result: %s\n", buf)do { if ((option_debug >= (5) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (5)))) { ast_log
(0, "app_voicemail.c", 1507, __PRETTY_FUNCTION__, "Result: %s\n"
, buf); } } while (0)
;
1508 if (!strncasecmp(buf, "VALID", 5)) {
1509 ast_debug(3, "Passed password check: '%s'\n", buf)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 1509, __PRETTY_FUNCTION__, "Passed password check: '%s'\n"
, buf); } } while (0)
;
1510 return 0;
1511 } else if (!strncasecmp(buf, "FAILURE", 7)) {
1512 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 1512, __PRETTY_FUNCTION__, "Unable to execute password validation script: '%s'.\n", buf);
1513 return 0;
1514 } else {
1515 ast_log(AST_LOG_NOTICE2, "app_voicemail.c", 1515, __PRETTY_FUNCTION__, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
1516 return 1;
1517 }
1518 }
1519 }
1520 return 0;
1521}
1522
1523/*!
1524 * \brief Performs a change of the voicemail passowrd in the realtime engine.
1525 * \param vmu The voicemail user to change the password for.
1526 * \param password The new value to be set to the password for this user.
1527 *
1528 * This only works if there is a realtime engine configured.
1529 * This is called from the (top level) vm_change_password.
1530 *
1531 * \return zero on success, -1 on error.
1532 */
1533static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
1534{
1535 int res = -1;
1536 if (!strcmp(vmu->password, password)) {
1537 /* No change (but an update would return 0 rows updated, so we opt out here) */
1538 return 0;
1539 }
1540
1541 if (strlen(password) > 10) {
1542 ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL((char *)((void*)0)));
1543 }
1544 if (ast_update2_realtime("voicemail", "context", vmu->context, "mailbox", vmu->mailbox, SENTINEL((char *)((void*)0)), "password", password, SENTINEL((char *)((void*)0))) > 0) {
1545 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: realtime engine updated with new password\r\nPasswordSource: realtime");
1546 ast_copy_string(vmu->password, password, sizeof(vmu->password));
1547 res = 0;
1548 }
1549 return res;
1550}
1551
1552/*!
1553 * \brief Destructively Parse options and apply.
1554 */
1555static void apply_options(struct ast_vm_user *vmu, const char *options)
1556{
1557 char *stringp;
1558 char *s;
1559 char *var, *value;
1560 stringp = ast_strdupa(options)(__extension__ ({ const char *__old = (options); size_t __len
= strlen(__old) + 1; char *__new = __builtin_alloca(__len); memcpy
(__new, __old, __len); __new; }))
;
1561 while ((s = strsep(&stringp, "|"))) {
1562 value = s;
1563 if ((var = strsep(&value, "=")) && value) {
1564 apply_option(vmu, var, value);
1565 }
1566 }
1567}
1568
1569/*!
1570 * \brief Loads the options specific to a voicemail user.
1571 *
1572 * This is called when a vm_user structure is being set up, such as from load_options.
1573 */
1574static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
1575{
1576 for (; var; var = var->next) {
1577 if (!strcasecmp(var->name, "vmsecret")) {
1578 ast_copy_string(retval->password, var->value, sizeof(retval->password));
1579 } else if (!strcasecmp(var->name, "secret") || !strcasecmp(var->name, "password")) { /* don't overwrite vmsecret if it exists */
1580 if (ast_strlen_zero(retval->password)_ast_strlen_zero(retval->password, "app_voicemail.c", __PRETTY_FUNCTION__
, 1580)
) {
1581 if (!ast_strlen_zero(var->value)_ast_strlen_zero(var->value, "app_voicemail.c", __PRETTY_FUNCTION__
, 1581)
&& var->value[0] == '*') {
1582 ast_log(LOG_WARNING3, "app_voicemail.c", 1582, __PRETTY_FUNCTION__, "Invalid password detected for mailbox %s. The password"
1583 "\n\tmust be reset in voicemail.conf.\n", retval->mailbox);
1584 } else {
1585 ast_copy_string(retval->password, var->value, sizeof(retval->password));
1586 }
1587 }
1588 } else if (!strcasecmp(var->name, "uniqueid")) {
1589 ast_copy_string(retval->uniqueid, var->value, sizeof(retval->uniqueid));
1590 } else if (!strcasecmp(var->name, "pager")) {
1591 ast_copy_string(retval->pager, var->value, sizeof(retval->pager));
1592 } else if (!strcasecmp(var->name, "email")) {
1593 ast_freefree(retval->email);
1594 retval->email = ast_strdup(var->value)_ast_strdup((var->value), "app_voicemail.c", 1594, __PRETTY_FUNCTION__
)
;
1595 } else if (!strcasecmp(var->name, "fullname")) {
1596 ast_copy_string(retval->fullname, var->value, sizeof(retval->fullname));
1597 } else if (!strcasecmp(var->name, "context")) {
1598 ast_copy_string(retval->context, var->value, sizeof(retval->context));
1599 } else if (!strcasecmp(var->name, "emailsubject")) {
1600 ast_freefree(retval->emailsubject);
1601 retval->emailsubject = ast_strdup(substitute_escapes(var->value))_ast_strdup((substitute_escapes(var->value)), "app_voicemail.c"
, 1601, __PRETTY_FUNCTION__)
;
1602 } else if (!strcasecmp(var->name, "emailbody")) {
1603 ast_freefree(retval->emailbody);
1604 retval->emailbody = ast_strdup(substitute_escapes(var->value))_ast_strdup((substitute_escapes(var->value)), "app_voicemail.c"
, 1604, __PRETTY_FUNCTION__)
;
1605#ifdef IMAP_STORAGE
1606 } else if (!strcasecmp(var->name, "imapuser")) {
1607 ast_copy_string(retval->imapuser, var->value, sizeof(retval->imapuser));
1608 retval->imapversion = imapversion;
1609 } else if (!strcasecmp(var->name, "imapserver")) {
1610 ast_copy_string(retval->imapserver, var->value, sizeof(retval->imapserver));
1611 retval->imapversion = imapversion;
1612 } else if (!strcasecmp(var->name, "imapport")) {
1613 ast_copy_string(retval->imapport, var->value, sizeof(retval->imapport));
1614 retval->imapversion = imapversion;
1615 } else if (!strcasecmp(var->name, "imapflags")) {
1616 ast_copy_string(retval->imapflags, var->value, sizeof(retval->imapflags));
1617 retval->imapversion = imapversion;
1618 } else if (!strcasecmp(var->name, "imappassword") || !strcasecmp(var->name, "imapsecret")) {
1619 ast_copy_string(retval->imappassword, var->value, sizeof(retval->imappassword));
1620 retval->imapversion = imapversion;
1621 } else if (!strcasecmp(var->name, "imapfolder")) {
1622 ast_copy_string(retval->imapfolder, var->value, sizeof(retval->imapfolder));
1623 retval->imapversion = imapversion;
1624 } else if (!strcasecmp(var->name, "imapvmshareid")) {
1625 ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
1626 retval->imapversion = imapversion;
1627#endif
1628 } else
1629 apply_option(retval, var->name, var->value);
1630 }
1631}
1632
1633/*!
1634 * \brief Determines if a DTMF key entered is valid.
1635 * \param key The character to be compared. expects a single character. Though is capable of handling a string, this is internally copies using ast_strdupa.
1636 *
1637 * Tests the character entered against the set of valid DTMF characters.
1638 * \return 1 if the character entered is a valid DTMF digit, 0 if the character is invalid.
1639 */
1640static int is_valid_dtmf(const char *key)
1641{
1642 int i;
1643 char *local_key = ast_strdupa(key)(__extension__ ({ const char *__old = (key); size_t __len = strlen
(__old) + 1; char *__new = __builtin_alloca(__len); memcpy (__new
, __old, __len); __new; }))
;
1644
1645 for (i = 0; i < strlen(key); ++i) {
1646 if (!strchr(VALID_DTMF, *local_key)(__extension__ (__builtin_constant_p (*local_key) && !
__builtin_constant_p ("1234567890*#") && (*local_key)
== '\0' ? (char *) __rawmemchr ("1234567890*#", *local_key) :
__builtin_strchr ("1234567890*#", *local_key)))
) {
1647 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 1647, __PRETTY_FUNCTION__, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
1648 return 0;
1649 }
1650 local_key++;
1651 }
1652 return 1;
1653}
1654
1655/*!
1656 * \brief Finds a voicemail user from the realtime engine.
1657 * \param ivm
1658 * \param context
1659 * \param mailbox
1660 *
1661 * This is called as a fall through case when the normal find_user() was not able to find a user. That is, the default it so look in the usual voicemail users file first.
1662 *
1663 * \return The ast_vm_user structure for the user that was found.
1664 */
1665static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
1666{
1667 struct ast_variable *var;
1668 struct ast_vm_user *retval;
1669
1670 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))_ast_calloc((1), (sizeof(*retval)), "app_voicemail.c", 1670, __PRETTY_FUNCTION__
)
))) {
1671 if (ivm) {
1672 memset(retval, 0, sizeof(*retval));
1673 }
1674 populate_defaults(retval);
1675 if (!ivm) {
1676 ast_set_flag(retval, VM_ALLOCED)do { typeof ((retval)->flags) __p = (retval)->flags; typeof
(__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); ((retval)->flags |= ((1 << 13))); } while(0)
;
1677 }
1678 if (mailbox) {
1679 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
1680 }
1681 if (!context && ast_test_flag((&globalflags), VM_SEARCH)({ typeof (((&globalflags))->flags) __p = ((&globalflags
))->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); (((&globalflags))->flags &
((1 << 14))); })
) {
1682 var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL((char *)((void*)0)));
1683 } else {
1684 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL((char *)((void*)0)));
1685 }
1686 if (var) {
1687 apply_options_full(retval, var);
1688 ast_variables_destroy(var);
1689 } else {
1690 if (!ivm)
1691 ast_freefree(retval);
1692 retval = NULL((void*)0);
1693 }
1694 }
1695 return retval;
1696}
1697
1698/*!
1699 * \brief Finds a voicemail user from the users file or the realtime engine.
1700 * \param ivm
1701 * \param context
1702 * \param mailbox
1703 *
1704 * \return The ast_vm_user structure for the user that was found.
1705 */
1706static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
1707{
1708 /* This function could be made to generate one from a database, too */
1709 struct ast_vm_user *vmu = NULL((void*)0), *cur;
1710 AST_LIST_LOCK(&users)__ast_pthread_mutex_lock("app_voicemail.c", 1710, __PRETTY_FUNCTION__
, "&(&users)->lock", &(&users)->lock)
;
1711
1712 if (!context && !ast_test_flag((&globalflags), VM_SEARCH)({ typeof (((&globalflags))->flags) __p = ((&globalflags
))->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); (((&globalflags))->flags &
((1 << 14))); })
)
1713 context = "default";
1714
1715 AST_LIST_TRAVERSE(&users, cur, list)for((cur) = (&users)->first; (cur); (cur) = (cur)->
list.next)
{
1716#ifdef IMAP_STORAGE
1717 if (cur->imapversion != imapversion) {
1718 continue;
1719 }
1720#endif
1721 if (ast_test_flag((&globalflags), VM_SEARCH)({ typeof (((&globalflags))->flags) __p = ((&globalflags
))->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); (((&globalflags))->flags &
((1 << 14))); })
&& !strcasecmp(mailbox, cur->mailbox))
1722 break;
1723 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
1724 break;
1725 }
1726 if (cur) {
1727 /* Make a copy, so that on a reload, we have no race */
1728 if ((vmu = (ivm ? ivm : ast_calloc(1, sizeof(*vmu))_ast_calloc((1), (sizeof(*vmu)), "app_voicemail.c", 1728, __PRETTY_FUNCTION__
)
))) {
1729 ast_freefree(vmu->email);
1730 ast_freefree(vmu->emailbody);
1731 ast_freefree(vmu->emailsubject);
1732 *vmu = *cur;
1733 vmu->email = ast_strdup(cur->email)_ast_strdup((cur->email), "app_voicemail.c", 1733, __PRETTY_FUNCTION__
)
;
1734 vmu->emailbody = ast_strdup(cur->emailbody)_ast_strdup((cur->emailbody), "app_voicemail.c", 1734, __PRETTY_FUNCTION__
)
;
1735 vmu->emailsubject = ast_strdup(cur->emailsubject)_ast_strdup((cur->emailsubject), "app_voicemail.c", 1735, __PRETTY_FUNCTION__
)
;
1736 ast_set2_flag(vmu, !ivm, VM_ALLOCED)do { typeof ((vmu)->flags) __p = (vmu)->flags; typeof (
__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); if (!ivm) (vmu)->flags |= ((1 << 13)); else (vmu
)->flags &= ~((1 << 13)); } while (0)
;
1737 AST_LIST_NEXT(vmu, list)((vmu)->list.next) = NULL((void*)0);
1738 }
1739 } else
1740 vmu = find_user_realtime(ivm, context, mailbox);
1741 AST_LIST_UNLOCK(&users)__ast_pthread_mutex_unlock("app_voicemail.c", 1741, __PRETTY_FUNCTION__
, "&(&users)->lock", &(&users)->lock)
;
1742 return vmu;
1743}
1744
1745/*!
1746 * \brief Resets a user password to a specified password.
1747 * \param context
1748 * \param mailbox
1749 * \param newpass
1750 *
1751 * This does the actual change password work, called by the vm_change_password() function.
1752 *
1753 * \return zero on success, -1 on error.
1754 */
1755static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
1756{
1757 /* This function could be made to generate one from a database, too */
1758 struct ast_vm_user *cur;
1759 int res = -1;
1760 AST_LIST_LOCK(&users)__ast_pthread_mutex_lock("app_voicemail.c", 1760, __PRETTY_FUNCTION__
, "&(&users)->lock", &(&users)->lock)
;
1761 AST_LIST_TRAVERSE(&users, cur, list)for((cur) = (&users)->first; (cur); (cur) = (cur)->
list.next)
{
1762 if ((!context || !strcasecmp(context, cur->context)) &&
1763 (!strcasecmp(mailbox, cur->mailbox)))
1764 break;
1765 }
1766 if (cur) {
1767 ast_copy_string(cur->password, newpass, sizeof(cur->password));
1768 res = 0;
1769 }
1770 AST_LIST_UNLOCK(&users)__ast_pthread_mutex_unlock("app_voicemail.c", 1770, __PRETTY_FUNCTION__
, "&(&users)->lock", &(&users)->lock)
;
1771 return res;
1772}
1773
1774/*!
1775 * \brief Check if configuration file is valid
1776 */
1777static inline int valid_config(const struct ast_config *cfg)
1778{
1779 return cfg && cfg != CONFIG_STATUS_FILEINVALID(void *)-2;
1780}
1781
1782/*!
1783 * \brief The handler for the change password option.
1784 * \param vmu The voicemail user to work with.
1785 * \param newpassword The new password (that has been gathered from the appropriate prompting).
1786 * This is called when a new user logs in for the first time and the option to force them to change their password is set.
1787 * It is also called when the user wants to change their password from menu option '5' on the mailbox options menu.
1788 */
1789static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
1790{
1791 struct ast_config *cfg = NULL((void*)0);
1792 struct ast_variable *var = NULL((void*)0);
1793 struct ast_category *cat = NULL((void*)0);
1794 char *category = NULL((void*)0), *value = NULL((void*)0), *new = NULL((void*)0);
1795 const char *tmp = NULL((void*)0);
1796 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
1797 char secretfn[PATH_MAX4096] = "";
1798 int found = 0;
1799
1800 if (!change_password_realtime(vmu, newpassword))
1801 return;
1802
1803 /* check if we should store the secret in the spool directory next to the messages */
1804 switch (vmu->passwordlocation) {
1805 case OPT_PWLOC_SPOOLDIR:
1806 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
1807 if (write_password_to_file(secretfn, newpassword) == 0) {
1808 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: secret.conf updated with new password\r\nPasswordSource: secret.conf");
1809 ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn)do { if (((4) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 1809, __PRETTY_FUNCTION__, 4, "Writing voicemail password to file %s succeeded\n"
, secretfn); } } while (0)
;
1810 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
1811 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
1812 break;
1813 } else {
1814 ast_verb(4, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn)do { if (((4) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 1814, __PRETTY_FUNCTION__, 4, "Writing voicemail password to file %s failed, falling back to config file\n"
, secretfn); } } while (0)
;
1815 }
1816 /* Fall-through */
1817 case OPT_PWLOC_VOICEMAILCONF:
1818 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)ast_config_load2("voicemail.conf", "app_voicemail", config_flags
)
) && valid_config(cfg)) {
1819 while ((category = ast_category_browse(cfg, category))) {
1820 if (!strcasecmp(category, vmu->context)) {
1821 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
1822 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 1822, __PRETTY_FUNCTION__, "We could not find the mailbox.\n");
1823 break;
1824 }
1825 value = strstr(tmp, ",");
1826 if (!value) {
1827 new = ast_alloca(strlen(newpassword)+1)__builtin_alloca(strlen(newpassword)+1);
1828 sprintf(new, "%s", newpassword);
1829 } else {
1830 new = ast_alloca((strlen(value) + strlen(newpassword) + 1))__builtin_alloca((strlen(value) + strlen(newpassword) + 1));
1831 sprintf(new, "%s%s", newpassword, value);
1832 }
1833 if (!(cat = ast_category_get(cfg, category, NULL((void*)0)))) {
1834 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 1834, __PRETTY_FUNCTION__, "Failed to get category structure.\n");
1835 break;
1836 }
1837 ast_variable_update(cat, vmu->mailbox, new, NULL((void*)0), 0);
1838 found = 1;
1839 }
1840 }
1841 /* save the results */
1842 if (found) {
1843 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
1844 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
1845 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
1846 ast_config_text_file_save(VOICEMAIL_CONFIG"voicemail.conf", cfg, "app_voicemail");
1847 ast_config_destroy(cfg);
1848 break;
1849 }
1850
1851 ast_config_destroy(cfg);
1852 }
1853 /* Fall-through */
1854 case OPT_PWLOC_USERSCONF:
1855 /* check users.conf and update the password stored for the mailbox */
1856 /* if no vmsecret entry exists create one. */
1857 if ((cfg = ast_config_load("users.conf", config_flags)ast_config_load2("users.conf", "app_voicemail", config_flags)) && valid_config(cfg)) {
1858 ast_debug(4, "we are looking for %s\n", vmu->mailbox)do { if ((option_debug >= (4) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (4)))) { ast_log
(0, "app_voicemail.c", 1858, __PRETTY_FUNCTION__, "we are looking for %s\n"
, vmu->mailbox); } } while (0)
;
1859 for (category = ast_category_browse(cfg, NULL((void*)0)); category; category = ast_category_browse(cfg, category)) {
1860 ast_debug(4, "users.conf: %s\n", category)do { if ((option_debug >= (4) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (4)))) { ast_log
(0, "app_voicemail.c", 1860, __PRETTY_FUNCTION__, "users.conf: %s\n"
, category); } } while (0)
;
1861 if (!strcasecmp(category, vmu->mailbox)) {
1862 if (!ast_variable_retrieve(cfg, category, "vmsecret")) {
1863 ast_debug(3, "looks like we need to make vmsecret!\n")do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 1863, __PRETTY_FUNCTION__, "looks like we need to make vmsecret!\n"
); } } while (0)
;
1864 var = ast_variable_new("vmsecret", newpassword, "");
1865 } else {
1866 var = NULL((void*)0);
1867 }
1868 new = ast_alloca(strlen(newpassword) + 1)__builtin_alloca(strlen(newpassword) + 1);
1869 sprintf(new, "%s", newpassword);
1870 if (!(cat = ast_category_get(cfg, category, NULL((void*)0)))) {
1871 ast_debug(4, "failed to get category!\n")do { if ((option_debug >= (4) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (4)))) { ast_log
(0, "app_voicemail.c", 1871, __PRETTY_FUNCTION__, "failed to get category!\n"
); } } while (0)
;
1872 ast_freefree(var);
1873 break;
1874 }
1875 if (!var) {
1876 ast_variable_update(cat, "vmsecret", new, NULL((void*)0), 0);
1877 } else {
1878 ast_variable_append(cat, var);
1879 }
1880 found = 1;
1881 break;
1882 }
1883 }
1884 /* save the results and clean things up */
1885 if (found) {
1886 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: users.conf updated with new password\r\nPasswordSource: users.conf");
1887 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
1888 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
1889 ast_config_text_file_save("users.conf", cfg, "app_voicemail");
1890 }
1891
1892 ast_config_destroy(cfg);
1893 }
1894 }
1895}
1896
1897static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
1898{
1899 char buf[255];
1900 snprintf(buf, sizeof(buf), "%s %s %s %s", ext_pass_cmd, vmu->context, vmu->mailbox, newpassword);
1901 ast_debug(1, "External password: %s\n",buf)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 1901, __PRETTY_FUNCTION__, "External password: %s\n"
,buf); } } while (0)
;
1902 if (!ast_safe_system(buf)) {
1903 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: external script updated with new password\r\nPasswordSource: external");
1904 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
1905 /* Reset the password in memory, too */
1906 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
1907 }
1908}
1909
1910/*!
1911 * \brief Creates a file system path expression for a folder within the voicemail data folder and the appropriate context.
1912 * \param dest The variable to hold the output generated path expression. This buffer should be of size PATH_MAX.
1913 * \param len The length of the path string that was written out.
1914 * \param context
1915 * \param ext
1916 * \param folder
1917 *
1918 * The path is constructed as
1919 * VM_SPOOL_DIRcontext/ext/folder
1920 *
1921 * \return zero on success, -1 on error.
1922 */
1923static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
1924{
1925 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
1926}
1927
1928/*!
1929 * \brief Creates a file system path expression for a folder within the voicemail data folder and the appropriate context.
1930 * \param dest The variable to hold the output generated path expression. This buffer should be of size PATH_MAX.
1931 * \param len The length of the path string that was written out.
1932 * \param dir
1933 * \param num
1934 *
1935 * The path is constructed as
1936 * VM_SPOOL_DIRcontext/ext/folder
1937 *
1938 * \return zero on success, -1 on error.
1939 */
1940static int make_file(char *dest, const int len, const char *dir, const int num)
1941{
1942 return snprintf(dest, len, "%s/msg%04d", dir, num);
1943}
1944
1945/* same as mkstemp, but return a FILE * */
1946static FILE *vm_mkftemp(char *template)
1947{
1948 FILE *p = NULL((void*)0);
1949 int pfd = mkstemp(template);
1950 chmod(template, VOICEMAIL_FILE_MODE0666 & ~my_umask);
1951 if (pfd > -1) {
1952 p = fdopen(pfd, "w+");
1953 if (!p) {
1954 close(pfd);
1955 pfd = -1;
1956 }
1957 }
1958 return p;
1959}
1960
1961/*! \brief basically mkdir -p $dest/$context/$ext/$folder
1962 * \param dest String. base directory.
1963 * \param len Length of dest.
1964 * \param context String. Ignored if is null or empty string.
1965 * \param ext String. Ignored if is null or empty string.
1966 * \param folder String. Ignored if is null or empty string.
1967 * \return -1 on failure, 0 on success.
1968 */
1969static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
1970{
1971 mode_t mode = VOICEMAIL_DIR_MODE0777;
1972 int res;
1973
1974 make_dir(dest, len, context, ext, folder);
1975 if ((res = ast_mkdir(dest, mode))) {
1976 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 1976, __PRETTY_FUNCTION__, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
1977 return -1;
1978 }
1979 return 0;
1980}
1981
1982static const char *mbox(struct ast_vm_user *vmu, int id)
1983{
1984#ifdef IMAP_STORAGE
1985 if (vmu && id == 0) {
1986 return vmu->imapfolder;
1987 }
1988#endif
1989 return (id >= 0 && id < ARRAY_LEN(mailbox_folders)(size_t) (sizeof(mailbox_folders) / sizeof(0[mailbox_folders]
))
) ? mailbox_folders[id] : "Unknown";
1990}
1991
1992static const char *vm_index_to_foldername(int id)
1993{
1994 return mbox(NULL((void*)0), id);
1995}
1996
1997
1998static int get_folder_by_name(const char *name)
1999{
2000 size_t i;
2001
2002 for (i = 0; i < ARRAY_LEN(mailbox_folders)(size_t) (sizeof(mailbox_folders) / sizeof(0[mailbox_folders]
))
; i++) {
2003 if (strcasecmp(name, mailbox_folders[i]) == 0) {
2004 return i;
2005 }
2006 }
2007
2008 return -1;
2009}
2010
2011static void free_user(struct ast_vm_user *vmu)
2012{
2013 if (!vmu) {
2014 return;
2015 }
2016
2017 ast_freefree(vmu->email);
2018 vmu->email = NULL((void*)0);
2019 ast_freefree(vmu->emailbody);
2020 vmu->emailbody = NULL((void*)0);
2021 ast_freefree(vmu->emailsubject);
2022 vmu->emailsubject = NULL((void*)0);
2023
2024 if (ast_test_flag(vmu, VM_ALLOCED)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 13))); })
) {
2025 ast_freefree(vmu);
2026 }
2027}
2028
2029static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
2030
2031 int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
2032
2033 /* remove old allocation */
2034 if (vms->deleted) {
2035 ast_freefree(vms->deleted);
2036 vms->deleted = NULL((void*)0);
2037 }
2038 if (vms->heard) {
2039 ast_freefree(vms->heard);
2040 vms->heard = NULL((void*)0);
2041 }
2042 vms->dh_arraysize = 0;
2043
2044 if (arraysize > 0) {
2045 if (!(vms->deleted = ast_calloc(arraysize, sizeof(int))_ast_calloc((arraysize), (sizeof(int)), "app_voicemail.c", 2045
, __PRETTY_FUNCTION__)
)) {
2046 return -1;
2047 }
2048 if (!(vms->heard = ast_calloc(arraysize, sizeof(int))_ast_calloc((arraysize), (sizeof(int)), "app_voicemail.c", 2048
, __PRETTY_FUNCTION__)
)) {
2049 ast_freefree(vms->deleted);
2050 vms->deleted = NULL((void*)0);
2051 return -1;
2052 }
2053 vms->dh_arraysize = arraysize;
2054 }
2055
2056 return 0;
2057}
2058
2059/* All IMAP-specific functions should go in this block. This
2060 * keeps them from being spread out all over the code */
2061#ifdef IMAP_STORAGE
2062static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
2063{
2064 char arg[10];
2065 struct vm_state *vms;
2066 unsigned long messageNum;
2067
2068 /* If greetings aren't stored in IMAP, just delete the file */
2069 if (msgnum < 0 && !imapgreetings) {
2070 ast_filedelete(file, NULL((void*)0));
2071 return;
2072 }
2073
2074 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
2075 ast_log(LOG_WARNING3, "app_voicemail.c", 2075, __PRETTY_FUNCTION__, "Couldn't find a vm_state for mailbox %s. Unable to set \\DELETED flag for message %d\n", vmu->mailbox, msgnum);
2076 return;
2077 }
2078
2079 if (msgnum < 0) {
2080 imap_delete_old_greeting(file, vms);
2081 return;
2082 }
2083
2084 /* find real message number based on msgnum */
2085 /* this may be an index into vms->msgArray based on the msgnum. */
2086 messageNum = vms->msgArray[msgnum];
2087 if (messageNum == 0) {
2088 ast_log(LOG_WARNING3, "app_voicemail.c", 2088, __PRETTY_FUNCTION__, "msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
2089 return;
2090 }
2091 ast_debug(3, "deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 2091, __PRETTY_FUNCTION__, "deleting msgnum %d, which is mailbox message %lu\n"
, msgnum, messageNum); } } while (0)
;
2092 /* delete message */
2093 snprintf (arg, sizeof(arg), "%lu", messageNum);
2094 ast_mutex_lock(&vms->lock)__ast_pthread_mutex_lock("app_voicemail.c", 2094, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
2095 mail_setflag (vms->mailstream, arg, "\\DELETED");
2096 mail_expunge(vms->mailstream);
2097 ast_mutex_unlock(&vms->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 2097, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
2098}
2099
2100static void vm_imap_update_msg_id(char *dir, int msgnum, const char *msg_id, struct ast_vm_user *vmu, struct ast_config *msg_cfg, int folder)
2101{
2102 struct ast_channel *chan;
2103 char *cid;
2104 char *cid_name;
2105 char *cid_num;
2106 struct vm_state *vms;
2107 const char *duration_str;
2108 int duration = 0;
2109
2110 /*
2111 * First, get things initially set up. If any of this fails, then
2112 * back out before doing anything substantial
2113 */
2114 vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0);
2115 if (!vms) {
2116 return;
2117 }
2118
2119 if (open_mailbox(vms, vmu, folder)) {
2120 return;
2121 }
2122
2123 chan = ast_dummy_channel_alloc()__ast_dummy_channel_alloc("app_voicemail.c", 2123, __PRETTY_FUNCTION__
)
;
2124 if (!chan) {
2125 close_mailbox(vms, vmu);
2126 return;
2127 }
2128
2129 /*
2130 * We need to make sure the new message we save has the same
2131 * callerid, flag, and duration as the original message
2132 */
2133 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"))(__extension__ ({ const char *__old = (ast_variable_retrieve(
msg_cfg, "message", "callerid")); size_t __len = strlen(__old
) + 1; char *__new = __builtin_alloca(__len); memcpy (__new, __old
, __len); __new; }))
;
2134
2135 if (!ast_strlen_zero(cid)_ast_strlen_zero(cid, "app_voicemail.c", __PRETTY_FUNCTION__,
2135)
) {
2136 ast_callerid_parse(cid, &cid_name, &cid_num);
2137 ast_party_caller_init(ast_channel_caller(chan));
2138 if (!ast_strlen_zero(cid_name)_ast_strlen_zero(cid_name, "app_voicemail.c", __PRETTY_FUNCTION__
, 2138)
) {
2139 ast_channel_caller(chan)->id.name.valid = 1;
2140 ast_channel_caller(chan)->id.name.str = ast_strdup(cid_name)_ast_strdup((cid_name), "app_voicemail.c", 2140, __PRETTY_FUNCTION__
)
;
2141 }
2142 if (!ast_strlen_zero(cid_num)_ast_strlen_zero(cid_num, "app_voicemail.c", __PRETTY_FUNCTION__
, 2142)
) {
2143 ast_channel_caller(chan)->id.number.valid = 1;
2144 ast_channel_caller(chan)->id.number.str = ast_strdup(cid_num)_ast_strdup((cid_num), "app_voicemail.c", 2144, __PRETTY_FUNCTION__
)
;
2145 }
2146 }
2147
2148 duration_str = ast_variable_retrieve(msg_cfg, "message", "duration");
2149
2150 if (!ast_strlen_zero(duration_str)_ast_strlen_zero(duration_str, "app_voicemail.c", __PRETTY_FUNCTION__
, 2150)
) {
2151 sscanf(duration_str, "%30d", &duration);
2152 }
2153
2154 /*
2155 * IMAP messages cannot be altered once delivered. So we have to delete the
2156 * current message and then re-add it with the updated message ID.
2157 *
2158 * Furthermore, there currently is no atomic way to create a new message and to
2159 * store it in an arbitrary folder. So we have to save it to the INBOX and then
2160 * move to the appropriate folder.
2161 */
2162 if (!imap_store_file(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, vmfmts,
2163 duration, vms, ast_variable_retrieve(msg_cfg, "message", "flag"), msg_id)) {
2164 if (folder != NEW_FOLDER) {
2165 save_to_folder(vmu, vms, msgnum, folder, NULL((void*)0), 1);
2166 }
2167 vm_imap_delete(dir, msgnum, vmu);
2168 }
2169 close_mailbox(vms, vmu);
2170 ast_channel_unref(chan)({ __ao2_ref((chan), (-1), "", "app_voicemail.c", 2170, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
2171}
2172
2173static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_vm_user *vmu)
2174{
2175 struct vm_state *vms_p;
2176 char *file, *filename;
2177 char dest[PATH_MAX4096];
2178 char *attachment;
2179 int i;
2180 BODY *body;
2181 int ret = 0;
2182 int curr_mbox;
2183
2184 /* This function is only used for retrieval of IMAP greetings
2185 * regular messages are not retrieved this way, nor are greetings
2186 * if they are stored locally*/
2187 if (msgnum > -1 || !imapgreetings) {
2188 return 0;
2189 } else {
2190 file = strrchr(ast_strdupa(dir)(__extension__ ({ const char *__old = (dir); size_t __len = strlen
(__old) + 1; char *__new = __builtin_alloca(__len); memcpy (__new
, __old, __len); __new; }))
, '/');
2191 if (file)
2192 *file++ = '\0';
2193 else {
2194 ast_debug(1, "Failed to procure file name from directory passed.\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 2194, __PRETTY_FUNCTION__, "Failed to procure file name from directory passed.\n"
); } } while (0)
;
2195 return -1;
2196 }
2197 }
2198
2199 /* check if someone is accessing this box right now... */
2200 if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) &&
2201 !(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
2202 /* Unlike when retrieving a message, it is reasonable not to be able to find a
2203 * vm_state for a mailbox when trying to retrieve a greeting. Just create one,
2204 * that's all we need to do.
2205 */
2206 if (!(vms_p = create_vm_state_from_user(vmu))) {
2207 ast_log(LOG_NOTICE2, "app_voicemail.c", 2207, __PRETTY_FUNCTION__, "Unable to create vm_state object!\n");
2208 return -1;
2209 }
2210 }
2211
2212 /* Greetings will never have a prepended message */
2213 *vms_p->introfn = '\0';
2214
2215 ast_mutex_lock(&vms_p->lock)__ast_pthread_mutex_lock("app_voicemail.c", 2215, __PRETTY_FUNCTION__
, "&vms_p->lock", &vms_p->lock)
;
2216
2217 /* get the current mailbox so that we can point the mailstream back to it later */
2218 curr_mbox = get_folder_by_name(vms_p->curbox);
2219
2220 if (init_mailstream(vms_p, GREETINGS_FOLDER) || !vms_p->mailstream) {
2221 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 2221, __PRETTY_FUNCTION__, "IMAP mailstream is NULL or can't init_mailstream\n");
2222 ast_mutex_unlock(&vms_p->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 2222, __PRETTY_FUNCTION__
, "&vms_p->lock", &vms_p->lock)
;
2223 return -1;
2224 }
2225
2226 /*XXX Yuck, this could probably be done a lot better */
2227 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
2228 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
2229 /* We have the body, now we extract the file name of the first attachment. */
2230 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
2231 attachment = ast_strdupa(body->nested.part->next->body.parameter->value)(__extension__ ({ const char *__old = (body->nested.part->
next->body.parameter->value); size_t __len = strlen(__old
) + 1; char *__new = __builtin_alloca(__len); memcpy (__new, __old
, __len); __new; }))
;
2232 } else {
2233 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 2233, __PRETTY_FUNCTION__, "There is no file attached to this IMAP message.\n");
2234 ret = -1;
2235 break;
2236 }
2237 filename = strsep(&attachment, ".");
2238 if (!strcmp(filename, file)) {
2239 ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
2240 vms_p->msgArray[vms_p->curmsg] = i + 1;
2241 create_dirpath(dest, sizeof(dest), vmu->context, vms_p->username, "");
2242 save_body(body, vms_p, "2", attachment, 0);
2243 ret = 0;
2244 break;
2245 }
2246 }
2247
2248 if (curr_mbox != -1) {
2249 /* restore previous mbox stream */
2250 if (init_mailstream(vms_p, curr_mbox) || !vms_p->mailstream) {
2251 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 2251, __PRETTY_FUNCTION__, "IMAP mailstream is NULL or can't init_mailstream\n");
2252 ret = -1;
2253 }
2254 }
2255 ast_mutex_unlock(&vms_p->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 2255, __PRETTY_FUNCTION__
, "&vms_p->lock", &vms_p->lock)
;
2256 return ret;
2257}
2258
2259static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
2260{
2261 BODY *body;
2262 char *header_content;
2263 char *attachedfilefmt;
2264 char buf[80];
2265 struct vm_state *vms;
2266 char text_file[PATH_MAX4096];
2267 FILE *text_file_ptr;
2268 int res = 0;
2269 struct ast_vm_user *vmu;
2270 int curr_mbox;
2271
2272 if (!(vmu = find_user(NULL((void*)0), context, mailbox))) {
2273 ast_log(LOG_WARNING3, "app_voicemail.c", 2273, __PRETTY_FUNCTION__, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
2274 return -1;
2275 }
2276
2277 if (msgnum < 0) {
2278 if (imapgreetings) {
2279 res = imap_retrieve_greeting(dir, msgnum, vmu);
2280 goto exit;
2281 } else {
2282 res = 0;
2283 goto exit;
2284 }
2285 }
2286
2287 /* Before anything can happen, we need a vm_state so that we can
2288 * actually access the imap server through the vms->mailstream
2289 */
2290 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
2291 /* This should not happen. If it does, then I guess we'd
2292 * need to create the vm_state, extract which mailbox to
2293 * open, and then set up the msgArray so that the correct
2294 * IMAP message could be accessed. If I have seen correctly
2295 * though, the vms should be obtainable from the vmstates list
2296 * and should have its msgArray properly set up.
2297 */
2298 ast_log(LOG_ERROR4, "app_voicemail.c", 2298, __PRETTY_FUNCTION__, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
2299 res = -1;
2300 goto exit;
2301 }
2302
2303 /* Ensure we have the correct mailbox open and have a valid mailstream for it */
2304 curr_mbox = get_folder_by_name(vms->curbox);
2305 if (curr_mbox < 0) {
2306 ast_debug(3, "Mailbox folder curbox not set, defaulting to Inbox\n")do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 2306, __PRETTY_FUNCTION__, "Mailbox folder curbox not set, defaulting to Inbox\n"
); } } while (0)
;
2307 curr_mbox = 0;
2308 }
2309 init_mailstream(vms, curr_mbox);
2310 if (!vms->mailstream) {
2311 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 2311, __PRETTY_FUNCTION__, "IMAP mailstream for %s is NULL\n", vmu->mailbox);
2312 res = -1;
2313 goto exit;
2314 }
2315
2316 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
2317 snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
2318
2319 /* Don't try to retrieve a message from IMAP if it already is on the file system */
2320 if (ast_fileexists(vms->fn, NULL((void*)0), NULL((void*)0)) > 0) {
2321 res = 0;
2322 goto exit;
2323 }
2324
2325 ast_debug(3, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum])do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 2325, __PRETTY_FUNCTION__, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n"
, msgnum, vms->msgArray[msgnum]); } } while (0)
;
2326 if (vms->msgArray[msgnum] == 0) {
2327 ast_log(LOG_WARNING3, "app_voicemail.c", 2327, __PRETTY_FUNCTION__, "Trying to access unknown message\n");
2328 res = -1;
2329 goto exit;
2330 }
2331
2332 /* This will only work for new messages... */
2333 ast_mutex_lock(&vms->lock)__ast_pthread_mutex_lock("app_voicemail.c", 2333, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
2334 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
2335 ast_mutex_unlock(&vms->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 2335, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
2336 /* empty string means no valid header */
2337 if (ast_strlen_zero(header_content)_ast_strlen_zero(header_content, "app_voicemail.c", __PRETTY_FUNCTION__
, 2337)
) {
2338 ast_log(LOG_ERROR4, "app_voicemail.c", 2338, __PRETTY_FUNCTION__, "Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
2339 res = -1;
2340 goto exit;
2341 }
2342
2343 ast_mutex_lock(&vms->lock)__ast_pthread_mutex_lock("app_voicemail.c", 2343, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
2344 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
2345 ast_mutex_unlock(&vms->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 2345, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
2346
2347 /* We have the body, now we extract the file name of the first attachment. */
2348 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
2349 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value)(__extension__ ({ const char *__old = (body->nested.part->
next->body.parameter->value); size_t __len = strlen(__old
) + 1; char *__new = __builtin_alloca(__len); memcpy (__new, __old
, __len); __new; }))
;
2350 } else {
2351 ast_log(LOG_ERROR4, "app_voicemail.c", 2351, __PRETTY_FUNCTION__, "There is no file attached to this IMAP message.\n");
2352 res = -1;
2353 goto exit;
2354 }
2355
2356 /* Find the format of the attached file */
2357
2358 strsep(&attachedfilefmt, ".");
2359 if (!attachedfilefmt) {
2360 ast_log(LOG_ERROR4, "app_voicemail.c", 2360, __PRETTY_FUNCTION__, "File format could not be obtained from IMAP message attachment\n");
2361 res = -1;
2362 goto exit;
2363 }
2364
2365 save_body(body, vms, "2", attachedfilefmt, 0);
2366 if (save_body(body, vms, "3", attachedfilefmt, 1)) {
2367 *vms->introfn = '\0';
2368 }
2369
2370 /* Get info from headers!! */
2371 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
2372
2373 if (!(text_file_ptr = fopen(text_file, "w"))) {
2374 ast_log(LOG_ERROR4, "app_voicemail.c", 2374, __PRETTY_FUNCTION__, "Unable to open/create file %s: %s\n", text_file, strerror(errno(*__errno_location ())));
2375 goto exit;
2376 }
2377
2378 fprintf(text_file_ptr, "%s\n", "[message]");
2379
2380 if (get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf))) {
2381 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, "")({typeof(&((buf)[0])) __x = (buf); _ast_strlen_zero(__x, "app_voicemail.c"
, __PRETTY_FUNCTION__, 2381) ? ("") : __x;})
);
2382 }
2383 if (get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf))) {
2384 fprintf(text_file_ptr, "<%s>\n", S_OR(buf, "")({typeof(&((buf)[0])) __x = (buf); _ast_strlen_zero(__x, "app_voicemail.c"
, __PRETTY_FUNCTION__, 2384) ? ("") : __x;})
);
2385 }
2386 if (get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf))) {
2387 fprintf(text_file_ptr, "context=%s\n", S_OR(buf, "")({typeof(&((buf)[0])) __x = (buf); _ast_strlen_zero(__x, "app_voicemail.c"
, __PRETTY_FUNCTION__, 2387) ? ("") : __x;})
);
2388 }
2389 if (get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf))) {
2390 fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, "")({typeof(&((buf)[0])) __x = (buf); _ast_strlen_zero(__x, "app_voicemail.c"
, __PRETTY_FUNCTION__, 2390) ? ("") : __x;})
);
2391 }
2392 if (get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf))) {
2393 fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, "")({typeof(&((buf)[0])) __x = (buf); _ast_strlen_zero(__x, "app_voicemail.c"
, __PRETTY_FUNCTION__, 2393) ? ("") : __x;})
);
2394 }
2395 if (get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf))) {
2396 fprintf(text_file_ptr, "category=%s\n", S_OR(buf, "")({typeof(&((buf)[0])) __x = (buf); _ast_strlen_zero(__x, "app_voicemail.c"
, __PRETTY_FUNCTION__, 2396) ? ("") : __x;})
);
2397 }
2398 if (get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf))) {
2399 fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, "")({typeof(&((buf)[0])) __x = (buf); _ast_strlen_zero(__x, "app_voicemail.c"
, __PRETTY_FUNCTION__, 2399) ? ("") : __x;})
);
2400 }
2401 if (get_header_by_tag(header_content, "X-Asterisk-VM-Message-ID:", buf, sizeof(buf))) {
2402 fprintf(text_file_ptr, "msg_id=%s\n", S_OR(buf, "")({typeof(&((buf)[0])) __x = (buf); _ast_strlen_zero(__x, "app_voicemail.c"
, __PRETTY_FUNCTION__, 2402) ? ("") : __x;})
);
2403 }
2404 fclose(text_file_ptr);
2405
2406exit:
2407 free_user(vmu);
2408 return res;
2409}
2410
2411static int folder_int(const char *folder)
2412{
2413 /*assume a NULL folder means INBOX*/
2414 if (!folder) {
2415 return 0;
2416 }
2417 if (!strcasecmp(folder, imapfolder)) {
2418 return 0;
2419 } else if (!strcasecmp(folder, "Old")) {
2420 return 1;
2421 } else if (!strcasecmp(folder, "Work")) {
2422 return 2;
2423 } else if (!strcasecmp(folder, "Family")) {
2424 return 3;
2425 } else if (!strcasecmp(folder, "Friends")) {
2426 return 4;
2427 } else if (!strcasecmp(folder, "Cust1")) {
2428 return 5;
2429 } else if (!strcasecmp(folder, "Cust2")) {
2430 return 6;
2431 } else if (!strcasecmp(folder, "Cust3")) {
2432 return 7;
2433 } else if (!strcasecmp(folder, "Cust4")) {
2434 return 8;
2435 } else if (!strcasecmp(folder, "Cust5")) {
2436 return 9;
2437 } else if (!strcasecmp(folder, "Urgent")) {
2438 return 11;
2439 } else { /*assume they meant INBOX if folder is not found otherwise*/
2440 return 0;
2441 }
2442}
2443
2444static int __messagecount(const char *context, const char *mailbox, const char *folder)
2445{
2446 SEARCHPGM *pgm;
2447 SEARCHHEADER *hdr;
2448
2449 struct ast_vm_user *vmu, vmus;
2450 struct vm_state *vms_p;
2451 int ret = 0;
2452 int fold = folder_int(folder);
2453 int urgent = 0;
2454
2455 /* If URGENT, then look at INBOX */
2456 if (fold == 11) {
2457 fold = NEW_FOLDER;
2458 urgent = 1;
2459 }
2460
2461 if (ast_strlen_zero(mailbox)_ast_strlen_zero(mailbox, "app_voicemail.c", __PRETTY_FUNCTION__
, 2461)
)
2462 return 0;
2463
2464 /* We have to get the user before we can open the stream! */
2465 memset(&vmus, 0, sizeof(vmus));
2466 vmu = find_user(&vmus, context, mailbox);
2467 if (!vmu) {
2468 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 2468, __PRETTY_FUNCTION__, "Couldn't find mailbox %s in context %s\n", mailbox, context);
2469 free_user(vmu);
2470 return -1;
2471 } else {
2472 /* No IMAP account available */
2473 if (vmu->imapuser[0] == '\0') {
2474 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 2474, __PRETTY_FUNCTION__, "IMAP user not set for mailbox %s\n", vmu->mailbox);
2475 free_user(vmu);
2476 return -1;
2477 }
2478 }
2479
2480 /* No IMAP account available */
2481 if (vmu->imapuser[0] == '\0') {
2482 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 2482, __PRETTY_FUNCTION__, "IMAP user not set for mailbox %s\n", vmu->mailbox);
2483 free_user(vmu);
2484 return -1;
2485 }
2486
2487 /* check if someone is accessing this box right now... */
2488 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
2489 if (!vms_p) {
2490 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
2491 }
2492 if (vms_p) {
2493 ast_debug(3, "Returning before search - user is logged in\n")do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 2493, __PRETTY_FUNCTION__, "Returning before search - user is logged in\n"
); } } while (0)
;
2494 if (fold == 0) { /* INBOX */
2495 free_user(vmu);
2496 return urgent ? vms_p->urgentmessages : vms_p->newmessages;
2497 }
2498 if (fold == 1) { /* Old messages */
2499 free_user(vmu);
2500 return vms_p->oldmessages;
2501 }
2502 }
2503
2504 /* add one if not there... */
2505 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
2506 if (!vms_p) {
2507 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
2508 }
2509
2510 if (!vms_p) {
2511 vms_p = create_vm_state_from_user(vmu);
2512 }
2513 ret = init_mailstream(vms_p, fold);
2514 if (!vms_p->mailstream) {
2515 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 2515, __PRETTY_FUNCTION__, "Houston we have a problem - IMAP mailstream is NULL\n");
2516 free_user(vmu);
2517 return -1;
2518 }
2519 if (ret == 0) {
2520 ast_mutex_lock(&vms_p->lock)__ast_pthread_mutex_lock("app_voicemail.c", 2520, __PRETTY_FUNCTION__
, "&vms_p->lock", &vms_p->lock)
;
2521 pgm = mail_newsearchpgm ();
2522 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid)_ast_strlen_zero(vmu->imapvmshareid, "app_voicemail.c", __PRETTY_FUNCTION__
, 2522)
? vmu->imapvmshareid : mailbox));
2523 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default")({typeof(&((context)[0])) __x = (context); _ast_strlen_zero
(__x, "app_voicemail.c", __PRETTY_FUNCTION__, 2523) ? ("default"
) : __x;})
);
2524 pgm->header = hdr;
2525 if (fold != OLD_FOLDER) {
2526 pgm->unseen = 1;
2527 pgm->seen = 0;
2528 }
2529 /* In the special case where fold is 1 (old messages) we have to do things a bit
2530 * differently. Old messages are stored in the INBOX but are marked as "seen"
2531 */
2532 else {
2533 pgm->unseen = 0;
2534 pgm->seen = 1;
2535 }
2536 /* look for urgent messages */
2537 if (fold == NEW_FOLDER) {
2538 if (urgent) {
2539 pgm->flagged = 1;
2540 pgm->unflagged = 0;
2541 } else {
2542 pgm->flagged = 0;
2543 pgm->unflagged = 1;
2544 }
2545 }
2546 pgm->undeleted = 1;
2547 pgm->deleted = 0;
2548
2549 vms_p->vmArrayIndex = 0;
2550 mail_search_full (vms_p->mailstream, NULL((void*)0), pgm, NIL);
2551 if (fold == 0 && urgent == 0)
2552 vms_p->newmessages = vms_p->vmArrayIndex;
2553 if (fold == 1)
2554 vms_p->oldmessages = vms_p->vmArrayIndex;
2555 if (fold == 0 && urgent == 1)
2556 vms_p->urgentmessages = vms_p->vmArrayIndex;
2557 /*Freeing the searchpgm also frees the searchhdr*/
2558 mail_free_searchpgm(&pgm);
2559 ast_mutex_unlock(&vms_p->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 2559, __PRETTY_FUNCTION__
, "&vms_p->lock", &vms_p->lock)
;
2560 free_user(vmu);
2561 vms_p->updated = 0;
2562 return vms_p->vmArrayIndex;
2563 } else {
2564 ast_mutex_lock(&vms_p->lock)__ast_pthread_mutex_lock("app_voicemail.c", 2564, __PRETTY_FUNCTION__
, "&vms_p->lock", &vms_p->lock)
;
2565 mail_ping(vms_p->mailstream);
2566 ast_mutex_unlock(&vms_p->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 2566, __PRETTY_FUNCTION__
, "&vms_p->lock", &vms_p->lock)
;
2567 }
2568 free_user(vmu);
2569 return 0;
2570}
2571
2572static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
2573{
2574 /* Check if mailbox is full */
2575 check_quota(vms, vmu->imapfolder);
2576 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
2577 ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 2577, __PRETTY_FUNCTION__, "*** QUOTA EXCEEDED!! %u >= %u\n"
, vms->quota_usage, vms->quota_limit); } } while (0)
;
2578 if (chan) {
2579 ast_play_and_wait(chan, "vm-mailboxfull");
2580 }
2581 return -1;
2582 }
2583
2584 /* Check if we have exceeded maxmsg */
2585 ast_debug(3, "Checking message number quota: mailbox has %d messages, maximum is set to %d, current messages %d\n", msgnum, vmu->maxmsg, inprocess_count(vmu->mailbox, vmu->context, 0))do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 2585, __PRETTY_FUNCTION__, "Checking message number quota: mailbox has %d messages, maximum is set to %d, current messages %d\n"
, msgnum, vmu->maxmsg, inprocess_count(vmu->mailbox, vmu
->context, 0)); } } while (0)
;
2586 if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
2587 ast_log(LOG_WARNING3, "app_voicemail.c", 2587, __PRETTY_FUNCTION__, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
2588 if (chan) {
2589 ast_play_and_wait(chan, "vm-mailboxfull");
2590 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
2591 }
2592 return -1;
2593 }
2594
2595 return 0;
2596}
2597
2598/*!
2599 * \brief Gets the number of messages that exist in a mailbox folder.
2600 * \param mailbox_id
2601 * \param folder
2602 *
2603 * This method is used when IMAP backend is used.
2604 * \return The number of messages in this mailbox folder (zero or more).
2605 */
2606static int messagecount(const char *mailbox_id, const char *folder)
2607{
2608 char *context;
2609 char *mailbox;
2610
2611 if (ast_strlen_zero(mailbox_id)_ast_strlen_zero(mailbox_id, "app_voicemail.c", __PRETTY_FUNCTION__
, 2611)
2612 || separate_mailbox(ast_strdupa(mailbox_id)(__extension__ ({ const char *__old = (mailbox_id); size_t __len
= strlen(__old) + 1; char *__new = __builtin_alloca(__len); memcpy
(__new, __old, __len); __new; }))
, &mailbox, &context)) {
2613 return 0;
2614 }
2615
2616 if (ast_strlen_zero(folder)_ast_strlen_zero(folder, "app_voicemail.c", __PRETTY_FUNCTION__
, 2616)
|| !strcmp(folder, "INBOX")) {
2617 return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
2618 } else {
2619 return __messagecount(context, mailbox, folder);
2620 }
2621}
2622
2623static int imap_store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms, const char *flag, const char *msg_id)
2624{
2625 char *myserveremail = serveremail;
2626 char fn[PATH_MAX4096];
2627 char introfn[PATH_MAX4096];
2628 char mailbox[256];
2629 char *stringp;
2630 FILE *p = NULL((void*)0);
2631 char tmp[80] = "/tmp/astmail-XXXXXX";
2632 long len;
2633 void *buf;
2634 int tempcopy = 0;
2635 STRING str;
2636 int ret; /* for better error checking */
2637 char *imap_flags = NIL;
2638 int msgcount;
2639 int box = NEW_FOLDER;
2640
2641 snprintf(mailbox, sizeof(mailbox), "%s@%s", vmu->mailbox, vmu->context);
2642 msgcount = messagecount(mailbox, "INBOX") + messagecount(mailbox, "Old");
2643
2644 /* Back out early if this is a greeting and we don't want to store greetings in IMAP */
2645 if (msgnum < 0) {
2646 if(!imapgreetings) {
2647 return 0;
2648 } else {
2649 box = GREETINGS_FOLDER;
2650 }
2651 }
2652
2653 if (imap_check_limits(chan, vms, vmu, msgcount)) {
2654 return -1;
2655 }
2656
2657 /* Set urgent flag for IMAP message */
2658 if (!ast_strlen_zero(flag)_ast_strlen_zero(flag, "app_voicemail.c", __PRETTY_FUNCTION__
, 2658)
&& !strcmp(flag, "Urgent")) {
2659 ast_debug(3, "Setting message flag \\\\FLAGGED.\n")do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 2659, __PRETTY_FUNCTION__, "Setting message flag \\\\FLAGGED.\n"
); } } while (0)
;
2660 imap_flags = "\\FLAGGED";
2661 }
2662
2663 /* Attach only the first format */
2664 fmt = ast_strdupa(fmt)(__extension__ ({ const char *__old = (fmt); size_t __len = strlen
(__old) + 1; char *__new = __builtin_alloca(__len); memcpy (__new
, __old, __len); __new; }))
;
2665 stringp = fmt;
2666 strsep(&stringp, "|");
2667
2668 if (!ast_strlen_zero(vmu->serveremail)_ast_strlen_zero(vmu->serveremail, "app_voicemail.c", __PRETTY_FUNCTION__
, 2668)
)
2669 myserveremail = vmu->serveremail;
2670
2671 if (msgnum > -1)
2672 make_file(fn, sizeof(fn), dir, msgnum);
2673 else
2674 ast_copy_string (fn, dir, sizeof(fn));
2675
2676 snprintf(introfn, sizeof(introfn), "%sintro", fn);
2677 if (ast_fileexists(introfn, NULL((void*)0), NULL((void*)0)) <= 0) {
2678 *introfn = '\0';
2679 }
2680
2681 if (ast_strlen_zero(vmu->email)_ast_strlen_zero(vmu->email, "app_voicemail.c", __PRETTY_FUNCTION__
, 2681)
) {
2682 /* We need the vmu->email to be set when we call make_email_file, but
2683 * if we keep it set, a duplicate e-mail will be created. So at the end
2684 * of this function, we will revert back to an empty string if tempcopy
2685 * is 1.
2686 */
2687 vmu->email = ast_strdup(vmu->imapuser)_ast_strdup((vmu->imapuser), "app_voicemail.c", 2687, __PRETTY_FUNCTION__
)
;
2688 tempcopy = 1;
2689 }
2690
2691 if (!strcmp(fmt, "wav49"))
2692 fmt = "WAV";
2693 ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 2693, __PRETTY_FUNCTION__, "Storing file '%s', format '%s'\n"
, fn, fmt); } } while (0)
;
2694
2695 /* Make a temporary file instead of piping directly to sendmail, in case the mail
2696 command hangs. */
2697 if (!(p = vm_mkftemp(tmp))) {
2698 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 2698, __PRETTY_FUNCTION__, "Unable to store '%s' (can't create temporary file)\n", fn);
2699 if (tempcopy) {
2700 ast_freefree(vmu->email);
2701 vmu->email = NULL((void*)0);
2702 }
2703 return -1;
2704 }
2705
2706 if (msgnum < 0 && imapgreetings) {
2707 if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
2708 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 2708, __PRETTY_FUNCTION__, "Unable to open mailstream.\n");
2709 return -1;
2710 }
2711 imap_delete_old_greeting(fn, vms);
2712 }
2713
2714 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX",
2715 chan ? S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL)({typeof(&((ast_channel_caller(chan)->id.number.str)[0
])) __x = (ast_channel_caller(chan)->id.number.str); (ast_channel_caller
(chan)->id.number.valid) && !_ast_strlen_zero(__x,
"app_voicemail.c", __PRETTY_FUNCTION__, 2715) ? (__x) : (((void
*)0));})
: NULL((void*)0),
2716 chan ? S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL)({typeof(&((ast_channel_caller(chan)->id.name.str)[0])
) __x = (ast_channel_caller(chan)->id.name.str); (ast_channel_caller
(chan)->id.name.valid) && !_ast_strlen_zero(__x, "app_voicemail.c"
, __PRETTY_FUNCTION__, 2716) ? (__x) : (((void*)0));})
: NULL((void*)0),
2717 fn, introfn, fmt, duration, 1, chan, NULL((void*)0), 1, flag, msg_id);
2718 /* read mail file to memory */
2719 len = ftell(p);
2720 rewind(p);
2721 if (!(buf = ast_malloc(len + 1)_ast_malloc((len + 1), "app_voicemail.c", 2721, __PRETTY_FUNCTION__
)
)) {
2722 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 2722, __PRETTY_FUNCTION__, "Can't allocate %ld bytes to read message\n", len + 1);
2723 fclose(p);
2724 if (tempcopy)
2725 *(vmu->email) = '\0';
2726 return -1;
2727 }
2728 if (fread(buf, len, 1, p) < len) {
2729 if (ferror(p)) {
2730 ast_log(LOG_ERROR4, "app_voicemail.c", 2730, __PRETTY_FUNCTION__, "Short read while reading in mail file.\n");
2731 return -1;
2732 }
2733 }
2734 ((char *) buf)[len] = '\0';
2735 INIT(&str, mail_string, buf, len);
2736 ret = init_mailstream(vms, box);
2737 if (ret == 0) {
2738 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
2739 ast_mutex_lock(&vms->lock)__ast_pthread_mutex_lock("app_voicemail.c", 2739, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
2740 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
2741 ast_log(LOG_ERROR4, "app_voicemail.c", 2741, __PRETTY_FUNCTION__, "Error while sending the message to %s\n", mailbox);
2742 ast_mutex_unlock(&vms->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 2742, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
2743 fclose(p);
2744 unlink(tmp);
2745 ast_freefree(buf);
2746 } else {
2747 ast_log(LOG_ERROR4, "app_voicemail.c", 2747, __PRETTY_FUNCTION__, "Could not initialize mailstream for %s\n", mailbox);
2748 fclose(p);
2749 unlink(tmp);
2750 ast_freefree(buf);
2751 return -1;
2752 }
2753 ast_debug(3, "%s stored\n", fn)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 2753, __PRETTY_FUNCTION__, "%s stored\n"
, fn); } } while (0)
;
2754
2755 if (tempcopy)
2756 *(vmu->email) = '\0';
2757 inprocess_count(vmu->mailbox, vmu->context, -1);
2758 return 0;
2759
2760}
2761
2762/*!
2763 * \brief Gets the number of messages that exist in the inbox folder.
2764 * \param mailbox_context
2765 * \param newmsgs The variable that is updated with the count of new messages within this inbox.
2766 * \param oldmsgs The variable that is updated with the count of old messages within this inbox.
2767 * \param urgentmsgs The variable that is updated with the count of urgent messages within this inbox.
2768 *
2769 * This method is used when IMAP backend is used.
2770 * Simultaneously determines the count of new,old, and urgent messages. The total messages would then be the sum of these three.
2771 *
2772 * \return zero on success, -1 on error.
2773 */
2774
2775static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
2776{
2777 char tmp[PATH_MAX4096] = "";
2778 char *mailboxnc;
2779 char *context;
2780 char *mb;
2781 char *cur;
2782 if (newmsgs)
2783 *newmsgs = 0;
2784 if (oldmsgs)
2785 *oldmsgs = 0;
2786 if (urgentmsgs)
2787 *urgentmsgs = 0;
2788
2789 ast_debug(3, "Mailbox is set to %s\n", mailbox_context)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 2789, __PRETTY_FUNCTION__, "Mailbox is set to %s\n"
, mailbox_context); } } while (0)
;
2790 /* If no mailbox, return immediately */
2791 if (ast_strlen_zero(mailbox_context)_ast_strlen_zero(mailbox_context, "app_voicemail.c", __PRETTY_FUNCTION__
, 2791)
)
2792 return 0;
2793
2794 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
2795 context = strchr(tmp, '@')(__extension__ (__builtin_constant_p ('@') && !__builtin_constant_p
(tmp) && ('@') == '\0' ? (char *) __rawmemchr (tmp, '@'
) : __builtin_strchr (tmp, '@')))
;
2796 if (strchr(mailbox_context, ',')(__extension__ (__builtin_constant_p (',') && !__builtin_constant_p
(mailbox_context) && (',') == '\0' ? (char *) __rawmemchr
(mailbox_context, ',') : __builtin_strchr (mailbox_context, ','
)))
) {
2797 int tmpnew, tmpold, tmpurgent;
2798 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
2799 mb = tmp;
2800 while ((cur = strsep(&mb, ", "))) {
2801 if (!ast_strlen_zero(cur)_ast_strlen_zero(cur, "app_voicemail.c", __PRETTY_FUNCTION__,
2801)
) {
2802 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL((void*)0), newmsgs ? &tmpnew : NULL((void*)0), oldmsgs ? &tmpold : NULL((void*)0)))
2803 return -1;
2804 else {
2805 if (newmsgs)
2806 *newmsgs += tmpnew;
2807 if (oldmsgs)
2808 *oldmsgs += tmpold;
2809 if (urgentmsgs)
2810 *urgentmsgs += tmpurgent;
2811 }
2812 }
2813 }
2814 return 0;
2815 }
2816 if (context) {
2817 *context = '\0';
2818 mailboxnc = tmp;
2819 context++;
2820 } else {
2821 context = "default";
2822 mailboxnc = (char *) mailbox_context;
2823 }
2824
2825 if (newmsgs) {
2826 struct ast_vm_user *vmu = find_user(NULL((void*)0), context, mailboxnc);
2827 if (!vmu) {
2828 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 2828, __PRETTY_FUNCTION__, "Couldn't find mailbox %s in context %s\n", mailboxnc, context);
2829 return -1;
2830 }
2831 if ((*newmsgs = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
2832 free_user(vmu);
2833 return -1;
2834 }
2835 free_user(vmu);
2836 }
2837 if (oldmsgs) {
2838 if ((*oldmsgs = __messagecount(context, mailboxnc, "Old")) < 0) {
2839 return -1;
2840 }
2841 }
2842 if (urgentmsgs) {
2843 if ((*urgentmsgs = __messagecount(context, mailboxnc, "Urgent")) < 0) {
2844 return -1;
2845 }
2846 }
2847 return 0;
2848}
2849
2850/**
2851 * \brief Determines if the given folder has messages.
2852 * \param mailbox The @ delimited string for user@context. If no context is found, uses 'default' for the context.
2853 * \param folder the folder to look in
2854 *
2855 * This function is used when the mailbox is stored in an IMAP back end.
2856 * This invokes the messagecount(). Here we are interested in the presence of messages (> 0) only, not the actual count.
2857 * \return 1 if the folder has one or more messages. zero otherwise.
2858 */
2859
2860static int has_voicemail(const char *mailbox, const char *folder)
2861{
2862 char tmp[256], *tmp2, *box, *context;
2863 ast_copy_string(tmp, mailbox, sizeof(tmp));
2864 tmp2 = tmp;
2865 if (strchr(tmp2, ',')(__extension__ (__builtin_constant_p (',') && !__builtin_constant_p
(tmp2) && (',') == '\0' ? (char *) __rawmemchr (tmp2
, ',') : __builtin_strchr (tmp2, ',')))
|| strchr(tmp2, '&')(__extension__ (__builtin_constant_p ('&') && !__builtin_constant_p
(tmp2) && ('&') == '\0' ? (char *) __rawmemchr (
tmp2, '&') : __builtin_strchr (tmp2, '&')))
) {
2866 while ((box = strsep(&tmp2, ",&"))) {
2867 if (!ast_strlen_zero(box)_ast_strlen_zero(box, "app_voicemail.c", __PRETTY_FUNCTION__,
2867)
) {
2868 if (has_voicemail(box, folder)) {
2869 return 1;
2870 }
2871 }
2872 }
2873 }
2874 if ((context = strchr(tmp, '@')(__extension__ (__builtin_constant_p ('@') && !__builtin_constant_p
(tmp) && ('@') == '\0' ? (char *) __rawmemchr (tmp, '@'
) : __builtin_strchr (tmp, '@')))
)) {
2875 *context++ = '\0';
2876 } else {
2877 context = "default";
2878 }
2879 return __messagecount(context, tmp, folder) ? 1 : 0;
2880}
2881
2882/*!
2883 * \brief Copies a message from one mailbox to another.
2884 * \param chan
2885 * \param vmu
2886 * \param imbox
2887 * \param msgnum
2888 * \param duration
2889 * \param recip
2890 * \param fmt
2891 * \param dir
2892 *
2893 * This works with IMAP storage based mailboxes.
2894 *
2895 * \return zero on success, -1 on error.
2896 */
2897static int copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int imbox, int msgnum, long duration, struct ast_vm_user *recip, char *fmt, char *dir, char *flag, const char *dest_folder)
2898{
2899 struct vm_state *sendvms = NULL((void*)0);
2900 char messagestring[10]; /*I guess this could be a problem if someone has more than 999999999 messages...*/
2901 if (msgnum >= recip->maxmsg) {
2902 ast_log(LOG_WARNING3, "app_voicemail.c", 2902, __PRETTY_FUNCTION__, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
2903 return -1;
2904 }
2905 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
2906 ast_log(LOG_ERROR4, "app_voicemail.c", 2906, __PRETTY_FUNCTION__, "Couldn't get vm_state for originator's mailbox!!\n");
2907 return -1;
2908 }
2909 if (!get_vm_state_by_imapuser(recip->imapuser, 0)) {
2910 ast_log(LOG_ERROR4, "app_voicemail.c", 2910, __PRETTY_FUNCTION__, "Couldn't get vm_state for destination mailbox!\n");
2911 return -1;
2912 }
2913 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
2914 ast_mutex_lock(&sendvms->lock)__ast_pthread_mutex_lock("app_voicemail.c", 2914, __PRETTY_FUNCTION__
, "&sendvms->lock", &sendvms->lock)
;
2915 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(vmu, imbox)) == T)) {
2916 ast_mutex_unlock(&sendvms->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 2916, __PRETTY_FUNCTION__
, "&sendvms->lock", &sendvms->lock)
;
2917 return 0;
2918 }
2919 ast_mutex_unlock(&sendvms->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 2919, __PRETTY_FUNCTION__
, "&sendvms->lock", &sendvms->lock)
;
2920 ast_log(LOG_WARNING3, "app_voicemail.c", 2920, __PRETTY_FUNCTION__, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
2921 return -1;
2922}
2923
2924static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
2925{
2926 char tmp[256], *t = tmp;
2927 size_t left = sizeof(tmp);
2928
2929 if (box == OLD_FOLDER) {
2930 ast_copy_string(vms->curbox, mbox(NULL((void*)0), NEW_FOLDER), sizeof(vms->curbox));
2931 } else {
2932 ast_copy_string(vms->curbox, mbox(NULL((void*)0), box), sizeof(vms->curbox));
2933 }
2934
2935 if (box == NEW_FOLDER) {
2936 ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
2937 } else {
2938 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(NULL((void*)0), box));
2939 }
2940
2941 /* Build up server information */
2942 ast_build_string(&t, &left, "{%s:%s/imap", S_OR(vms->imapserver, imapserver)({typeof(&((vms->imapserver)[0])) __x = (vms->imapserver
); _ast_strlen_zero(__x, "app_voicemail.c", __PRETTY_FUNCTION__
, 2942) ? (imapserver) : __x;})
, S_OR(vms->imapport, imapport)({typeof(&((vms->imapport)[0])) __x = (vms->imapport
); _ast_strlen_zero(__x, "app_voicemail.c", __PRETTY_FUNCTION__
, 2942) ? (imapport) : __x;})
);
2943
2944 /* Add authentication user if present */
2945 if (!ast_strlen_zero(authuser)_ast_strlen_zero(authuser, "app_voicemail.c", __PRETTY_FUNCTION__
, 2945)
)
2946 ast_build_string(&t, &left, "/authuser=%s", authuser);
2947
2948 /* Add flags if present */
2949 if (!ast_strlen_zero(imapflags)_ast_strlen_zero(imapflags, "app_voicemail.c", __PRETTY_FUNCTION__
, 2949)
|| !(ast_strlen_zero(vms->imapflags)_ast_strlen_zero(vms->imapflags, "app_voicemail.c", __PRETTY_FUNCTION__
, 2949)
)) {
2950 ast_build_string(&t, &left, "/%s", S_OR(vms->imapflags, imapflags)({typeof(&((vms->imapflags)[0])) __x = (vms->imapflags
); _ast_strlen_zero(__x, "app_voicemail.c", __PRETTY_FUNCTION__
, 2950) ? (imapflags) : __x;})
);
2951 }
2952
2953 /* End with username */
2954#if 1
2955 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
2956#else
2957 ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
2958#endif
2959 if (box == NEW_FOLDER || box == OLD_FOLDER)
2960 snprintf(spec, len, "%s%s", tmp, use_folder? vms->imapfolder: "INBOX");
2961 else if (box == GREETINGS_FOLDER)
2962 snprintf(spec, len, "%s%s", tmp, greetingfolder);
2963 else { /* Other folders such as Friends, Family, etc... */
2964 if (!ast_strlen_zero(imapparentfolder)_ast_strlen_zero(imapparentfolder, "app_voicemail.c", __PRETTY_FUNCTION__
, 2964)
) {
2965 /* imapparentfolder would typically be set to INBOX */
2966 snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(NULL((void*)0), box));
2967 } else {
2968 snprintf(spec, len, "%s%s", tmp, mbox(NULL((void*)0), box));
2969 }
2970 }
2971}
2972
2973static int init_mailstream(struct vm_state *vms, int box)
2974{
2975 MAILSTREAM *stream = NIL;
2976 long debug;
2977 char tmp[256];
2978
2979 if (!vms) {
2980 ast_log(LOG_ERROR4, "app_voicemail.c", 2980, __PRETTY_FUNCTION__, "vm_state is NULL!\n");
2981 return -1;
2982 }
2983 ast_debug(3, "vm_state user is:%s\n", vms->imapuser)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 2983, __PRETTY_FUNCTION__, "vm_state user is:%s\n"
, vms->imapuser); } } while (0)
;
2984 if (vms->mailstream == NIL || !vms->mailstream) {
2985 ast_debug(1, "mailstream not set.\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 2985, __PRETTY_FUNCTION__, "mailstream not set.\n"
); } } while (0)
;
2986 } else {
2987 stream = vms->mailstream;
2988 }
2989 /* debug = T; user wants protocol telemetry? */
2990 debug = NIL; /* NO protocol telemetry? */
2991
2992 if (delimiter == '\0') { /* did not probe the server yet */
2993 char *cp;
2994#ifdef USE_SYSTEM_IMAP
2995#include <imap/linkage.c>
2996#elif defined(USE_SYSTEM_CCLIENT)
2997#include <c-client/linkage.c>
2998#else
2999#include "linkage.c"
3000#endif
3001 /* Connect to INBOX first to get folders delimiter */
3002 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
3003 ast_mutex_lock(&vms->lock)__ast_pthread_mutex_lock("app_voicemail.c", 3003, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
3004 ast_mutex_lock(&mail_open_lock)__ast_pthread_mutex_lock("app_voicemail.c", 3004, __PRETTY_FUNCTION__
, "&mail_open_lock", &mail_open_lock)
;
3005 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
3006 ast_mutex_unlock(&mail_open_lock)__ast_pthread_mutex_unlock("app_voicemail.c", 3006, __PRETTY_FUNCTION__
, "&mail_open_lock", &mail_open_lock)
;
3007 ast_mutex_unlock(&vms->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 3007, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
3008 if (stream == NIL) {
3009 ast_log(LOG_ERROR4, "app_voicemail.c", 3009, __PRETTY_FUNCTION__, "Can't connect to imap server %s\n", tmp);
3010 return -1;
3011 }
3012 get_mailbox_delimiter(vms, stream);
3013 /* update delimiter in imapfolder */
3014 for (cp = vms->imapfolder; *cp; cp++)
3015 if (*cp == '/')
3016 *cp = delimiter;
3017 }
3018 /* Now connect to the target folder */
3019 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
3020 ast_debug(3, "Before mail_open, server: %s, box:%d\n", tmp, box)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 3020, __PRETTY_FUNCTION__, "Before mail_open, server: %s, box:%d\n"
, tmp, box); } } while (0)
;
3021 ast_mutex_lock(&vms->lock)__ast_pthread_mutex_lock("app_voicemail.c", 3021, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
3022 ast_mutex_lock(&mail_open_lock)__ast_pthread_mutex_lock("app_voicemail.c", 3022, __PRETTY_FUNCTION__
, "&mail_open_lock", &mail_open_lock)
;
3023 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
3024 /* Create the folder if it dosn't exist */
3025 if (vms->mailstream && !mail_status(vms->mailstream, tmp, SA_UIDNEXT)) {
3026 mail_create(vms->mailstream, tmp);
3027 }
3028 ast_mutex_unlock(&mail_open_lock)__ast_pthread_mutex_unlock("app_voicemail.c", 3028, __PRETTY_FUNCTION__
, "&mail_open_lock", &mail_open_lock)
;
3029 ast_mutex_unlock(&vms->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 3029, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
3030 if (vms->mailstream == NIL) {
3031 return -1;
3032 } else {
3033 return 0;
3034 }
3035}
3036
3037static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
3038{
3039 SEARCHPGM *pgm;
3040 SEARCHHEADER *hdr;
3041 int urgent = 0;
3042
3043 /* If Urgent, then look at INBOX */
3044 if (box == 11) {
3045 box = NEW_FOLDER;
3046 urgent = 1;
3047 }
3048
3049 ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser));
3050 ast_copy_string(vms->imapfolder, vmu->imapfolder, sizeof(vms->imapfolder));
3051 ast_copy_string(vms->imapserver, vmu->imapserver, sizeof(vms->imapserver));
3052 ast_copy_string(vms->imapport, vmu->imapport, sizeof(vms->imapport));
3053 ast_copy_string(vms->imapflags, vmu->imapflags, sizeof(vms->imapflags));
3054 vms->imapversion = vmu->imapversion;
3055 ast_debug(3, "Before init_mailstream, user is %s\n", vmu->imapuser)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 3055, __PRETTY_FUNCTION__, "Before init_mailstream, user is %s\n"
, vmu->imapuser); } } while (0)
;
3056
3057 if (init_mailstream(vms, box) || !vms->mailstream) {
3058 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 3058, __PRETTY_FUNCTION__, "Could not initialize mailstream\n");
3059 return -1;
3060 }
3061
3062 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
3063
3064 /* Check Quota */
3065 if (box == 0) {
3066 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(vmu, box))do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 3066, __PRETTY_FUNCTION__, "Mailbox name set to: %s, about to check quotas\n"
, mbox(vmu, box)); } } while (0)
;
3067 check_quota(vms, (char *) mbox(vmu, box));
3068 }
3069
3070 ast_mutex_lock(&vms->lock)__ast_pthread_mutex_lock("app_voicemail.c", 3070, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
3071 pgm = mail_newsearchpgm();
3072
3073 /* Check IMAP folder for Asterisk messages only... */
3074 hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid)_ast_strlen_zero(vmu->imapvmshareid, "app_voicemail.c", __PRETTY_FUNCTION__
, 3074)
? vmu->imapvmshareid : vmu->mailbox));
3075 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
3076 pgm->header = hdr;
3077 pgm->deleted = 0;
3078 pgm->undeleted = 1;
3079
3080 /* if box = NEW_FOLDER, check for new, if box = OLD_FOLDER, check for read */
3081 if (box == NEW_FOLDER && urgent == 1) {
3082 pgm->unseen = 1;
3083 pgm->seen = 0;
3084 pgm->flagged = 1;
3085 pgm->unflagged = 0;
3086 } else if (box == NEW_FOLDER && urgent == 0) {
3087 pgm->unseen = 1;
3088 pgm->seen = 0;
3089 pgm->flagged = 0;
3090 pgm->unflagged = 1;
3091 } else if (box == OLD_FOLDER) {
3092 pgm->seen = 1;
3093 pgm->unseen = 0;
3094 }
3095
3096 ast_debug(3, "Before mail_search_full, user is %s\n", vmu->imapuser)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 3096, __PRETTY_FUNCTION__, "Before mail_search_full, user is %s\n"
, vmu->imapuser); } } while (0)
;
3097
3098 vms->vmArrayIndex = 0;
3099 mail_search_full (vms->mailstream, NULL((void*)0), pgm, NIL);
3100 vms->lastmsg = vms->vmArrayIndex - 1;
3101 mail_free_searchpgm(&pgm);
3102 /* Since IMAP storage actually stores both old and new messages in the same IMAP folder,
3103 * ensure to allocate enough space to account for all of them. Warn if old messages
3104 * have not been checked first as that is required.
3105 */
3106 if (box == 0 && !vms->dh_arraysize) {
3107 ast_log(LOG_WARNING3, "app_voicemail.c", 3107, __PRETTY_FUNCTION__, "The code expects the old messages to be checked first, fix the code.\n");
3108 }
3109 if (vm_allocate_dh(vms, vmu, box == 0 ? vms->vmArrayIndex + vms->oldmessages : vms->lastmsg)) {
3110 ast_mutex_unlock(&vms->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 3110, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
3111 return -1;
3112 }
3113
3114 ast_mutex_unlock(&vms->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 3114, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
3115 return 0;
3116}
3117
3118static void write_file(char *filename, char *buffer, unsigned long len)
3119{
3120 FILE *output;
3121
3122 if (!filename || !buffer) {
3123 return;
3124 }
3125
3126 if (!(output = fopen(filename, "w"))) {
3127 ast_log(LOG_ERROR4, "app_voicemail.c", 3127, __PRETTY_FUNCTION__, "Unable to open/create file %s: %s\n", filename, strerror(errno(*__errno_location ())));
3128 return;
3129 }
3130
3131 if (fwrite(buffer, len, 1, output) != 1) {
3132 if (ferror(output)) {
3133 ast_log(LOG_ERROR4, "app_voicemail.c", 3133, __PRETTY_FUNCTION__, "Short write while writing e-mail body: %s.\n", strerror(errno(*__errno_location ())));
3134 }
3135 }
3136 fclose (output);
3137}
3138
3139static void update_messages_by_imapuser(const char *user, unsigned long number)
3140{
3141 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
3142
3143 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
3144 return;
3145 }
3146
3147 ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 3147, __PRETTY_FUNCTION__, "saving mailbox message number %lu as message %d. Interactive set to %d\n"
, number, vms->vmArrayIndex, vms->interactive); } } while
(0)
;
3148
3149 /* Ensure we have room for the next message. */
3150 if (vms->vmArrayIndex >= vms->msg_array_max) {
3151 long *new_mem = ast_realloc(vms->msgArray, 2 * vms->msg_array_max * sizeof(long))_ast_realloc((vms->msgArray), (2 * vms->msg_array_max *
sizeof(long)), "app_voicemail.c", 3151, __PRETTY_FUNCTION__)
;
3152 if (!new_mem) {
3153 return;
3154 }
3155 vms->msgArray = new_mem;
3156 vms->msg_array_max *= 2;
3157 }
3158
3159 vms->msgArray[vms->vmArrayIndex++] = number;
3160}
3161
3162void mm_searched(MAILSTREAM *stream, unsigned long number)
3163{
3164 char *mailbox = stream->mailbox, buf[1024] = "", *user;
3165
3166 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
3167 return;
3168
3169 update_messages_by_imapuser(user, number);
3170}
3171
3172static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
3173{
3174 struct ast_variable *var;
3175 struct ast_vm_user *vmu;
3176
3177 vmu = ast_calloc(1, sizeof *vmu)_ast_calloc((1), (sizeof *vmu), "app_voicemail.c", 3177, __PRETTY_FUNCTION__
)
;
3178 if (!vmu)
3179 return NULL((void*)0);
3180
3181 populate_defaults(vmu);
3182 ast_set_flag(vmu, VM_ALLOCED)do { typeof ((vmu)->flags) __p = (vmu)->flags; typeof (
__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); ((vmu)->flags |= ((1 << 13))); } while(0)
;
3183
3184 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL((void*)0));
3185 if (var) {
3186 apply_options_full(vmu, var);
3187 ast_variables_destroy(var);
3188 return vmu;
3189 } else {
3190 ast_freefree(vmu);
3191 return NULL((void*)0);
3192 }
3193}
3194
3195/* Interfaces to C-client */
3196
3197void mm_exists(MAILSTREAM * stream, unsigned long number)
3198{
3199 /* mail_ping will callback here if new mail! */
3200 ast_debug(4, "Entering EXISTS callback for message %ld\n", number)do { if ((option_debug >= (4) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (4)))) { ast_log
(0, "app_voicemail.c", 3200, __PRETTY_FUNCTION__, "Entering EXISTS callback for message %ld\n"
, number); } } while (0)
;
3201 if (number == 0) return;
3202 set_update(stream);
3203}
3204
3205
3206void mm_expunged(MAILSTREAM * stream, unsigned long number)
3207{
3208 /* mail_ping will callback here if expunged mail! */
3209 ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number)do { if ((option_debug >= (4) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (4)))) { ast_log
(0, "app_voicemail.c", 3209, __PRETTY_FUNCTION__, "Entering EXPUNGE callback for message %ld\n"
, number); } } while (0)
;
3210 if (number == 0) return;
3211 set_update(stream);
3212}
3213
3214
3215void mm_flags(MAILSTREAM * stream, unsigned long number)
3216{
3217 /* mail_ping will callback here if read mail! */
3218 ast_debug(4, "Entering FLAGS callback for message %ld\n", number)do { if ((option_debug >= (4) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (4)))) { ast_log
(0, "app_voicemail.c", 3218, __PRETTY_FUNCTION__, "Entering FLAGS callback for message %ld\n"
, number); } } while (0)
;
3219 if (number == 0) return;
3220 set_update(stream);
3221}
3222
3223
3224void mm_notify(MAILSTREAM * stream, char *string, long errflg)
3225{
3226 ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string)do { if ((option_debug >= (5) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (5)))) { ast_log
(0, "app_voicemail.c", 3226, __PRETTY_FUNCTION__, "Entering NOTIFY callback, errflag is %ld, string is %s\n"
, errflg, string); } } while (0)
;
3227 mm_log (string, errflg);
3228}
3229
3230
3231void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
3232{
3233 if (delimiter == '\0') {
3234 delimiter = delim;
3235 }
3236
3237 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox)do { if ((option_debug >= (5) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (5)))) { ast_log
(0, "app_voicemail.c", 3237, __PRETTY_FUNCTION__, "Delimiter set to %c and mailbox %s\n"
, delim, mailbox); } } while (0)
;
3238 if (attributes & LATT_NOINFERIORS)
3239 ast_debug(5, "no inferiors\n")do { if ((option_debug >= (5) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (5)))) { ast_log
(0, "app_voicemail.c", 3239, __PRETTY_FUNCTION__, "no inferiors\n"
); } } while (0)
;
3240 if (attributes & LATT_NOSELECT)
3241 ast_debug(5, "no select\n")do { if ((option_debug >= (5) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (5)))) { ast_log
(0, "app_voicemail.c", 3241, __PRETTY_FUNCTION__, "no select\n"
); } } while (0)
;
3242 if (attributes & LATT_MARKED)
3243 ast_debug(5, "marked\n")do { if ((option_debug >= (5) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (5)))) { ast_log
(0, "app_voicemail.c", 3243, __PRETTY_FUNCTION__, "marked\n")
; } } while (0)
;
3244 if (attributes & LATT_UNMARKED)
3245 ast_debug(5, "unmarked\n")do { if ((option_debug >= (5) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (5)))) { ast_log
(0, "app_voicemail.c", 3245, __PRETTY_FUNCTION__, "unmarked\n"
); } } while (0)
;
3246}
3247
3248
3249void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
3250{
3251 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox)do { if ((option_debug >= (5) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (5)))) { ast_log
(0, "app_voicemail.c", 3251, __PRETTY_FUNCTION__, "Delimiter set to %c and mailbox %s\n"
, delim, mailbox); } } while (0)
;
3252 if (attributes & LATT_NOINFERIORS)
3253 ast_debug(5, "no inferiors\n")do { if ((option_debug >= (5) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (5)))) { ast_log
(0, "app_voicemail.c", 3253, __PRETTY_FUNCTION__, "no inferiors\n"
); } } while (0)
;
3254 if (attributes & LATT_NOSELECT)
3255 ast_debug(5, "no select\n")do { if ((option_debug >= (5) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (5)))) { ast_log
(0, "app_voicemail.c", 3255, __PRETTY_FUNCTION__, "no select\n"
); } } while (0)
;
3256 if (attributes & LATT_MARKED)
3257 ast_debug(5, "marked\n")do { if ((option_debug >= (5) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (5)))) { ast_log
(0, "app_voicemail.c", 3257, __PRETTY_FUNCTION__, "marked\n")
; } } while (0)
;
3258 if (attributes & LATT_UNMARKED)
3259 ast_debug(5, "unmarked\n")do { if ((option_debug >= (5) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (5)))) { ast_log
(0, "app_voicemail.c", 3259, __PRETTY_FUNCTION__, "unmarked\n"
); } } while (0)
;
3260}
3261
3262
3263void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
3264{
3265 struct ast_str *str;
3266
3267 if (!DEBUG_ATLEAST(5)(option_debug >= (5) || (({ typeof ((&ast_options)->
flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (5)))
|| !(str = ast_str_create(256))) {
3268 return;
3269 }
3270
3271 ast_str_append(&str, 0, " Mailbox %s", mailbox);
3272 if (status->flags & SA_MESSAGES) {
3273 ast_str_append(&str, 0, ", %lu messages", status->messages);
3274 }
3275 if (status->flags & SA_RECENT) {
3276 ast_str_append(&str, 0, ", %lu recent", status->recent);
3277 }
3278 if (status->flags & SA_UNSEEN) {
3279 ast_str_append(&str, 0, ", %lu unseen", status->unseen);
3280 }
3281 if (status->flags & SA_UIDVALIDITY) {
3282 ast_str_append(&str, 0, ", %lu UID validity", status->uidvalidity);
3283 }
3284 if (status->flags & SA_UIDNEXT) {
3285 ast_str_append(&str, 0, ", %lu next UID", status->uidnext);
3286 }
3287 ast_log(LOG_DEBUG0, "app_voicemail.c", 3287, __PRETTY_FUNCTION__, "%s\n", ast_str_buffer(str));
3288
3289 ast_freefree(str);
3290}
3291
3292
3293void mm_log(char *string, long errflg)
3294{
3295 switch ((short) errflg) {
3296 case NIL:
3297 ast_debug(1, "IMAP Info: %s\n", string)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 3297, __PRETTY_FUNCTION__, "IMAP Info: %s\n"
, string); } } while (0)
;
3298 break;
3299 case PARSE:
3300 case WARN:
3301 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 3301, __PRETTY_FUNCTION__, "IMAP Warning: %s\n", string);
3302 break;
3303 case ERROR:
3304 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 3304, __PRETTY_FUNCTION__, "IMAP Error: %s\n", string);
3305 break;
3306 }
3307}
3308
3309
3310void mm_dlog(char *string)
3311{
3312 ast_log(AST_LOG_NOTICE2, "app_voicemail.c", 3312, __PRETTY_FUNCTION__, "%s\n", string);
3313}
3314
3315
3316void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
3317{
3318 struct ast_vm_user *vmu;
3319
3320 ast_debug(4, "Entering callback mm_login\n")do { if ((option_debug >= (4) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (4)))) { ast_log
(0, "app_voicemail.c", 3320, __PRETTY_FUNCTION__, "Entering callback mm_login\n"
); } } while (0)
;
3321
3322 ast_copy_string(user, mb->user, MAILTMPLEN);
3323
3324 /* We should only do this when necessary */
3325 if (!ast_strlen_zero(authpassword)_ast_strlen_zero(authpassword, "app_voicemail.c", __PRETTY_FUNCTION__
, 3325)
) {
3326 ast_copy_string(pwd, authpassword, MAILTMPLEN);
3327 } else {
3328 AST_LIST_TRAVERSE(&users, vmu, list)for((vmu) = (&users)->first; (vmu); (vmu) = (vmu)->
list.next)
{
3329 if (!strcasecmp(mb->user, vmu->imapuser)) {
3330 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
3331 break;
3332 }
3333 }
3334 if (!vmu) {
3335 if ((vmu = find_user_realtime_imapuser(mb->user))) {
3336 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
3337 free_user(vmu);
3338 }
3339 }
3340 }
3341}
3342
3343
3344void mm_critical(MAILSTREAM * stream)
3345{
3346}
3347
3348
3349void mm_nocritical(MAILSTREAM * stream)
3350{
3351}
3352
3353
3354long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
3355{
3356 kill (getpid (), SIGSTOP19);
3357 return NIL;
3358}
3359
3360
3361void mm_fatal(char *string)
3362{
3363 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 3363, __PRETTY_FUNCTION__, "IMAP access FATAL error: %s\n", string);
3364}
3365
3366/* C-client callback to handle quota */
3367static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
3368{
3369 struct vm_state *vms;
3370 char *mailbox = stream->mailbox, *user;
3371 char buf[1024] = "";
3372 unsigned long usage = 0, limit = 0;
3373
3374 while (pquota) {
3375 usage = pquota->usage;
3376 limit = pquota->limit;
3377 pquota = pquota->next;
3378 }
3379
3380 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || (!(vms = get_vm_state_by_imapuser(user, 2)) && !(vms = get_vm_state_by_imapuser(user, 0)))) {
3381 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 3381, __PRETTY_FUNCTION__, "No state found.\n");
3382 return;
3383 }
3384
3385 ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 3385, __PRETTY_FUNCTION__, "User %s usage is %lu, limit is %lu\n"
, user, usage, limit); } } while (0)
;
3386
3387 vms->quota_usage = usage;
3388 vms->quota_limit = limit;
3389}
3390
3391static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
3392{
3393 char *start, *eol_pnt;
3394 int taglen;
3395
3396 if (ast_strlen_zero(header)_ast_strlen_zero(header, "app_voicemail.c", __PRETTY_FUNCTION__
, 3396)
|| ast_strlen_zero(tag)_ast_strlen_zero(tag, "app_voicemail.c", __PRETTY_FUNCTION__,
3396)
)
3397 return NULL((void*)0);
3398
3399 taglen = strlen(tag) + 1;
3400 if (taglen < 1)
3401 return NULL((void*)0);
3402
3403 if (!(start = strcasestr(header, tag)))
3404 return NULL((void*)0);
3405
3406 /* Since we can be called multiple times we should clear our buffer */
3407 memset(buf, 0, len);
3408
3409 ast_copy_string(buf, start+taglen, len);
3410 if ((eol_pnt = strchr(buf,'\r')(__extension__ (__builtin_constant_p ('\r') && !__builtin_constant_p
(buf) && ('\r') == '\0' ? (char *) __rawmemchr (buf,
'\r') : __builtin_strchr (buf, '\r')))
) || (eol_pnt = strchr(buf,'\n')(__extension__ (__builtin_constant_p ('\n') && !__builtin_constant_p
(buf) && ('\n') == '\0' ? (char *) __rawmemchr (buf,
'\n') : __builtin_strchr (buf, '\n')))
))
3411 *eol_pnt = '\0';
3412 return buf;
3413}
3414
3415static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
3416{
3417 char *start, *eol_pnt, *quote;
3418
3419 if (ast_strlen_zero(mailbox)_ast_strlen_zero(mailbox, "app_voicemail.c", __PRETTY_FUNCTION__
, 3419)
)
3420 return NULL((void*)0);
3421
3422 if (!(start = strstr(mailbox, "/user=")))
3423 return NULL((void*)0);
3424
3425 ast_copy_string(buf, start+6, len);
3426
3427 if (!(quote = strchr(buf, '"')(__extension__ (__builtin_constant_p ('"') && !__builtin_constant_p
(buf) && ('"') == '\0' ? (char *) __rawmemchr (buf, '"'
) : __builtin_strchr (buf, '"')))
)) {
3428 if ((eol_pnt = strchr(buf, '/')(__extension__ (__builtin_constant_p ('/') && !__builtin_constant_p
(buf) && ('/') == '\0' ? (char *) __rawmemchr (buf, '/'
) : __builtin_strchr (buf, '/')))
) || (eol_pnt = strchr(buf, '}')(__extension__ (__builtin_constant_p ('}') && !__builtin_constant_p
(buf) && ('}') == '\0' ? (char *) __rawmemchr (buf, '}'
) : __builtin_strchr (buf, '}')))
)) {
3429 *eol_pnt = '\0';
3430 }
3431 return buf;
3432 } else {
3433 if ((eol_pnt = strchr(quote + 1, '"')(__extension__ (__builtin_constant_p ('"') && !__builtin_constant_p
(quote + 1) && ('"') == '\0' ? (char *) __rawmemchr (
quote + 1, '"') : __builtin_strchr (quote + 1, '"')))
)) {
3434 *eol_pnt = '\0';
3435 }
3436 return quote + 1;
3437 }
3438}
3439
3440static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
3441{
3442 struct vm_state *vms_p;
3443
3444 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
3445 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
3446 return vms_p;
3447 }
3448 ast_debug(5, "Adding new vmstate for %s\n", vmu->imapuser)do { if ((option_debug >= (5) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (5)))) { ast_log
(0, "app_voicemail.c", 3448, __PRETTY_FUNCTION__, "Adding new vmstate for %s\n"
, vmu->imapuser); } } while (0)
;
3449 /* XXX: Is this correctly freed always? */
3450 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))_ast_calloc((1), (sizeof(*vms_p)), "app_voicemail.c", 3450, __PRETTY_FUNCTION__
)
))
3451 return NULL((void*)0);
3452 ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
3453 ast_copy_string(vms_p->imapfolder, vmu->imapfolder, sizeof(vms_p->imapfolder));
3454 ast_copy_string(vms_p->imapserver, vmu->imapserver, sizeof(vms_p->imapserver));
3455 ast_copy_string(vms_p->imapport, vmu->imapport, sizeof(vms_p->imapport));
3456 ast_copy_string(vms_p->imapflags, vmu->imapflags, sizeof(vms_p->imapflags));
3457 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username)); /* save for access from interactive entry point */
3458 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
3459 vms_p->mailstream = NIL; /* save for access from interactive entry point */
3460 vms_p->imapversion = vmu->imapversion;
3461 ast_debug(5, "Copied %s to %s\n", vmu->imapuser, vms_p->imapuser)do { if ((option_debug >= (5) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (5)))) { ast_log
(0, "app_voicemail.c", 3461, __PRETTY_FUNCTION__, "Copied %s to %s\n"
, vmu->imapuser, vms_p->imapuser); } } while (0)
;
3462 vms_p->updated = 1;
3463 /* set mailbox to INBOX! */
3464 ast_copy_string(vms_p->curbox, mbox(vmu, 0), sizeof(vms_p->curbox));
3465 init_vm_state(vms_p);
3466 vmstate_insert(vms_p);
3467 return vms_p;
3468}
3469
3470static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
3471{
3472 struct vmstate *vlist = NULL((void*)0);
3473
3474 if (interactive) {
3475 struct vm_state *vms;
3476 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
3477 if ((vms = pthread_getspecific(ts_vmstate.key)) && vms->imapuser && !strcmp(vms->imapuser, user)) {
3478 return vms;
3479 }
3480 }
3481
3482 AST_LIST_LOCK(&vmstates)__ast_pthread_mutex_lock("app_voicemail.c", 3482, __PRETTY_FUNCTION__
, "&(&vmstates)->lock", &(&vmstates)->lock
)
;
3483 AST_LIST_TRAVERSE(&vmstates, vlist, list)for((vlist) = (&vmstates)->first; (vlist); (vlist) = (
vlist)->list.next)
{
3484 if (!vlist->vms) {
3485 ast_debug(3, "error: vms is NULL for %s\n", user)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 3485, __PRETTY_FUNCTION__, "error: vms is NULL for %s\n"
, user); } } while (0)
;
3486 continue;
3487 }
3488 if (vlist->vms->imapversion != imapversion) {
3489 continue;
3490 }
3491 if (!vlist->vms->imapuser) {
3492 ast_debug(3, "error: imapuser is NULL for %s\n", user)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 3492, __PRETTY_FUNCTION__, "error: imapuser is NULL for %s\n"
, user); } } while (0)
;
3493 continue;
3494 }
3495
3496 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
3497 AST_LIST_UNLOCK(&vmstates)__ast_pthread_mutex_unlock("app_voicemail.c", 3497, __PRETTY_FUNCTION__
, "&(&vmstates)->lock", &(&vmstates)->lock
)
;
3498 return vlist->vms;
3499 }
3500 }
3501 AST_LIST_UNLOCK(&vmstates)__ast_pthread_mutex_unlock("app_voicemail.c", 3501, __PRETTY_FUNCTION__
, "&(&vmstates)->lock", &(&vmstates)->lock
)
;
3502
3503 ast_debug(3, "%s not found in vmstates\n", user)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 3503, __PRETTY_FUNCTION__, "%s not found in vmstates\n"
, user); } } while (0)
;
3504
3505 return NULL((void*)0);
3506}
3507
3508static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
3509{
3510
3511 struct vmstate *vlist = NULL((void*)0);
3512 const char *local_context = S_OR(context, "default")({typeof(&((context)[0])) __x = (context); _ast_strlen_zero
(__x, "app_voicemail.c", __PRETTY_FUNCTION__, 3512) ? ("default"
) : __x;})
;
3513
3514 if (interactive) {
3515 struct vm_state *vms;
3516 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
3517 if ((vms = pthread_getspecific(ts_vmstate.key)) && vms->username && vms->context &&
3518 !strcmp(vms->username,mailbox) && !strcmp(vms->context, local_context)) {
3519 return vms;
3520 }
3521 }
3522
3523 AST_LIST_LOCK(&vmstates)__ast_pthread_mutex_lock("app_voicemail.c", 3523, __PRETTY_FUNCTION__
, "&(&vmstates)->lock", &(&vmstates)->lock
)
;
3524 AST_LIST_TRAVERSE(&vmstates, vlist, list)for((vlist) = (&vmstates)->first; (vlist); (vlist) = (
vlist)->list.next)
{
3525 if (!vlist->vms) {
3526 ast_debug(3, "error: vms is NULL for %s\n", mailbox)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 3526, __PRETTY_FUNCTION__, "error: vms is NULL for %s\n"
, mailbox); } } while (0)
;
3527 continue;
3528 }
3529 if (vlist->vms->imapversion != imapversion) {
3530 continue;
3531 }
3532 if (!vlist->vms->username || !vlist->vms->context) {
3533 ast_debug(3, "error: username is NULL for %s\n", mailbox)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 3533, __PRETTY_FUNCTION__, "error: username is NULL for %s\n"
, mailbox); } } while (0)
;
3534 continue;
3535 }
3536
3537 ast_debug(3, "comparing mailbox %s@%s (i=%d) to vmstate mailbox %s@%s (i=%d)\n", mailbox, local_context, interactive, vlist->vms->username, vlist->vms->context, vlist->vms->interactive)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 3537, __PRETTY_FUNCTION__, "comparing mailbox %s@%s (i=%d) to vmstate mailbox %s@%s (i=%d)\n"
, mailbox, local_context, interactive, vlist->vms->username
, vlist->vms->context, vlist->vms->interactive); }
} while (0)
;
3538
3539 if (!strcmp(vlist->vms->username, mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
3540 ast_debug(3, "Found it!\n")do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 3540, __PRETTY_FUNCTION__, "Found it!\n"
); } } while (0)
;
3541 AST_LIST_UNLOCK(&vmstates)__ast_pthread_mutex_unlock("app_voicemail.c", 3541, __PRETTY_FUNCTION__
, "&(&vmstates)->lock", &(&vmstates)->lock
)
;
3542 return vlist->vms;
3543 }
3544 }
3545 AST_LIST_UNLOCK(&vmstates)__ast_pthread_mutex_unlock("app_voicemail.c", 3545, __PRETTY_FUNCTION__
, "&(&vmstates)->lock", &(&vmstates)->lock
)
;
3546
3547 ast_debug(3, "%s not found in vmstates\n", mailbox)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 3547, __PRETTY_FUNCTION__, "%s not found in vmstates\n"
, mailbox); } } while (0)
;
3548
3549 return NULL((void*)0);
3550}
3551
3552static void vmstate_insert(struct vm_state *vms)
3553{
3554 struct vmstate *v;
3555 struct vm_state *altvms;
3556
3557 /* If interactive, it probably already exists, and we should
3558 use the one we already have since it is more up to date.
3559 We can compare the username to find the duplicate */
3560 if (vms->interactive == 1) {
3561 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
3562 if (altvms) {
3563 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 3563, __PRETTY_FUNCTION__, "Duplicate mailbox %s, copying message info...\n"
, vms->username); } } while (0)
;
3564 vms->newmessages = altvms->newmessages;
3565 vms->oldmessages = altvms->oldmessages;
3566 vms->vmArrayIndex = altvms->vmArrayIndex;
3567 /* XXX: no msgArray copying? */
3568 vms->lastmsg = altvms->lastmsg;
3569 vms->curmsg = altvms->curmsg;
3570 /* get a pointer to the persistent store */
3571 vms->persist_vms = altvms;
3572 /* Reuse the mailstream? */
3573#ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
3574 vms->mailstream = altvms->mailstream;
3575#else
3576 vms->mailstream = NIL;
3577#endif
3578 }
3579 return;
3580 }
3581
3582 if (!(v = ast_calloc(1, sizeof(*v))_ast_calloc((1), (sizeof(*v)), "app_voicemail.c", 3582, __PRETTY_FUNCTION__
)
))
3583 return;
3584
3585 v->vms = vms;
3586
3587 ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 3587, __PRETTY_FUNCTION__, "Inserting vm_state for user:%s, mailbox %s\n"
, vms->imapuser, vms->username); } } while (0)
;
3588
3589 AST_LIST_LOCK(&vmstates)__ast_pthread_mutex_lock("app_voicemail.c", 3589, __PRETTY_FUNCTION__
, "&(&vmstates)->lock", &(&vmstates)->lock
)
;
3590 AST_LIST_INSERT_TAIL(&vmstates, v, list)do { if (!(&vmstates)->first) { (&vmstates)->first
= (v); (&vmstates)->last = (v); } else { (&vmstates
)->last->list.next = (v); (&vmstates)->last = (v
); } } while (0)
;
3591 AST_LIST_UNLOCK(&vmstates)__ast_pthread_mutex_unlock("app_voicemail.c", 3591, __PRETTY_FUNCTION__
, "&(&vmstates)->lock", &(&vmstates)->lock
)
;
3592}
3593
3594static void vmstate_delete(struct vm_state *vms)
3595{
3596 struct vmstate *vc = NULL((void*)0);
3597 struct vm_state *altvms = NULL((void*)0);
3598
3599 /* If interactive, we should copy pertinent info
3600 back to the persistent state (to make update immediate) */
3601 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
3602 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 3602, __PRETTY_FUNCTION__, "Duplicate mailbox %s, copying message info...\n"
, vms->username); } } while (0)
;
3603 altvms->newmessages = vms->newmessages;
3604 altvms->oldmessages = vms->oldmessages;
3605 altvms->updated = 1;
3606 vms->mailstream = mail_close(vms->mailstream);
3607
3608 /* Interactive states are not stored within the persistent list */
3609 return;
3610 }
3611
3612 ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 3612, __PRETTY_FUNCTION__, "Removing vm_state for user:%s, mailbox %s\n"
, vms->imapuser, vms->username); } } while (0)
;
3613
3614 AST_LIST_LOCK(&vmstates)__ast_pthread_mutex_lock("app_voicemail.c", 3614, __PRETTY_FUNCTION__
, "&(&vmstates)->lock", &(&vmstates)->lock
)
;
3615 AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list){ typeof((&vmstates)) __list_head = &vmstates; typeof
(__list_head->first) __list_next; typeof(__list_head->first
) __list_prev = ((void*)0); typeof(__list_head->first) __list_current
; for ((vc) = __list_head->first, __list_current = (vc), __list_next
= (vc) ? (vc)->list.next : ((void*)0); (vc); __list_prev =
__list_current, (vc) = __list_next, __list_current = (vc), __list_next
= (vc) ? (vc)->list.next : ((void*)0), (void) __list_prev
)
{
3616 if (vc->vms == vms) {
3617 AST_LIST_REMOVE_CURRENT(list)do { __list_current->list.next = ((void*)0); __list_current
= __list_prev; if (__list_prev) { __list_prev->list.next =
__list_next; } else { __list_head->first = __list_next; }
if (!__list_next) { __list_head->last = __list_prev; } } while
(0)
;
3618 break;
3619 }
3620 }
3621 AST_LIST_TRAVERSE_SAFE_END}
3622 AST_LIST_UNLOCK(&vmstates)__ast_pthread_mutex_unlock("app_voicemail.c", 3622, __PRETTY_FUNCTION__
, "&(&vmstates)->lock", &(&vmstates)->lock
)
;
3623
3624 if (vc) {
3625 ast_mutex_destroy(&vc->vms->lock)__ast_pthread_mutex_destroy("app_voicemail.c", 3625, __PRETTY_FUNCTION__
, "&vc->vms->lock", &vc->vms->lock)
;
3626 ast_freefree(vc->vms->msgArray);
3627 vc->vms->msgArray = NULL((void*)0);
3628 vc->vms->msg_array_max = 0;
3629 /* XXX: is no one supposed to free vms itself? */
3630 ast_freefree(vc);
3631 } else {
3632 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 3632, __PRETTY_FUNCTION__, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
3633 }
3634}
3635
3636static void set_update(MAILSTREAM * stream)
3637{
3638 struct vm_state *vms;
3639 char *mailbox = stream->mailbox, *user;
3640 char buf[1024] = "";
3641
3642 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
3643 if (user && option_debug > 2)
3644 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 3644, __PRETTY_FUNCTION__, "User %s mailbox not found for update.\n", user);
3645 return;
3646 }
3647
3648 ast_debug(3, "User %s mailbox set for update.\n", user)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 3648, __PRETTY_FUNCTION__, "User %s mailbox set for update.\n"
, user); } } while (0)
;
3649
3650 vms->updated = 1; /* Set updated flag since mailbox changed */
3651}
3652
3653static void init_vm_state(struct vm_state *vms)
3654{
3655 vms->msg_array_max = VMSTATE_MAX_MSG_ARRAY256;
3656 vms->msgArray = ast_calloc(vms->msg_array_max, sizeof(long))_ast_calloc((vms->msg_array_max), (sizeof(long)), "app_voicemail.c"
, 3656, __PRETTY_FUNCTION__)
;
3657 if (!vms->msgArray) {
3658 /* Out of mem? This can't be good. */
3659 vms->msg_array_max = 0;
3660 }
3661 vms->vmArrayIndex = 0;
3662 ast_mutex_init(&vms->lock)__ast_pthread_mutex_init(1, "app_voicemail.c", 3662, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
3663}
3664
3665static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro)
3666{
3667 char *body_content;
3668 char *body_decoded;
3669 char *fn = is_intro ? vms->introfn : vms->fn;
3670 unsigned long len = 0;
3671 unsigned long newlen = 0;
3672 char filename[256];
3673
3674 if (!body || body == NIL)
3675 return -1;
3676
3677 ast_mutex_lock(&vms->lock)__ast_pthread_mutex_lock("app_voicemail.c", 3677, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
3678 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
3679 ast_mutex_unlock(&vms->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 3679, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
3680 if (len > MAX_MAIL_BODY_CONTENT_SIZE134217728L) {
3681 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 3681, __PRETTY_FUNCTION__,
3682 "Msgno %ld, section %s. The body's content size %ld is huge (max %ld). User:%s, mailbox %s\n",
3683 vms->msgArray[vms->curmsg], section, len, MAX_MAIL_BODY_CONTENT_SIZE134217728L, vms->imapuser, vms->username);
3684 return -1;
3685 }
3686 if (body_content != NIL && len) {
3687 snprintf(filename, sizeof(filename), "%s.%s", fn, format);
3688 /* ast_debug(1, body_content); */
3689 body_decoded = rfc822_base64((unsigned char *) body_content, len, &newlen);
3690 /* If the body of the file is empty, return an error */
3691 if (!newlen || !body_decoded) {
3692 return -1;
3693 }
3694 write_file(filename, (char *) body_decoded, newlen);
3695 } else {
3696 ast_debug(5, "Body of message is NULL.\n")do { if ((option_debug >= (5) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (5)))) { ast_log
(0, "app_voicemail.c", 3696, __PRETTY_FUNCTION__, "Body of message is NULL.\n"
); } } while (0)
;
3697 return -1;
3698 }
3699 return 0;
3700}
3701
3702/*!
3703 * \brief Get delimiter via mm_list callback
3704 * \param vms The voicemail state object
3705 * \param stream
3706 *
3707 * Determines the delimiter character that is used by the underlying IMAP based mail store.
3708 */
3709/* MUTEX should already be held */
3710static void get_mailbox_delimiter(struct vm_state *vms, MAILSTREAM *stream) {
3711 char tmp[50];
3712 snprintf(tmp, sizeof(tmp), "{%s}", S_OR(vms->imapserver, imapserver)({typeof(&((vms->imapserver)[0])) __x = (vms->imapserver
); _ast_strlen_zero(__x, "app_voicemail.c", __PRETTY_FUNCTION__
, 3712) ? (imapserver) : __x;})
);
3713 mail_list(stream, tmp, "*");
3714}
3715
3716/*!
3717 * \brief Check Quota for user
3718 * \param vms a pointer to a vm_state struct, will use the mailstream property of this.
3719 * \param mailbox the mailbox to check the quota for.
3720 *
3721 * Calls imap_getquotaroot, which will populate its results into the vm_state vms input structure.
3722 */
3723static void check_quota(struct vm_state *vms, char *mailbox) {
3724 ast_mutex_lock(&vms->lock)__ast_pthread_mutex_lock("app_voicemail.c", 3724, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
3725 mail_parameters(NULL((void*)0), SET_QUOTA, (void *) mm_parsequota);
3726 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 3726, __PRETTY_FUNCTION__, "Mailbox name set to: %s, about to check quotas\n"
, mailbox); } } while (0)
;
3727 if (vms && vms->mailstream != NULL((void*)0)) {
3728 imap_getquotaroot(vms->mailstream, mailbox);
3729 } else {
3730 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 3730, __PRETTY_FUNCTION__, "Mailstream not available for mailbox: %s\n", mailbox);
3731 }
3732 ast_mutex_unlock(&vms->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 3732, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
3733}
3734
3735#endif /* IMAP_STORAGE */
3736
3737/*! \brief Lock file path
3738 * only return failure if ast_lock_path returns 'timeout',
3739 * not if the path does not exist or any other reason
3740 */
3741static int vm_lock_path(const char *path)
3742{
3743 switch (ast_lock_path(path)) {
3744 case AST_LOCK_TIMEOUT:
3745 return -1;
3746 default:
3747 return 0;
3748 }
3749}
3750
3751#define MSG_ID_LEN256 256
3752
3753/* Used to attach a unique identifier to an msg_id */
3754static int msg_id_incrementor;
3755
3756/*!
3757 * \brief Sets the destination string to a uniquely identifying msg_id string
3758 * \param dst pointer to a character buffer that should contain MSG_ID_LEN characters.
3759 */
3760static void generate_msg_id(char *dst);
3761
3762#ifdef ODBC_STORAGE
3763struct generic_prepare_struct {
3764 char *sql;
3765 int argc;
3766 char **argv;
3767};
3768
3769static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
3770{
3771 struct generic_prepare_struct *gps = data;
3772 int res, i;
3773 SQLHSTMT stmt;
3774
3775 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
3776 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3777 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 3777, __PRETTY_FUNCTION__, "SQL Alloc Handle failed!\n");
3778 return NULL((void*)0);
3779 }
3780 res = SQLPrepare(stmt, (unsigned char *) gps->sql, SQL_NTS);
3781 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3782 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 3782, __PRETTY_FUNCTION__, "SQL Prepare failed![%s]\n", gps->sql);
3783 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
3784 return NULL((void*)0);
3785 }
3786 for (i = 0; i < gps->argc; i++)
3787 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL((void*)0));
3788
3789 return stmt;
3790}
3791
3792static void odbc_update_msg_id(char *dir, int msg_num, char *msg_id)
3793{
3794 SQLHSTMT stmt;
3795 char sql[PATH_MAX4096];
3796 struct odbc_obj *obj;
3797 char msg_num_str[20];
3798 char *argv[] = { msg_id, dir, msg_num_str };
3799 struct generic_prepare_struct gps = { .sql = sql, .argc = 3, .argv = argv };
3800
3801 obj = ast_odbc_request_obj(odbc_database, 0);
3802 if (!obj) {
3803 ast_log(LOG_WARNING3, "app_voicemail.c", 3803, __PRETTY_FUNCTION__, "Unable to update message ID for message %d in %s\n", msg_num, dir);
3804 return;
3805 }
3806
3807 snprintf(msg_num_str, sizeof(msg_num_str), "%d", msg_num);
3808 snprintf(sql, sizeof(sql), "UPDATE %s SET msg_id=? WHERE dir=? AND msgnum=?", odbc_table);
3809 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
3810 if (!stmt) {
3811 ast_log(LOG_WARNING3, "app_voicemail.c", 3811, __PRETTY_FUNCTION__, "SQL Execute error!\n[%s]\n\n", sql);
3812 } else {
3813 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
3814 }
3815 ast_odbc_release_obj(obj);
3816 return;
3817}
3818
3819/*!
3820 * \brief Retrieves a file from an ODBC data store.
3821 * \param dir the path to the file to be retrieved.
3822 * \param msgnum the message number, such as within a mailbox folder.
3823 *
3824 * This method is used by the RETRIEVE macro when mailboxes are stored in an ODBC back end.
3825 * The purpose is to get the message from the database store to the local file system, so that the message may be played, or the information file may be read.
3826 *
3827 * The file is looked up by invoking a SQL on the odbc_table (default 'voicemessages') using the dir and msgnum input parameters.
3828 * The output is the message information file with the name msgnum and the extension .txt
3829 * and the message file with the extension of its format, in the directory with base file name of the msgnum.
3830 *
3831 * \return 0 on success, -1 on error.
3832 */
3833static int retrieve_file(char *dir, int msgnum)
3834{
3835 int x = 0;
3836 int res;
3837 int fd = -1;
3838 size_t fdlen = 0;
3839 void *fdm = MAP_FAILED((void *) -1);
3840 SQLSMALLINT colcount = 0;
3841 SQLHSTMT stmt;
3842 char sql[PATH_MAX4096];
3843 char fmt[80]="";
3844 char *c;
3845 char coltitle[256];
3846 SQLSMALLINT collen;
3847 SQLSMALLINT datatype;
3848 SQLSMALLINT decimaldigits;
3849 SQLSMALLINT nullable;
3850 SQLULEN colsize;
3851 SQLLEN colsize2;
3852 FILE *f = NULL((void*)0);
3853 char rowdata[80];
3854 char fn[PATH_MAX4096];
3855 char full_fn[PATH_MAX4096];
3856 char msgnums[80];
3857 char *argv[] = { dir, msgnums };
3858 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
3859
3860 struct odbc_obj *obj;
3861 obj = ast_odbc_request_obj(odbc_database, 0);
3862 if (obj) {
3863 ast_copy_string(fmt, vmfmts, sizeof(fmt));
3864 c = strchr(fmt, '|')(__extension__ (__builtin_constant_p ('|') && !__builtin_constant_p
(fmt) && ('|') == '\0' ? (char *) __rawmemchr (fmt, '|'
) : __builtin_strchr (fmt, '|')))
;
3865 if (c)
3866 *c = '\0';
3867 if (!strcasecmp(fmt, "wav49"))
3868 strcpy(fmt, "WAV");
3869 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
3870 if (msgnum > -1)
3871 make_file(fn, sizeof(fn), dir, msgnum);
3872 else
3873 ast_copy_string(fn, dir, sizeof(fn));
3874
3875 /* Create the information file */
3876 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
3877
3878 if (!(f = fopen(full_fn, "w+"))) {
3879 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 3879, __PRETTY_FUNCTION__, "Failed to open/create '%s'\n", full_fn);
3880 goto yuck;
3881 }
3882
3883 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
3884 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
3885 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
3886 if (!stmt) {
3887 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 3887, __PRETTY_FUNCTION__, "SQL Execute error!\n[%s]\n\n", sql);
3888 ast_odbc_release_obj(obj);
3889 goto yuck;
3890 }
3891 res = SQLFetch(stmt);
3892 if (res == SQL_NO_DATA) {
3893 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3894 ast_odbc_release_obj(obj);
3895 goto yuck;
3896 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3897 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 3897, __PRETTY_FUNCTION__, "SQL Fetch error!\n[%s]\n\n", sql);
3898 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3899 ast_odbc_release_obj(obj);
3900 goto yuck;
3901 }
3902 fd = open(full_fn, O_RDWR02 | O_CREAT0100 | O_TRUNC01000, VOICEMAIL_FILE_MODE0666);
3903 if (fd < 0) {
3904 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 3904, __PRETTY_FUNCTION__, "Failed to write '%s': %s\n", full_fn, strerror(errno(*__errno_location ())));
3905 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3906 ast_odbc_release_obj(obj);
3907 goto yuck;
3908 }
3909 res = SQLNumResultCols(stmt, &colcount);
3910 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3911 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 3911, __PRETTY_FUNCTION__, "SQL Column Count error!\n[%s]\n\n", sql);
3912 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3913 ast_odbc_release_obj(obj);
3914 goto yuck;
3915 }
3916 if (f)
3917 fprintf(f, "[message]\n");
3918 for (x = 0; x < colcount; x++) {
3919 rowdata[0] = '\0';
3920 colsize = 0;
3921 collen = sizeof(coltitle);
3922 res = SQLDescribeCol(stmt, x + 1, (unsigned char *) coltitle, sizeof(coltitle), &collen,
3923 &datatype, &colsize, &decimaldigits, &nullable);
3924 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3925 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 3925, __PRETTY_FUNCTION__, "SQL Describe Column error!\n[%s]\n\n", sql);
3926 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3927 ast_odbc_release_obj(obj);
3928 goto yuck;
3929 }
3930 if (!strcasecmp(coltitle, "recording")) {
3931 off_t offset;
3932 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
3933 fdlen = colsize2;
3934 if (fd > -1) {
3935 char tmp[1]="";
3936 lseek(fd, fdlen - 1, SEEK_SET0);
3937 if (write(fd, tmp, 1) != 1) {
3938 close(fd);
3939 fd = -1;
3940 continue;
3941 }
3942 /* Read out in small chunks */
3943 for (offset = 0; offset < colsize2; offset += CHUNKSIZE65536) {
3944 if ((fdm = mmap(NULL((void*)0), CHUNKSIZE65536, PROT_READ0x1 | PROT_WRITE0x2, MAP_SHARED0x01, fd, offset)) == MAP_FAILED((void *) -1)) {
3945 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 3945, __PRETTY_FUNCTION__, "Could not mmap the output file: %s (%d)\n", strerror(errno(*__errno_location ())), errno(*__errno_location ()));
3946 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
3947 ast_odbc_release_obj(obj);
3948 goto yuck;
3949 } else {
3950 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE65536, NULL((void*)0));
3951 munmap(fdm, CHUNKSIZE65536);
3952 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3953 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 3953, __PRETTY_FUNCTION__, "SQL Get Data error!\n[%s]\n\n", sql);
3954 unlink(full_fn);
3955 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
3956 ast_odbc_release_obj(obj);
3957 goto yuck;
3958 }
3959 }
3960 }
3961 if (truncate(full_fn, fdlen) < 0) {
3962 ast_log(LOG_WARNING3, "app_voicemail.c", 3962, __PRETTY_FUNCTION__, "Unable to truncate '%s': %s\n", full_fn, strerror(errno(*__errno_location ())));
3963 }
3964 }
3965 } else {
3966 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL((void*)0));
3967 if ((res == SQL_NULL_DATA) && (!strcasecmp(coltitle, "msg_id"))) {
3968 char msg_id[MSG_ID_LEN256];
3969 generate_msg_id(msg_id);
3970 snprintf(rowdata, sizeof(rowdata), "%s", msg_id);
3971 odbc_update_msg_id(dir, msgnum, msg_id);
3972 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3973 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 3973, __PRETTY_FUNCTION__, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
3974 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3975 ast_odbc_release_obj(obj);
3976 goto yuck;
3977 }
3978 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
3979 fprintf(f, "%s=%s\n", coltitle, rowdata);
3980 }
3981 }
3982 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3983 ast_odbc_release_obj(obj);
3984 } else
3985 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 3985, __PRETTY_FUNCTION__, "Failed to obtain database object for '%s'!\n", odbc_database);
3986yuck:
3987 if (f)
3988 fclose(f);
3989 if (fd > -1)
3990 close(fd);
3991 return x - 1;
3992}
3993
3994/*!
3995 * \brief Determines the highest message number in use for a given user and mailbox folder.
3996 * \param vmu
3997 * \param dir the folder the mailbox folder to look for messages. Used to construct the SQL where clause.
3998 *
3999 * This method is used when mailboxes are stored in an ODBC back end.
4000 * Typical use to set the msgnum would be to take the value returned from this method and add one to it.
4001 *
4002 * \return the value of zero or greater to indicate the last message index in use, -1 to indicate none.
4003
4004 */
4005static int last_message_index(struct ast_vm_user *vmu, char *dir)
4006{
4007 int x = 0;
4008 int res;
4009 SQLHSTMT stmt;
4010 char sql[PATH_MAX4096];
4011 char rowdata[20];
4012 char *argv[] = { dir };
4013 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
4014
4015 struct odbc_obj *obj;
4016 obj = ast_odbc_request_obj(odbc_database, 0);
4017 if (obj) {
4018 snprintf(sql, sizeof(sql), "SELECT msgnum FROM %s WHERE dir=? order by msgnum desc", odbc_table);
4019
4020 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
4021 if (!stmt) {
4022 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4022, __PRETTY_FUNCTION__, "SQL Execute error!\n[%s]\n\n", sql);
4023 ast_odbc_release_obj(obj);
4024 goto yuck;
4025 }
4026 res = SQLFetch(stmt);
4027 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
4028 if (res == SQL_NO_DATA) {
4029 ast_log(AST_LOG_DEBUG0, "app_voicemail.c", 4029, __PRETTY_FUNCTION__, "Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
4030 } else {
4031 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4031, __PRETTY_FUNCTION__, "SQL Fetch error!\n[%s]\n\n", sql);
4032 }
4033
4034 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
4035 ast_odbc_release_obj(obj);
4036 goto yuck;
4037 }
4038 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL((void*)0));
4039 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
4040 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4040, __PRETTY_FUNCTION__, "SQL Get Data error!\n[%s]\n\n", sql);
4041 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
4042 ast_odbc_release_obj(obj);
4043 goto yuck;
4044 }
4045 if (sscanf(rowdata, "%30d", &x) != 1)
4046 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4046, __PRETTY_FUNCTION__, "Failed to read message index!\n");
4047 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
4048 ast_odbc_release_obj(obj);
4049 return x;
4050 } else
4051 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4051, __PRETTY_FUNCTION__, "Failed to obtain database object for '%s'!\n", odbc_database);
4052yuck:
4053 return x - 1;
4054}
4055
4056/*!
4057 * \brief Determines if the specified message exists.
4058 * \param dir the folder the mailbox folder to look for messages.
4059 * \param msgnum the message index to query for.
4060 *
4061 * This method is used when mailboxes are stored in an ODBC back end.
4062 *
4063 * \return greater than zero if the message exists, zero when the message does not exist or on error.
4064 */
4065static int message_exists(char *dir, int msgnum)
4066{
4067 int x = 0;
4068 int res;
4069 SQLHSTMT stmt;
4070 char sql[PATH_MAX4096];
4071 char rowdata[20];
4072 char msgnums[20];
4073 char *argv[] = { dir, msgnums };
4074 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
4075
4076 struct odbc_obj *obj;
4077 obj = ast_odbc_request_obj(odbc_database, 0);
4078 if (obj) {
4079 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
4080 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table);
4081 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
4082 if (!stmt) {
4083 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4083, __PRETTY_FUNCTION__, "SQL Execute error!\n[%s]\n\n", sql);
4084 ast_odbc_release_obj(obj);
4085 goto yuck;
4086 }
4087 res = SQLFetch(stmt);
4088 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
4089 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4089, __PRETTY_FUNCTION__, "SQL Fetch error!\n[%s]\n\n", sql);
4090 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
4091 ast_odbc_release_obj(obj);
4092 goto yuck;
4093 }
4094 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL((void*)0));
4095 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
4096 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4096, __PRETTY_FUNCTION__, "SQL Get Data error!\n[%s]\n\n", sql);
4097 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
4098 ast_odbc_release_obj(obj);
4099 goto yuck;
4100 }
4101 if (sscanf(rowdata, "%30d", &x) != 1)
4102 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4102, __PRETTY_FUNCTION__, "Failed to read message count!\n");
4103 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
4104 ast_odbc_release_obj(obj);
4105 } else
4106 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4106, __PRETTY_FUNCTION__, "Failed to obtain database object for '%s'!\n", odbc_database);
4107yuck:
4108 return x;
4109}
4110
4111/*!
4112 * \brief returns the number of messages found.
4113 * \param vmu
4114 * \param dir the folder the mailbox folder to look for messages. Used to construct the SQL where clause.
4115 *
4116 * This method is used when mailboxes are stored in an ODBC back end.
4117 *
4118 * \return The count of messages being zero or more, less than zero on error.
4119 */
4120static int count_messages(struct ast_vm_user *vmu, char *dir)
4121{
4122 int x = 0;
4123 int res;
4124 SQLHSTMT stmt;
4125 char sql[PATH_MAX4096];
4126 char rowdata[20];
4127 char *argv[] = { dir };
4128 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
4129
4130 struct odbc_obj *obj;
4131 obj = ast_odbc_request_obj(odbc_database, 0);
4132 if (obj) {
4133 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
4134 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
4135 if (!stmt) {
4136 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4136, __PRETTY_FUNCTION__, "SQL Execute error!\n[%s]\n\n", sql);
4137 ast_odbc_release_obj(obj);
4138 goto yuck;
4139 }
4140 res = SQLFetch(stmt);
4141 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
4142 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4142, __PRETTY_FUNCTION__, "SQL Fetch error!\n[%s]\n\n", sql);
4143 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
4144 ast_odbc_release_obj(obj);
4145 goto yuck;
4146 }
4147 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL((void*)0));
4148 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
4149 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4149, __PRETTY_FUNCTION__, "SQL Get Data error!\n[%s]\n\n", sql);
4150 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
4151 ast_odbc_release_obj(obj);
4152 goto yuck;
4153 }
4154 if (sscanf(rowdata, "%30d", &x) != 1)
4155 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4155, __PRETTY_FUNCTION__, "Failed to read message count!\n");
4156 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
4157 ast_odbc_release_obj(obj);
4158 return x;
4159 } else
4160 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4160, __PRETTY_FUNCTION__, "Failed to obtain database object for '%s'!\n", odbc_database);
4161yuck:
4162 return x - 1;
4163
4164}
4165
4166/*!
4167 * \brief Deletes a message from the mailbox folder.
4168 * \param sdir The mailbox folder to work in.
4169 * \param smsg The message index to be deleted.
4170 *
4171 * This method is used when mailboxes are stored in an ODBC back end.
4172 * The specified message is directly deleted from the database 'voicemessages' table.
4173 *
4174 * \return the value greater than zero on success to indicate the number of messages, less than zero on error.
4175 */
4176static void delete_file(const char *sdir, int smsg)
4177{
4178 SQLHSTMT stmt;
4179 char sql[PATH_MAX4096];
4180 char msgnums[20];
4181 char *argv[] = { NULL((void*)0), msgnums };
4182 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
4183 struct odbc_obj *obj;
4184
4185 argv[0] = ast_strdupa(sdir)(__extension__ ({ const char *__old = (sdir); size_t __len = strlen
(__old) + 1; char *__new = __builtin_alloca(__len); memcpy (__new
, __old, __len); __new; }))
;
4186
4187 obj = ast_odbc_request_obj(odbc_database, 0);
4188 if (obj) {
4189 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
4190 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table);
4191 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
4192 if (!stmt)
4193 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4193, __PRETTY_FUNCTION__, "SQL Execute error!\n[%s]\n\n", sql);
4194 else
4195 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
4196 ast_odbc_release_obj(obj);
4197 } else
4198 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4198, __PRETTY_FUNCTION__, "Failed to obtain database object for '%s'!\n", odbc_database);
4199 return;
4200}
4201
4202/*!
4203 * \brief Copies a voicemail from one mailbox to another.
4204 * \param sdir the folder for which to look for the message to be copied.
4205 * \param smsg the index of the message to be copied.
4206 * \param ddir the destination folder to copy the message into.
4207 * \param dmsg the index to be used for the copied message.
4208 * \param dmailboxuser The user who owns the mailbox tha contains the destination folder.
4209 * \param dmailboxcontext The context for the destination user.
4210 *
4211 * This method is used for the COPY macro when mailboxes are stored in an ODBC back end.
4212 */
4213static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
4214{
4215 SQLHSTMT stmt;
4216 char sql[512];
4217 char msgnums[20];
4218 char msgnumd[20];
4219 char msg_id[MSG_ID_LEN256];
4220 struct odbc_obj *obj;
4221 char *argv[] = { ddir, msgnumd, msg_id, dmailboxuser, dmailboxcontext, sdir, msgnums };
4222 struct generic_prepare_struct gps = { .sql = sql, .argc = 7, .argv = argv };
4223
4224 generate_msg_id(msg_id);
4225 delete_file(ddir, dmsg);
4226 obj = ast_odbc_request_obj(odbc_database, 0);
4227 if (obj) {
4228 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
4229 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
4230 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir, msgnum, msg_id, context, macrocontext, callerid, origtime, duration, recording, flag, mailboxuser, mailboxcontext) SELECT ?,?,?,context,macrocontext,callerid,origtime,duration,recording,flag,?,? FROM %s WHERE dir=? AND msgnum=?", odbc_table, odbc_table);
4231 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
4232 if (!stmt)
4233 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4233, __PRETTY_FUNCTION__, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
4234 else
4235 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4236 ast_odbc_release_obj(obj);
4237 } else
4238 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4238, __PRETTY_FUNCTION__, "Failed to obtain database object for '%s'!\n", odbc_database);
4239 return;
4240}
4241
4242struct insert_data {
4243 char *sql;
4244 const char *dir;
4245 const char *msgnums;
4246 void *data;
4247 SQLLEN datalen;
4248 SQLLEN indlen;
4249 const char *context;
4250 const char *macrocontext;
4251 const char *callerid;
4252 const char *origtime;
4253 const char *duration;
4254 const char *mailboxuser;
4255 const char *mailboxcontext;
4256 const char *category;
4257 const char *flag;
4258 const char *msg_id;
4259};
4260
4261static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
4262{
4263 struct insert_data *data = vdata;
4264 int res;
4265 SQLHSTMT stmt;
4266
4267 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
4268 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
4269 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4269, __PRETTY_FUNCTION__, "SQL Alloc Handle failed!\n");
4270 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4271 return NULL((void*)0);
4272 }
4273
4274 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (void *) data->dir, 0, NULL((void*)0));
4275 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (void *) data->msgnums, 0, NULL((void*)0));
4276 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (void *) data->data, data->datalen, &data->indlen);
4277 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (void *) data->context, 0, NULL((void*)0));
4278 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (void *) data->macrocontext, 0, NULL((void*)0));
4279 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (void *) data->callerid, 0, NULL((void*)0));
4280 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (void *) data->origtime, 0, NULL((void*)0));
4281 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (void *) data->duration, 0, NULL((void*)0));
4282 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (void *) data->mailboxuser, 0, NULL((void*)0));
4283 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (void *) data->mailboxcontext, 0, NULL((void*)0));
4284 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (void *) data->flag, 0, NULL((void*)0));
4285 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msg_id), 0, (void *) data->msg_id, 0, NULL((void*)0));
4286 if (!ast_strlen_zero(data->category)_ast_strlen_zero(data->category, "app_voicemail.c", __PRETTY_FUNCTION__
, 4286)
) {
4287 SQLBindParameter(stmt, 13, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *) data->category, 0, NULL((void*)0));
4288 }
4289 res = SQLExecDirect(stmt, (unsigned char *) data->sql, SQL_NTS);
4290 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
4291 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4291, __PRETTY_FUNCTION__, "SQL Direct Execute failed!\n");
4292 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4293 return NULL((void*)0);
4294 }
4295
4296 return stmt;
4297}
4298
4299/*!
4300 * \brief Stores a voicemail into the database.
4301 * \param dir the folder the mailbox folder to store the message.
4302 * \param mailboxuser the user owning the mailbox folder.
4303 * \param mailboxcontext
4304 * \param msgnum the message index for the message to be stored.
4305 *
4306 * This method is used when mailboxes are stored in an ODBC back end.
4307 * The message sound file and information file is looked up on the file system.
4308 * A SQL query is invoked to store the message into the (MySQL) database.
4309 *
4310 * \return the zero on success -1 on error.
4311 */
4312static int store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum)
4313{
4314 int res = 0;
4315 int fd = -1;
4316 void *fdm = MAP_FAILED((void *) -1);
4317 off_t fdlen = -1;
4318 SQLHSTMT stmt;
4319 char sql[PATH_MAX4096];
4320 char msgnums[20];
4321 char fn[PATH_MAX4096];
4322 char full_fn[PATH_MAX4096];
4323 char fmt[80]="";
4324 char *c;
4325 struct ast_config *cfg = NULL((void*)0);
4326 struct odbc_obj *obj;
4327 struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
4328 .context = "", .macrocontext = "", .callerid = "", .origtime = "", .duration = "", .category = "", .flag = "", .msg_id = "" };
4329 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
4330
4331 delete_file(dir, msgnum);
4332 if (!(obj = ast_odbc_request_obj(odbc_database, 0))) {
4333 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4333, __PRETTY_FUNCTION__, "Failed to obtain database object for '%s'!\n", odbc_database);
4334 return -1;
4335 }
4336
4337 do {
4338 ast_copy_string(fmt, vmfmts, sizeof(fmt));
4339 c = strchr(fmt, '|')(__extension__ (__builtin_constant_p ('|') && !__builtin_constant_p
(fmt) && ('|') == '\0' ? (char *) __rawmemchr (fmt, '|'
) : __builtin_strchr (fmt, '|')))
;
4340 if (c)
4341 *c = '\0';
4342 if (!strcasecmp(fmt, "wav49"))
4343 strcpy(fmt, "WAV");
4344 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
4345 if (msgnum > -1)
4346 make_file(fn, sizeof(fn), dir, msgnum);
4347 else
4348 ast_copy_string(fn, dir, sizeof(fn));
4349 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
4350 cfg = ast_config_load(full_fn, config_flags)ast_config_load2(full_fn, "app_voicemail", config_flags);
4351 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
4352 fd = open(full_fn, O_RDWR02);
4353 if (fd < 0) {
4354 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4354, __PRETTY_FUNCTION__, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno(*__errno_location ())));
4355 res = -1;
4356 break;
4357 }
4358 if (valid_config(cfg)) {
4359 if (!(idata.context = ast_variable_retrieve(cfg, "message", "context"))) {
4360 idata.context = "";
4361 }
4362 if (!(idata.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"))) {
4363 idata.macrocontext = "";
4364 }
4365 if (!(idata.callerid = ast_variable_retrieve(cfg, "message", "callerid"))) {
4366 idata.callerid = "";
4367 }
4368 if (!(idata.origtime = ast_variable_retrieve(cfg, "message", "origtime"))) {
4369 idata.origtime = "";
4370 }
4371 if (!(idata.duration = ast_variable_retrieve(cfg, "message", "duration"))) {
4372 idata.duration = "";
4373 }
4374 if (!(idata.category = ast_variable_retrieve(cfg, "message", "category"))) {
4375 idata.category = "";
4376 }
4377 if (!(idata.flag = ast_variable_retrieve(cfg, "message", "flag"))) {
4378 idata.flag = "";
4379 }
4380 if (!(idata.msg_id = ast_variable_retrieve(cfg, "message", "msg_id"))) {
4381 idata.msg_id = "";
4382 }
4383 }
4384 fdlen = lseek(fd, 0, SEEK_END2);
4385 if (fdlen < 0 || lseek(fd, 0, SEEK_SET0) < 0) {
4386 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4386, __PRETTY_FUNCTION__, "Failed to process sound file '%s': %s\n", full_fn, strerror(errno(*__errno_location ())));
4387 res = -1;
4388 break;
4389 }
4390 fdm = mmap(NULL((void*)0), fdlen, PROT_READ0x1 | PROT_WRITE0x2, MAP_SHARED0x01, fd, 0);
4391 if (fdm == MAP_FAILED((void *) -1)) {
4392 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4392, __PRETTY_FUNCTION__, "Memory map failed for sound file '%s'!\n", full_fn);
4393 res = -1;
4394 break;
4395 }
4396 idata.data = fdm;
4397 idata.datalen = idata.indlen = fdlen;
4398
4399 if (!ast_strlen_zero(idata.category)_ast_strlen_zero(idata.category, "app_voicemail.c", __PRETTY_FUNCTION__
, 4399)
)
4400 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,msg_id,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
4401 else
4402 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,msg_id) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
4403
4404 if ((stmt = ast_odbc_direct_execute(obj, insert_data_cb, &idata))) {
4405 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
4406 } else {
4407 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4407, __PRETTY_FUNCTION__, "SQL Execute error!\n[%s]\n\n", sql);
4408 res = -1;
4409 }
4410 } while (0);
4411 if (obj) {
4412 ast_odbc_release_obj(obj);
4413 }
4414 if (valid_config(cfg))
4415 ast_config_destroy(cfg);
4416 if (fdm != MAP_FAILED((void *) -1))
4417 munmap(fdm, fdlen);
4418 if (fd > -1)
4419 close(fd);
4420 return res;
4421}
4422
4423/*!
4424 * \brief Renames a message in a mailbox folder.
4425 * \param sdir The folder of the message to be renamed.
4426 * \param smsg The index of the message to be renamed.
4427 * \param mailboxuser The user to become the owner of the message after it is renamed. Usually this will be the same as the original owner.
4428 * \param mailboxcontext The context to be set for the message. Usually this will be the same as the original context.
4429 * \param ddir The destination folder for the message to be renamed into
4430 * \param dmsg The destination message for the message to be renamed.
4431 *
4432 * This method is used by the RENAME macro when mailboxes are stored in an ODBC back end.
4433 * The is usually used to resequence the messages in the mailbox, such as to delete messag index 0, it would be called successively to slide all the other messages down one index.
4434 * But in theory, because the SQL query performs an update on (dir, msgnum, mailboxuser, mailboxcontext) in the database, it should be possible to have the message relocated to another mailbox or context as well.
4435 */
4436static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
4437{
4438 SQLHSTMT stmt;
4439 char sql[PATH_MAX4096];
4440 char msgnums[20];
4441 char msgnumd[20];
4442 struct odbc_obj *obj;
4443 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
4444 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
4445
4446 delete_file(ddir, dmsg);
4447 obj = ast_odbc_request_obj(odbc_database, 0);
4448 if (obj) {
4449 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
4450 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
4451 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table);
4452 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
4453 if (!stmt)
4454 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4454, __PRETTY_FUNCTION__, "SQL Execute error!\n[%s]\n\n", sql);
4455 else
4456 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4457 ast_odbc_release_obj(obj);
4458 } else
4459 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4459, __PRETTY_FUNCTION__, "Failed to obtain database object for '%s'!\n", odbc_database);
4460 return;
4461}
4462
4463/*!
4464 * \brief Removes a voicemail message file.
4465 * \param dir the path to the message file.
4466 * \param msgnum the unique number for the message within the mailbox.
4467 *
4468 * Removes the message content file and the information file.
4469 * This method is used by the DISPOSE macro when mailboxes are stored in an ODBC back end.
4470 * Typical use is to clean up after a RETRIEVE operation.
4471 * Note that this does not remove the message from the mailbox folders, to do that we would use delete_file().
4472 * \return zero on success, -1 on error.
4473 */
4474static int remove_file(char *dir, int msgnum)
4475{
4476 char fn[PATH_MAX4096];
4477 char full_fn[PATH_MAX4096];
4478 char msgnums[80];
4479
4480 if (msgnum > -1) {
4481 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
4482 make_file(fn, sizeof(fn), dir, msgnum);
4483 } else
4484 ast_copy_string(fn, dir, sizeof(fn));
4485 ast_filedelete(fn, NULL((void*)0));
4486 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
4487 unlink(full_fn);
4488 return 0;
4489}
4490#else
4491#ifndef IMAP_STORAGE
4492/*!
4493 * \brief Find all .txt files - even if they are not in sequence from 0000.
4494 * \param vmu
4495 * \param dir
4496 *
4497 * This method is used when mailboxes are stored on the filesystem. (not ODBC and not IMAP).
4498 *
4499 * \return the count of messages, zero or more.
4500 */
4501static int count_messages(struct ast_vm_user *vmu, char *dir)
4502{
4503
4504 int vmcount = 0;
4505 DIR *vmdir = NULL((void*)0);
4506 struct dirent *vment = NULL((void*)0);
4507
4508 if (vm_lock_path(dir))
4509 return ERROR_LOCK_PATH-100;
4510
4511 if ((vmdir = opendir(dir))) {
4512 while ((vment = readdir(vmdir))) {
4513 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)(__extension__ (__builtin_constant_p (4) && ((__builtin_constant_p
(vment->d_name + 7) && strlen (vment->d_name +
7) < ((size_t) (4))) || (__builtin_constant_p (".txt") &&
strlen (".txt") < ((size_t) (4)))) ? strcmp (vment->d_name
+ 7, ".txt") : strncmp (vment->d_name + 7, ".txt", 4)))
) {
4514 vmcount++;
4515 }
4516 }
4517 closedir(vmdir);
4518 }
4519 ast_unlock_path(dir);
4520
4521 return vmcount;
4522}
4523
4524/*!
4525 * \brief Renames a message in a mailbox folder.
4526 * \param sfn The path to the mailbox information and data file to be renamed.
4527 * \param dfn The path for where the message data and information files will be renamed to.
4528 *
4529 * This method is used by the RENAME macro when mailboxes are stored on the filesystem. (not ODBC and not IMAP).
4530 */
4531static void rename_file(char *sfn, char *dfn)
4532{
4533 char stxt[PATH_MAX4096];
4534 char dtxt[PATH_MAX4096];
4535 ast_filerename(sfn, dfn, NULL((void*)0));
4536 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
4537 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
4538 if (ast_check_realtime("voicemail_data")) {
4539 ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL((char *)((void*)0)));
4540 }
4541 rename(stxt, dtxt);
4542}
4543
4544/*!
4545 * \brief Determines the highest message number in use for a given user and mailbox folder.
4546 * \param vmu
4547 * \param dir the folder the mailbox folder to look for messages. Used to construct the SQL where clause.
4548 *
4549 * This method is used when mailboxes are stored on the filesystem. (not ODBC and not IMAP).
4550 * Typical use to set the msgnum would be to take the value returned from this method and add one to it.
4551 *
4552 * \note Should always be called with a lock already set on dir.
4553 * \return the value of zero or greaterto indicate the last message index in use, -1 to indicate none.
4554 */
4555static int last_message_index(struct ast_vm_user *vmu, char *dir)
4556{
4557 int x;
4558 unsigned char map[MAXMSGLIMIT9999] = "";
4559 DIR *msgdir;
4560 struct dirent *msgdirent;
4561 int msgdirint;
4562 char extension[4];
4563 int stopcount = 0;
4564
4565 /* Reading the entire directory into a file map scales better than
4566 * doing a stat repeatedly on a predicted sequence. I suspect this
4567 * is partially due to stat(2) internally doing a readdir(2) itself to
4568 * find each file. */
4569 if (!(msgdir = opendir(dir))) {
4570 return -1;
4571 }
4572
4573 while ((msgdirent = readdir(msgdir))) {
4574 if (sscanf(msgdirent->d_name, "msg%30d.%3s", &msgdirint, extension) == 2 && !strcmp(extension, "txt") && msgdirint < MAXMSGLIMIT9999) {
4575 map[msgdirint] = 1;
4576 stopcount++;
4577 ast_debug(4, "%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount)do { if ((option_debug >= (4) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (4)))) { ast_log
(0, "app_voicemail.c", 4577, __PRETTY_FUNCTION__, "%s map[%d] = %d, count = %d\n"
, dir, msgdirint, map[msgdirint], stopcount); } } while (0)
;
4578 }
4579 }
4580 closedir(msgdir);
4581
4582 for (x = 0; x < vmu->maxmsg; x++) {
4583 if (map[x] == 1) {
4584 stopcount--;
4585 } else if (map[x] == 0 && !stopcount) {
4586 break;
4587 }
4588 }
4589
4590 return x - 1;
4591}
4592
4593#endif /* #ifndef IMAP_STORAGE */
4594#endif /* #else of #ifdef ODBC_STORAGE */
4595#ifndef IMAP_STORAGE
4596/*!
4597 * \brief Utility function to copy a file.
4598 * \param infile The path to the file to be copied. The file must be readable, it is opened in read only mode.
4599 * \param outfile The path for which to copy the file to. The directory permissions must allow the creation (or truncation) of the file, and allow for opening the file in write only mode.
4600 *
4601 * When the compiler option HARDLINK_WHEN_POSSIBLE is set, the copy operation will attempt to use the hard link facility instead of copy the file (to save disk space). If the link operation fails, it falls back to the copy operation.
4602 * The copy operation copies up to 4096 bytes at once.
4603 *
4604 * \return zero on success, -1 on error.
4605 */
4606static int copy(char *infile, char *outfile)
4607{
4608 int ifd;
4609 int ofd;
4610 int res;
4611 int len;
4612 char buf[4096];
4613
4614#ifdef HARDLINK_WHEN_POSSIBLE
4615 /* Hard link if possible; saves disk space & is faster */
4616 if (link(infile, outfile)) {
4617#endif
4618 if ((ifd = open(infile, O_RDONLY00)) < 0) {
4619 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4619, __PRETTY_FUNCTION__, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno(*__errno_location ())));
4620 return -1;
4621 }
4622 if ((ofd = open(outfile, O_WRONLY01 | O_TRUNC01000 | O_CREAT0100, VOICEMAIL_FILE_MODE0666)) < 0) {
4623 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4623, __PRETTY_FUNCTION__, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno(*__errno_location ())));
4624 close(ifd);
4625 return -1;
4626 }
4627 do {
4628 len = read(ifd, buf, sizeof(buf));
4629 if (len < 0) {
4630 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4630, __PRETTY_FUNCTION__, "Read failed on %s: %s\n", infile, strerror(errno(*__errno_location ())));
4631 close(ifd);
4632 close(ofd);
4633 unlink(outfile);
4634 } else if (len) {
4635 res = write(ofd, buf, len);
4636 if (errno(*__errno_location ()) == ENOMEM12 || errno(*__errno_location ()) == ENOSPC28 || res != len) {
4637 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4637, __PRETTY_FUNCTION__, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno(*__errno_location ())));
4638 close(ifd);
4639 close(ofd);
4640 unlink(outfile);
4641 }
4642 }
4643 } while (len);
4644 close(ifd);
4645 close(ofd);
4646 return 0;
4647#ifdef HARDLINK_WHEN_POSSIBLE
4648 } else {
4649 /* Hard link succeeded */
4650 return 0;
4651 }
4652#endif
4653}
4654
4655/*!
4656 * \brief Copies a voicemail information (envelope) file.
4657 * \param frompath
4658 * \param topath
4659 *
4660 * Every voicemail has the data (.wav) file, and the information file.
4661 * This function performs the file system copying of the information file for a voicemail, handling the internal fields and their values.
4662 * This is used by the COPY macro when not using IMAP storage.
4663 */
4664static void copy_plain_file(char *frompath, char *topath)
4665{
4666 char frompath2[PATH_MAX4096], topath2[PATH_MAX4096];
4667 struct ast_variable *tmp,*var = NULL((void*)0);
4668 const char *origmailbox = NULL((void*)0), *context = NULL((void*)0), *macrocontext = NULL((void*)0), *exten = NULL((void*)0), *priority = NULL((void*)0), *callerchan = NULL((void*)0), *callerid = NULL((void*)0), *origdate = NULL((void*)0), *origtime = NULL((void*)0), *category = NULL((void*)0), *duration = NULL((void*)0);
4669 ast_filecopy(frompath, topath, NULL((void*)0));
4670 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
4671 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
4672 if (ast_check_realtime("voicemail_data")) {
4673 var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL((char *)((void*)0)));
4674 /* This cycle converts ast_variable linked list, to va_list list of arguments, may be there is a better way to do it? */
4675 for (tmp = var; tmp; tmp = tmp->next) {
4676 if (!strcasecmp(tmp->name, "origmailbox")) {
4677 origmailbox = tmp->value;
4678 } else if (!strcasecmp(tmp->name, "context")) {
4679 context = tmp->value;
4680 } else if (!strcasecmp(tmp->name, "macrocontext")) {
4681 macrocontext = tmp->value;
4682 } else if (!strcasecmp(tmp->name, "exten")) {
4683 exten = tmp->value;
4684 } else if (!strcasecmp(tmp->name, "priority")) {
4685 priority = tmp->value;
4686 } else if (!strcasecmp(tmp->name, "callerchan")) {
4687 callerchan = tmp->value;
4688 } else if (!strcasecmp(tmp->name, "callerid")) {
4689 callerid = tmp->value;
4690 } else if (!strcasecmp(tmp->name, "origdate")) {
4691 origdate = tmp->value;
4692 } else if (!strcasecmp(tmp->name, "origtime")) {
4693 origtime = tmp->value;
4694 } else if (!strcasecmp(tmp->name, "category")) {
4695 category = tmp->value;
4696 } else if (!strcasecmp(tmp->name, "duration")) {
4697 duration = tmp->value;
4698 }
4699 }
4700 ast_store_realtime("voicemail_data", "filename", topath, "origmailbox", origmailbox, "context", context, "macrocontext", macrocontext, "exten", exten, "priority", priority, "callerchan", callerchan, "callerid", callerid, "origdate", origdate, "origtime", origtime, "category", category, "duration", duration, SENTINEL((char *)((void*)0)));
4701 }
4702 copy(frompath2, topath2);
4703 ast_variables_destroy(var);
4704}
4705#endif
4706
4707/*!
4708 * \brief Removes the voicemail sound and information file.
4709 * \param file The path to the sound file. This will be the the folder and message index, without the extension.
4710 *
4711 * This is used by the DELETE macro when voicemails are stored on the file system.
4712 *
4713 * \return zero on success, -1 on error.
4714 */
4715static int vm_delete(char *file)
4716{
4717 char *txt;
4718 int txtsize = 0;
4719
4720 txtsize = (strlen(file) + 5)*sizeof(char);
4721 txt = ast_alloca(txtsize)__builtin_alloca(txtsize);
4722 /* Sprintf here would safe because we alloca'd exactly the right length,
4723 * but trying to eliminate all sprintf's anyhow
4724 */
4725 if (ast_check_realtime("voicemail_data")) {
4726 ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL((char *)((void*)0)));
4727 }
4728 snprintf(txt, txtsize, "%s.txt", file);
4729 unlink(txt);
4730 return ast_filedelete(file, NULL((void*)0));
4731}
4732
4733/*!
4734 * \brief utility used by inchar(), for base_encode()
4735 */
4736static int inbuf(struct baseio *bio, FILE *fi)
4737{
4738 int l;
4739
4740 if (bio->ateof)
4741 return 0;
4742
4743 if ((l = fread(bio->iobuf, 1, BASEMAXINLINE256, fi)) <= 0) {
4744 if (ferror(fi))
4745 return -1;
4746
4747 bio->ateof = 1;
4748 return 0;
4749 }
4750
4751 bio->iolen = l;
4752 bio->iocp = 0;
4753
4754 return 1;
4755}
4756
4757/*!
4758 * \brief utility used by base_encode()
4759 */
4760static int inchar(struct baseio *bio, FILE *fi)
4761{
4762 if (bio->iocp>=bio->iolen) {
4763 if (!inbuf(bio, fi))
4764 return EOF(-1);
4765 }
4766
4767 return bio->iobuf[bio->iocp++];
4768}
4769
4770/*!
4771 * \brief utility used by base_encode()
4772 */
4773static int ochar(struct baseio *bio, int c, FILE *so)
4774{
4775 if (bio->linelength >= BASELINELEN72) {
4776 if (fputs(ENDL"\n", so) == EOF(-1)) {
4777 return -1;
4778 }
4779
4780 bio->linelength = 0;
4781 }
4782
4783 if (putc(((unsigned char) c), so)_IO_putc (((unsigned char) c), so) == EOF(-1)) {
4784 return -1;
4785 }
4786
4787 bio->linelength++;
4788
4789 return 1;
4790}
4791
4792/*!
4793 * \brief Performs a base 64 encode algorithm on the contents of a File
4794 * \param filename The path to the file to be encoded. Must be readable, file is opened in read mode.
4795 * \param so A FILE handle to the output file to receive the base 64 encoded contents of the input file, identified by filename.
4796 *
4797 * TODO: shouldn't this (and the above 3 support functions) be put into some kind of external utility location, such as funcs/func_base64.c ?
4798 *
4799 * \return zero on success, -1 on error.
4800 */
4801static int base_encode(char *filename, FILE *so)
4802{
4803 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
4804 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
4805 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
4806 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
4807 int i, hiteof = 0;
4808 FILE *fi;
4809 struct baseio bio;
4810
4811 memset(&bio, 0, sizeof(bio));
4812 bio.iocp = BASEMAXINLINE256;
4813
4814 if (!(fi = fopen(filename, "rb"))) {
4815 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 4815, __PRETTY_FUNCTION__, "Failed to open file: %s: %s\n", filename, strerror(errno(*__errno_location ())));
4816 return -1;
4817 }
4818
4819 while (!hiteof){
4820 unsigned char igroup[3], ogroup[4];
4821 int c, n;
4822
4823 memset(igroup, 0, sizeof(igroup));
4824
4825 for (n = 0; n < 3; n++) {
4826 if ((c = inchar(&bio, fi)) == EOF(-1)) {
4827 hiteof = 1;
4828 break;
4829 }
4830
4831 igroup[n] = (unsigned char) c;
4832 }
4833
4834 if (n > 0) {
4835 ogroup[0]= dtable[igroup[0] >> 2];
4836 ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
4837 ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
4838 ogroup[3]= dtable[igroup[2] & 0x3F];
4839
4840 if (n < 3) {
4841 ogroup[3] = '=';
4842
4843 if (n < 2)
4844 ogroup[2] = '=';
4845 }
4846
4847 for (i = 0; i < 4; i++)
4848 ochar(&bio, ogroup[i], so);
4849 }
4850 }
4851
4852 fclose(fi);
4853
4854 if (fputs(ENDL"\n", so) == EOF(-1)) {
4855 return 0;
4856 }
4857
4858 return 1;
4859}
4860
4861static void prep_email_sub_vars(struct ast_channel *ast, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *dur, char *date, const char *category, const char *flag)
4862{
4863 char callerid[256];
4864 char num[12];
4865 char fromdir[256], fromfile[256];
4866 struct ast_config *msg_cfg;
4867 const char *origcallerid, *origtime;
4868 char origcidname[80], origcidnum[80], origdate[80];
4869 int inttime;
4870 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
4871
4872 /* Prepare variables for substitution in email body and subject */
4873 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
4874 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
4875 snprintf(num, sizeof(num), "%d", msgnum);
4876 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", num);
4877 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
4878 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
4879 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname)_ast_strlen_zero(cidname, "app_voicemail.c", __PRETTY_FUNCTION__
, 4879)
|| !ast_strlen_zero(cidnum)_ast_strlen_zero(cidnum, "app_voicemail.c", __PRETTY_FUNCTION__
, 4879)
) ?
4880 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL((void*)0)) : "an unknown caller");
4881 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname)_ast_strlen_zero(cidname, "app_voicemail.c", __PRETTY_FUNCTION__
, 4881)
? cidname : "an unknown caller"));
4882 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum)_ast_strlen_zero(cidnum, "app_voicemail.c", __PRETTY_FUNCTION__
, 4882)
? cidnum : "an unknown caller"));
4883 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
4884 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category)(__extension__ ({ const char *__old = (category); size_t __len
= strlen(__old) + 1; char *__new = __builtin_alloca(__len); memcpy
(__new, __old, __len); __new; }))
: "no category");
4885 pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
4886
4887 /* Retrieve info from VM attribute file */
4888 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
4889 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
4890 if (strlen(fromfile) < sizeof(fromfile) - 5) {
4891 strcat(fromfile, ".txt");
4892 }
4893 if (!(msg_cfg = ast_config_load(fromfile, config_flags)ast_config_load2(fromfile, "app_voicemail", config_flags)) || !(valid_config(msg_cfg))) {
4894 ast_debug(1, "Config load for message text file '%s' failed\n", fromfile)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 4894, __PRETTY_FUNCTION__, "Config load for message text file '%s' failed\n"
, fromfile); } } while (0)
;
4895 return;
4896 }
4897
4898 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
4899 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
4900 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
4901 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
4902 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
4903 }
4904
4905 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
4906 struct timeval tv = { inttime, };
4907 struct ast_tm tm;
4908 ast_localtime(&tv, &tm, NULL((void*)0));
4909 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL)({typeof(&((vmu->locale)[0])) __x = (vmu->locale); _ast_strlen_zero
(__x, "app_voicemail.c", __PRETTY_FUNCTION__, 4909) ? (((void
*)0)) : __x;})
);
4910 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
4911 }
4912 ast_config_destroy(msg_cfg);
4913}
4914
4915/*!
4916 * \brief Wraps a character sequence in double quotes, escaping occurences of quotes within the string.
4917 * \param from The string to work with.
4918 * \param buf The buffer into which to write the modified quoted string.
4919 * \param maxlen Always zero, but see \see ast_str
4920 *
4921 * \return The destination string with quotes wrapped on it (the to field).
4922 */
4923static const char *ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
4924{
4925 const char *ptr;
4926
4927 /* We're only ever passing 0 to maxlen, so short output isn't possible */
4928 ast_str_set(buf, maxlen, "\"");
4929 for (ptr = from; *ptr; ptr++) {
4930 if (*ptr == '"' || *ptr == '\\') {
4931 ast_str_append(buf, maxlen, "\\%c", *ptr);
4932 } else {
4933 ast_str_append(buf, maxlen, "%c", *ptr);
4934 }
4935 }
4936 ast_str_append(buf, maxlen, "\"");
4937
4938 return ast_str_buffer(*buf);
4939}
4940
4941/*! \brief
4942 * fill in *tm for current time according to the proper timezone, if any.
4943 * \return tm so it can be used as a function argument.
4944 */
4945static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
4946{
4947 const struct vm_zone *z = NULL((void*)0);
4948 struct timeval t = ast_tvnow();
4949
4950 /* Does this user have a timezone specified? */
4951 if (!ast_strlen_zero(vmu->zonetag)_ast_strlen_zero(vmu->zonetag, "app_voicemail.c", __PRETTY_FUNCTION__
, 4951)
) {
4952 /* Find the zone in the list */
4953 AST_LIST_LOCK(&zones)__ast_pthread_mutex_lock("app_voicemail.c", 4953, __PRETTY_FUNCTION__
, "&(&zones)->lock", &(&zones)->lock)
;
4954 AST_LIST_TRAVERSE(&zones, z, list)for((z) = (&zones)->first; (z); (z) = (z)->list.next
)
{
4955 if (!strcmp(z->name, vmu->zonetag))
4956 break;
4957 }
4958 AST_LIST_UNLOCK(&zones)__ast_pthread_mutex_unlock("app_voicemail.c", 4958, __PRETTY_FUNCTION__
, "&(&zones)->lock", &(&zones)->lock)
;
4959 }
4960 ast_localtime(&t, tm, z ? z->timezone : NULL((void*)0));
4961 return tm;
4962}
4963
4964/*!\brief Check if the string would need encoding within the MIME standard, to
4965 * avoid confusing certain mail software that expects messages to be 7-bit
4966 * clean.
4967 */
4968static int check_mime(const char *str)
4969{
4970 for (; *str; str++) {
4971 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)(__extension__ (__builtin_constant_p (*str) && !__builtin_constant_p
("()<>@,:;/\"[]?.=") && (*str) == '\0' ? (char
*) __rawmemchr ("()<>@,:;/\"[]?.=", *str) : __builtin_strchr
("()<>@,:;/\"[]?.=", *str)))
) {
4972 return 1;
4973 }
4974 }
4975 return 0;
4976}
4977
4978/*!\brief Encode a string according to the MIME rules for encoding strings
4979 * that are not 7-bit clean or contain control characters.
4980 *
4981 * Additionally, if the encoded string would exceed the MIME limit of 76
4982 * characters per line, then the encoding will be broken up into multiple
4983 * sections, separated by a space character, in order to facilitate
4984 * breaking up the associated header across multiple lines.
4985 *
4986 * \param end An expandable buffer for holding the result
4987 * \param maxlen Always zero, but see \see ast_str
4988 * \param start A string to be encoded
4989 * \param preamble The length of the first line already used for this string,
4990 * to ensure that each line maintains a maximum length of 76 chars.
4991 * \param postamble the length of any additional characters appended to the
4992 * line, used to ensure proper field wrapping.
4993 * \retval The encoded string.
4994 */
4995static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
4996{
4997 struct ast_str *tmp = ast_str_alloca(80)({ struct ast_str *__ast_str_buf; __ast_str_buf = __builtin_alloca
(sizeof(*__ast_str_buf) + 80); __ast_str_buf->len = 80; __ast_str_buf
->used = 0; __ast_str_buf->ts = ((struct ast_threadstorage
*)2); __ast_str_buf->str[0] = '\0'; (__ast_str_buf); })
;
4998 int first_section = 1;
4999
5000 ast_str_reset(*end);
5001 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
5002 for (; *start; start++) {
5003 int need_encoding = 0;
5004 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)(__extension__ (__builtin_constant_p (*start) && !__builtin_constant_p
("()<>@,:;/\"[]?.=_") && (*start) == '\0' ? (char
*) __rawmemchr ("()<>@,:;/\"[]?.=_", *start) : __builtin_strchr
("()<>@,:;/\"[]?.=_", *start)))
) {
5005 need_encoding = 1;
5006 }
5007 if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
5008 (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
5009 (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
5010 (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
5011 /* Start new line */
5012 ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
5013 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
5014 first_section = 0;
5015 }
5016 if (need_encoding && *start == ' ') {
5017 ast_str_append(&tmp, -1, "_");
5018 } else if (need_encoding) {
5019 ast_str_append(&tmp, -1, "=%hhX", *start);
5020 } else {
5021 ast_str_append(&tmp, -1, "%c", *start);
5022 }
5023 }
5024 ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
5025 return ast_str_buffer(*end);
5026}
5027
5028/*!
5029 * \brief Creates the email file to be sent to indicate a new voicemail exists for a user.
5030 * \param p The output file to generate the email contents into.
5031 * \param srcemail The email address to send the email to, presumably the email address for the owner of the mailbox.
5032 * \param vmu The voicemail user who is sending the voicemail.
5033 * \param msgnum The message index in the mailbox folder.
5034 * \param context
5035 * \param mailbox The voicemail box to read the voicemail to be notified in this email.
5036 * \param fromfolder
5037 * \param cidnum The caller ID number.
5038 * \param cidname The caller ID name.
5039 * \param attach the name of the sound file to be attached to the email, if attach_user_voicemail == 1.
5040 * \param attach2
5041 * \param format The message sound file format. i.e. .wav
5042 * \param duration The time of the message content, in seconds.
5043 * \param attach_user_voicemail if 1, the sound file is attached to the email.
5044 * \param chan
5045 * \param category
5046 * \param imap if == 1, indicates the target folder for the email notification to be sent to will be an IMAP mailstore. This causes additional mailbox headers to be set, which would facilitate searching for the email in the destination IMAP folder.
5047 * \param flag, msg_id
5048 *
5049 * The email body, and base 64 encoded attachement (if any) are stored to the file identified by *p. This method does not actually send the email. That is done by invoking the configure 'mailcmd' and piping this generated file into it, or with the sendemail() function.
5050 */
5051static void make_email_file(FILE *p,
5052 char *srcemail,
5053 struct ast_vm_user *vmu,
5054 int msgnum,
5055 char *context,
5056 char *mailbox,
5057 const char *fromfolder,
5058 char *cidnum,
5059 char *cidname,
5060 char *attach,
5061 char *attach2,
5062 char *format,
5063 int duration,
5064 int attach_user_voicemail,
5065 struct ast_channel *chan,
5066 const char *category,
5067 int imap,
5068 const char *flag,
5069 const char *msg_id)
5070{
5071 char date[256];
5072 char host[MAXHOSTNAMELEN64] = "";
5073 char who[256];
5074 char bound[256];
5075 char dur[256];
5076 struct ast_tm tm;
5077 char enc_cidnum[256] = "", enc_cidname[256] = "";
5078 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
5079 char *greeting_attachment;
5080 char filename[256];
5081 int first_line;
5082 char *emailsbuf;
5083 char *email;
5084
5085 if (!str1 || !str2) {
5086 ast_freefree(str1);
5087 ast_freefree(str2);
5088 return;
5089 }
5090
5091 if (cidnum) {
5092 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
5093 }
5094 if (cidname) {
5095 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
5096 }
5097 gethostname(host, sizeof(host) - 1);
5098
5099 if (strchr(srcemail, '@')(__extension__ (__builtin_constant_p ('@') && !__builtin_constant_p
(srcemail) && ('@') == '\0' ? (char *) __rawmemchr (
srcemail, '@') : __builtin_strchr (srcemail, '@')))
) {
5100 ast_copy_string(who, srcemail, sizeof(who));
5101 } else {
5102 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
5103 }
5104
5105 greeting_attachment = strrchr(ast_strdupa(attach)(__extension__ ({ const char *__old = (attach); size_t __len =
strlen(__old) + 1; char *__new = __builtin_alloca(__len); memcpy
(__new, __old, __len); __new; }))
, '/');
5106 if (greeting_attachment) {
5107 *greeting_attachment++ = '\0';
5108 }
5109
5110 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
5111 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
5112 fprintf(p, "Date: %s" ENDL"\n", date);
5113
5114 /* Set date format for voicemail mail */
5115 ast_strftime_locale(date, sizeof(date), emaildateformat, &tm, S_OR(vmu->locale, NULL)({typeof(&((vmu->locale)[0])) __x = (vmu->locale); _ast_strlen_zero
(__x, "app_voicemail.c", __PRETTY_FUNCTION__, 5115) ? (((void
*)0)) : __x;})
);
5116
5117 if (!ast_strlen_zero(fromstring)_ast_strlen_zero(fromstring, "app_voicemail.c", __PRETTY_FUNCTION__
, 5117)
) {
5118 struct ast_channel *ast;
5119 if ((ast = ast_dummy_channel_alloc()__ast_dummy_channel_alloc("app_voicemail.c", 5119, __PRETTY_FUNCTION__
)
)) {
5120 char *ptr;
5121 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
5122 ast_str_substitute_variables(&str1, 0, ast, fromstring);
5123
5124 if (check_mime(ast_str_buffer(str1))) {
5125 first_line = 1;
5126 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
5127 while ((ptr = strchr(ast_str_buffer(str2), ' ')(__extension__ (__builtin_constant_p (' ') && !__builtin_constant_p
(ast_str_buffer(str2)) && (' ') == '\0' ? (char *) __rawmemchr
(ast_str_buffer(str2), ' ') : __builtin_strchr (ast_str_buffer
(str2), ' ')))
)) {
5128 *ptr = '\0';
5129 fprintf(p, "%s %s" ENDL"\n", first_line ? "From:" : "", ast_str_buffer(str2));
5130 first_line = 0;
5131 /* Substring is smaller, so this will never grow */
5132 ast_str_set(&str2, 0, "%s", ptr + 1);
5133 }
5134 fprintf(p, "%s %s <%s>" ENDL"\n", first_line ? "From:" : "", ast_str_buffer(str2), who);
5135 } else {
5136 fprintf(p, "From: %s <%s>" ENDL"\n", ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
5137 }
5138 ast = ast_channel_unref(ast)({ __ao2_ref((ast), (-1), "", "app_voicemail.c", 5138, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
5139 } else {
5140 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 5140, __PRETTY_FUNCTION__, "Cannot allocate the channel for variables substitution\n");
5141 }
5142 } else {
5143 fprintf(p, "From: Asterisk PBX <%s>" ENDL"\n", who);
5144 }
5145
5146 emailsbuf = ast_strdupa(vmu->email)(__extension__ ({ const char *__old = (vmu->email); size_t
__len = strlen(__old) + 1; char *__new = __builtin_alloca(__len
); memcpy (__new, __old, __len); __new; }))
;
5147 fprintf(p, "To:");
5148 first_line = 1;
5149 while ((email = strsep(&emailsbuf, "|"))) {
5150 char *next = emailsbuf;
5151 if (check_mime(vmu->fullname)) {
5152 char *ptr;
5153 ast_str_encode_mime(&str2, 0, vmu->fullname, first_line ? strlen("To: ") : 0, strlen(email) + 3 + (next ? strlen(",") : 0));
5154 while ((ptr = strchr(ast_str_buffer(str2), ' ')(__extension__ (__builtin_constant_p (' ') && !__builtin_constant_p
(ast_str_buffer(str2)) && (' ') == '\0' ? (char *) __rawmemchr
(ast_str_buffer(str2), ' ') : __builtin_strchr (ast_str_buffer
(str2), ' ')))
)) {
5155 *ptr = '\0';
5156 fprintf(p, " %s" ENDL"\n", ast_str_buffer(str2));
5157 /* Substring is smaller, so this will never grow */
5158 ast_str_set(&str2, 0, "%s", ptr + 1);
5159 }
5160 fprintf(p, " %s <%s>%s" ENDL"\n", ast_str_buffer(str2), email, next ? "," : "");
5161 } else {
5162 fprintf(p, " %s <%s>%s" ENDL"\n", ast_str_quote(&str2, 0, vmu->fullname), email, next ? "," : "");
5163 }
5164 first_line = 0;
5165 }
5166
5167 if (msgnum <= -1) {
5168 fprintf(p, "Subject: New greeting '%s' on %s." ENDL"\n", greeting_attachment, date);
5169 } else if (!ast_strlen_zero(emailsubject)_ast_strlen_zero(emailsubject, "app_voicemail.c", __PRETTY_FUNCTION__
, 5169)
|| !ast_strlen_zero(vmu->emailsubject)_ast_strlen_zero(vmu->emailsubject, "app_voicemail.c", __PRETTY_FUNCTION__
, 5169)
) {
5170 char *e_subj = !ast_strlen_zero(vmu->emailsubject)_ast_strlen_zero(vmu->emailsubject, "app_voicemail.c", __PRETTY_FUNCTION__
, 5170)
? vmu->emailsubject : emailsubject;
5171 struct ast_channel *ast;
5172 if ((ast = ast_dummy_channel_alloc()__ast_dummy_channel_alloc("app_voicemail.c", 5172, __PRETTY_FUNCTION__
)
)) {
5173 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
5174 ast_str_substitute_variables(&str1, 0, ast, e_subj);
5175 if (check_mime(ast_str_buffer(str1))) {
5176 char *ptr;
5177 first_line = 1;
5178 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
5179 while ((ptr = strchr(ast_str_buffer(str2), ' ')(__extension__ (__builtin_constant_p (' ') && !__builtin_constant_p
(ast_str_buffer(str2)) && (' ') == '\0' ? (char *) __rawmemchr
(ast_str_buffer(str2), ' ') : __builtin_strchr (ast_str_buffer
(str2), ' ')))
)) {
5180 *ptr = '\0';
5181 fprintf(p, "%s %s" ENDL"\n", first_line ? "Subject:" : "", ast_str_buffer(str2));
5182 first_line = 0;
5183 /* Substring is smaller, so this will never grow */
5184 ast_str_set(&str2, 0, "%s", ptr + 1);
5185 }
5186 fprintf(p, "%s %s" ENDL"\n", first_line ? "Subject:" : "", ast_str_buffer(str2));
5187 } else {
5188 fprintf(p, "Subject: %s" ENDL"\n", ast_str_buffer(str1));
5189 }
5190 ast = ast_channel_unref(ast)({ __ao2_ref((ast), (-1), "", "app_voicemail.c", 5190, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
5191 } else {
5192 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 5192, __PRETTY_FUNCTION__, "Cannot allocate the channel for variables substitution\n");
5193 }
5194 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)({ typeof (((&globalflags))->flags) __p = ((&globalflags
))->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); (((&globalflags))->flags &
((1 << 9))); })
) {
5195 if (ast_strlen_zero(flag)_ast_strlen_zero(flag, "app_voicemail.c", __PRETTY_FUNCTION__
, 5195)
) {
5196 fprintf(p, "Subject: New message %d in mailbox %s" ENDL"\n", msgnum + 1, mailbox);
5197 } else {
5198 fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL"\n", flag, msgnum + 1, mailbox);
5199 }
5200 } else {
5201 if (ast_strlen_zero(flag)_ast_strlen_zero(flag, "app_voicemail.c", __PRETTY_FUNCTION__
, 5201)
) {
5202 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL"\n", msgnum + 1, mailbox);
5203 } else {
5204 fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL"\n", flag, msgnum + 1, mailbox);
5205 }
5206 }
5207
5208 fprintf(p, "Message-ID: <Asterisk-%d-%u-%s-%d@%s>" ENDL"\n", msgnum + 1,
5209 (unsigned int) ast_random(), mailbox, (int) getpid(), host);
5210 if (imap) {
5211 /* additional information needed for IMAP searching */
5212 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL"\n", msgnum + 1);
5213 /* fprintf(p, "X-Asterisk-VM-Orig-Mailbox: %s" ENDL, ext); */
5214 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL"\n", fromstring);
5215 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL"\n", context);
5216#ifdef IMAP_STORAGE
5217 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL"\n", (!ast_strlen_zero(vmu->imapvmshareid)_ast_strlen_zero(vmu->imapvmshareid, "app_voicemail.c", __PRETTY_FUNCTION__
, 5217)
? vmu->imapvmshareid : mailbox));
5218#else
5219 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL"\n", mailbox);
5220#endif
5221 /* flag added for Urgent */
5222 fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL"\n", S_OR(flag, "")({typeof(&((flag)[0])) __x = (flag); _ast_strlen_zero(__x
, "app_voicemail.c", __PRETTY_FUNCTION__, 5222) ? ("") : __x;
})
);
5223 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL"\n", chan ? ast_channel_priority(chan) : 0);
5224 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL"\n", enc_cidnum);
5225 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL"\n", enc_cidname);
5226 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL"\n", duration);
5227 if (!ast_strlen_zero(category)_ast_strlen_zero(category, "app_voicemail.c", __PRETTY_FUNCTION__
, 5227)
) {
5228 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL"\n", category);
5229 } else {
5230 fprintf(p, "X-Asterisk-VM-Category: " ENDL"\n");
5231 }
5232 fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL"\n", msgnum > -1 ? "Message" : greeting_attachment);
5233 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL"\n", date);
5234 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL"\n", (long) time(NULL((void*)0)));
5235 fprintf(p, "X-Asterisk-VM-Message-ID: %s" ENDL"\n", msg_id);
5236 }
5237 if (!ast_strlen_zero(cidnum)_ast_strlen_zero(cidnum, "app_voicemail.c", __PRETTY_FUNCTION__
, 5237)
) {
5238 fprintf(p, "X-Asterisk-CallerID: %s" ENDL"\n", enc_cidnum);
5239 }
5240 if (!ast_strlen_zero(cidname)_ast_strlen_zero(cidname, "app_voicemail.c", __PRETTY_FUNCTION__
, 5240)
) {
5241 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL"\n", enc_cidname);
5242 }
5243 fprintf(p, "MIME-Version: 1.0" ENDL"\n");
5244 if (attach_user_voicemail) {
5245 /* Something unique. */
5246 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%u", msgnum + 1, mailbox,
5247 (int) getpid(), (unsigned int) ast_random());
5248
5249 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL"\n", bound);
5250 fprintf(p, ENDL"\n" ENDL"\n" "This is a multi-part message in MIME format." ENDL"\n" ENDL"\n");
5251 fprintf(p, "--%s" ENDL"\n", bound);
5252 }
5253 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL"\n" "Content-Transfer-Encoding: 8bit" ENDL"\n" ENDL"\n", charset);
5254 if (msgnum <= -1) {
5255 fprintf(p, "This message is to let you know that your greeting '%s' was changed on %s." ENDL"\n"
5256 "Please do not delete this message, lest your greeting vanish with it." ENDL"\n" ENDL"\n",
5257 greeting_attachment, date);
5258 } else if (emailbody || vmu->emailbody) {
5259 char* e_body = vmu->emailbody ? vmu->emailbody : emailbody;
5260 struct ast_channel *ast;
5261 if ((ast = ast_dummy_channel_alloc()__ast_dummy_channel_alloc("app_voicemail.c", 5261, __PRETTY_FUNCTION__
)
)) {
5262 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
5263 ast_str_substitute_variables(&str1, 0, ast, e_body);
5264#ifdef IMAP_STORAGE
5265 {
5266 /* Convert body to native line terminators for IMAP backend */
5267 char *line = ast_str_buffer(str1), *next;
5268 do {
5269 /* Terminate line before outputting it to the file */
5270 if ((next = strchr(line, '\n')(__extension__ (__builtin_constant_p ('\n') && !__builtin_constant_p
(line) && ('\n') == '\0' ? (char *) __rawmemchr (line
, '\n') : __builtin_strchr (line, '\n')))
)) {
5271 *next++ = '\0';
5272 }
5273 fprintf(p, "%s" ENDL"\n", line);
5274 line = next;
5275 } while (!ast_strlen_zero(line)_ast_strlen_zero(line, "app_voicemail.c", __PRETTY_FUNCTION__
, 5275)
);
5276 }
5277#else
5278 fprintf(p, "%s" ENDL"\n", ast_str_buffer(str1));
5279#endif
5280 ast = ast_channel_unref(ast)({ __ao2_ref((ast), (-1), "", "app_voicemail.c", 5280, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
5281 } else {
5282 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 5282, __PRETTY_FUNCTION__, "Cannot allocate the channel for variables substitution\n");
5283 }
5284 } else {
5285 if (strcmp(vmu->mailbox, mailbox)) {
5286 /* Forwarded type */
5287 struct ast_config *msg_cfg;
5288 const char *v;
5289 int inttime;
5290 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
5291 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
5292 /* Retrieve info from VM attribute file */
5293 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
5294 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
5295 if (strlen(fromfile) < sizeof(fromfile) - 5) {
5296 strcat(fromfile, ".txt");
5297 }
5298 if ((msg_cfg = ast_config_load(fromfile, config_flags)ast_config_load2(fromfile, "app_voicemail", config_flags)) && valid_config(msg_cfg)) {
5299 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
5300 ast_copy_string(origcallerid, v, sizeof(origcallerid));
5301 }
5302
5303 /* You might be tempted to do origdate, except that a) it's in the wrong
5304 * format, and b) it's missing for IMAP recordings. */
5305 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
5306 struct timeval tv = { inttime, };
5307 struct ast_tm tm;
5308 ast_localtime(&tv, &tm, NULL((void*)0));
5309 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL)({typeof(&((vmu->locale)[0])) __x = (vmu->locale); _ast_strlen_zero
(__x, "app_voicemail.c", __PRETTY_FUNCTION__, 5309) ? (((void
*)0)) : __x;})
);
5310 }
5311 fprintf(p, "Dear %s:" ENDL"\n" ENDL"\n" "\tJust wanted to let you know you were just forwarded"
5312 " a %s long message (number %d)" ENDL"\n" "in mailbox %s from %s, on %s" ENDL"\n"
5313 "(originally sent by %s on %s)" ENDL"\n" "so you might want to check it when you get a"
5314 " chance. Thanks!" ENDL"\n" ENDL"\n" "\t\t\t\t--Asterisk" ENDL"\n" ENDL"\n", vmu->fullname, dur,
5315 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
5316 date, origcallerid, origdate);
5317 ast_config_destroy(msg_cfg);
5318 } else {
5319 goto plain_message;
5320 }
5321 } else {
5322plain_message:
5323 fprintf(p, "Dear %s:" ENDL"\n" ENDL"\n" "\tJust wanted to let you know you were just left a "
5324 "%s long message (number %d)" ENDL"\n" "in mailbox %s from %s, on %s so you might" ENDL"\n"
5325 "want to check it when you get a chance. Thanks!" ENDL"\n" ENDL"\n" "\t\t\t\t--Asterisk"
5326 ENDL"\n" ENDL"\n", vmu->fullname, dur, msgnum + 1, mailbox,
5327 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
5328 }
5329 }
5330
5331 if (imap || attach_user_voicemail) {
5332 if (!ast_strlen_zero(attach2)_ast_strlen_zero(attach2, "app_voicemail.c", __PRETTY_FUNCTION__
, 5332)
) {
5333 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
5334 ast_debug(5, "creating second attachment filename %s\n", filename)do { if ((option_debug >= (5) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (5)))) { ast_log
(0, "app_voicemail.c", 5334, __PRETTY_FUNCTION__, "creating second attachment filename %s\n"
, filename); } } while (0)
;
5335 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
5336 snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
5337 ast_debug(5, "creating attachment filename %s\n", filename)do { if ((option_debug >= (5) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (5)))) { ast_log
(0, "app_voicemail.c", 5337, __PRETTY_FUNCTION__, "creating attachment filename %s\n"
, filename); } } while (0)
;
5338 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
5339 } else {
5340 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
5341 ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename)do { if ((option_debug >= (5) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (5)))) { ast_log
(0, "app_voicemail.c", 5341, __PRETTY_FUNCTION__, "creating attachment filename %s, no second attachment.\n"
, filename); } } while (0)
;
5342 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
5343 }
5344 }
5345 ast_freefree(str1);
5346 ast_freefree(str2);
5347}
5348
5349static int add_email_attachment(FILE *p, struct ast_vm_user *vmu, char *format, char *attach, char *greeting_attachment, char *mailbox, char *bound, char *filename, int last, int msgnum)
5350{
5351 char tmpdir[256], newtmp[256];
5352 char fname[256];
5353 char tmpcmd[256];
5354 int tmpfd = -1;
5355 int soxstatus = 0;
5356
5357 /* Eww. We want formats to tell us their own MIME type */
5358 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
5359
5360 if (vmu->volgain < -.001 || vmu->volgain > .001) {
5361 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
5362 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
5363 tmpfd = mkstemp(newtmp);
5364 chmod(newtmp, VOICEMAIL_FILE_MODE0666 & ~my_umask);
5365 ast_debug(3, "newtmp: %s\n", newtmp)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 5365, __PRETTY_FUNCTION__, "newtmp: %s\n"
, newtmp); } } while (0)
;
5366 if (tmpfd > -1) {
5367 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
5368 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
5369 attach = newtmp;
5370 ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 5370, __PRETTY_FUNCTION__, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n"
, attach, format, vmu->volgain, mailbox); } } while (0)
;
5371 } else {
5372 ast_log(LOG_WARNING3, "app_voicemail.c", 5372, __PRETTY_FUNCTION__, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
5373 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
5374 ast_log(LOG_WARNING3, "app_voicemail.c", 5374, __PRETTY_FUNCTION__, "Voicemail attachment will have no volume gain.\n");
5375 }
5376 }
5377 }
5378 fprintf(p, "--%s" ENDL"\n", bound);
5379 if (msgnum > -1)
5380 fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL"\n", ctype, format, filename);
5381 else
5382 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL"\n", ctype, format, greeting_attachment, format);
5383 fprintf(p, "Content-Transfer-Encoding: base64" ENDL"\n");
5384 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL"\n");
5385 if (msgnum > -1)
5386 fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL"\n" ENDL"\n", filename);
5387 else
5388 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL"\n" ENDL"\n", greeting_attachment, format);
5389 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
5390 base_encode(fname, p);
5391 if (last)
5392 fprintf(p, ENDL"\n" ENDL"\n" "--%s--" ENDL"\n" "." ENDL"\n", bound);
5393 if (tmpfd > -1) {
5394 if (soxstatus == 0) {
5395 unlink(fname);
5396 }
5397 close(tmpfd);
5398 unlink(newtmp);
5399 }
5400 return 0;
5401}
5402
5403static int sendmail(char *srcemail,
5404 struct ast_vm_user *vmu,
5405 int msgnum,
5406 char *context,
5407 char *mailbox,
5408 const char *fromfolder,
5409 char *cidnum,
5410 char *cidname,
5411 char *attach,
5412 char *attach2,
5413 char *format,
5414 int duration,
5415 int attach_user_voicemail,
5416 struct ast_channel *chan,
5417 const char *category,
5418 const char *flag,
5419 const char *msg_id)
5420{
5421 FILE *p = NULL((void*)0);
5422 char tmp[80] = "/tmp/astmail-XXXXXX";
5423 char tmp2[256];
5424 char *stringp;
5425
5426 if (vmu && ast_strlen_zero(vmu->email)_ast_strlen_zero(vmu->email, "app_voicemail.c", __PRETTY_FUNCTION__
, 5426)
) {
5427 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 5427, __PRETTY_FUNCTION__, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
5428 return(0);
5429 }
5430
5431 /* Mail only the first format */
5432 format = ast_strdupa(format)(__extension__ ({ const char *__old = (format); size_t __len =
strlen(__old) + 1; char *__new = __builtin_alloca(__len); memcpy
(__new, __old, __len); __new; }))
;
5433 stringp = format;
5434 strsep(&stringp, "|");
5435
5436 if (!strcmp(format, "wav49"))
5437 format = "WAV";
5438 ast_debug(3, "Attaching file '%s', format '%s', uservm is '%d', global is %u\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags), VM_ATTACH))do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 5438, __PRETTY_FUNCTION__, "Attaching file '%s', format '%s', uservm is '%d', global is %u\n"
, attach, format, attach_user_voicemail, ({ typeof (((&globalflags
))->flags) __p = ((&globalflags))->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); (((&globalflags
))->flags & ((1 << 11))); })); } } while (0)
;
5439 /* Make a temporary file instead of piping directly to sendmail, in case the mail
5440 command hangs */
5441 if ((p = vm_mkftemp(tmp)) == NULL((void*)0)) {
5442 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 5442, __PRETTY_FUNCTION__, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
5443 return -1;
5444 } else {
5445 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag, msg_id);
5446 fclose(p);
5447 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
5448 ast_safe_system(tmp2);
5449 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 5449, __PRETTY_FUNCTION__, "Sent mail to %s with command '%s'\n"
, vmu->email, mailcmd); } } while (0)
;
5450 }
5451 return 0;
5452}
5453
5454static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, int duration, struct ast_vm_user *vmu, const char *category, const char *flag)
5455{
5456 char enc_cidnum[256], enc_cidname[256];
5457 char date[256];
5458 char host[MAXHOSTNAMELEN64] = "";
5459 char who[256];
5460 char dur[PATH_MAX4096];
5461 char tmp[80] = "/tmp/astmail-XXXXXX";
5462 char tmp2[PATH_MAX4096];
5463 struct ast_tm tm;
5464 FILE *p;
5465 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
5466
5467 if (!str1 || !str2) {
5468 ast_freefree(str1);
5469 ast_freefree(str2);
5470 return -1;
5471 }
5472
5473 if (cidnum) {
5474 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
5475 }
5476 if (cidname) {
5477 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
5478 }
5479
5480 if ((p = vm_mkftemp(tmp)) == NULL((void*)0)) {
5481 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 5481, __PRETTY_FUNCTION__, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
5482 ast_freefree(str1);
5483 ast_freefree(str2);
5484 return -1;
5485 }
5486 gethostname(host, sizeof(host)-1);
5487 if (strchr(srcemail, '@')(__extension__ (__builtin_constant_p ('@') && !__builtin_constant_p
(srcemail) && ('@') == '\0' ? (char *) __rawmemchr (
srcemail, '@') : __builtin_strchr (srcemail, '@')))
) {
5488 ast_copy_string(who, srcemail, sizeof(who));
5489 } else {
5490 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
5491 }
5492 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
5493 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
5494 fprintf(p, "Date: %s\n", date);
5495
5496 /* Reformat for custom pager format */
5497 ast_strftime_locale(date, sizeof(date), pagerdateformat, vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL)({typeof(&((vmu->locale)[0])) __x = (vmu->locale); _ast_strlen_zero
(__x, "app_voicemail.c", __PRETTY_FUNCTION__, 5497) ? (((void
*)0)) : __x;})
);
5498
5499 if (!ast_strlen_zero(pagerfromstring)_ast_strlen_zero(pagerfromstring, "app_voicemail.c", __PRETTY_FUNCTION__
, 5499)
) {
5500 struct ast_channel *ast;
5501 if ((ast = ast_dummy_channel_alloc()__ast_dummy_channel_alloc("app_voicemail.c", 5501, __PRETTY_FUNCTION__
)
)) {
5502 char *ptr;
5503 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
5504 ast_str_substitute_variables(&str1, 0, ast, pagerfromstring);
5505
5506 if (check_mime(ast_str_buffer(str1))) {
5507 int first_line = 1;
5508 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
5509 while ((ptr = strchr(ast_str_buffer(str2), ' ')(__extension__ (__builtin_constant_p (' ') && !__builtin_constant_p
(ast_str_buffer(str2)) && (' ') == '\0' ? (char *) __rawmemchr
(ast_str_buffer(str2), ' ') : __builtin_strchr (ast_str_buffer
(str2), ' ')))
)) {
5510 *ptr = '\0';
5511 fprintf(p, "%s %s" ENDL"\n", first_line ? "From:" : "", ast_str_buffer(str2));
5512 first_line = 0;
5513 /* Substring is smaller, so this will never grow */
5514 ast_str_set(&str2, 0, "%s", ptr + 1);
5515 }
5516 fprintf(p, "%s %s <%s>" ENDL"\n", first_line ? "From:" : "", ast_str_buffer(str2), who);
5517 } else {
5518 fprintf(p, "From: %s <%s>" ENDL"\n", ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
5519 }
5520 ast = ast_channel_unref(ast)({ __ao2_ref((ast), (-1), "", "app_voicemail.c", 5520, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
5521 } else {
5522 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 5522, __PRETTY_FUNCTION__, "Cannot allocate the channel for variables substitution\n");
5523 }
5524 } else {
5525 fprintf(p, "From: Asterisk PBX <%s>" ENDL"\n", who);
5526 }
5527
5528 if (check_mime(vmu->fullname)) {
5529 int first_line = 1;
5530 char *ptr;
5531 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(pager) + 3);
5532 while ((ptr = strchr(ast_str_buffer(str2), ' ')(__extension__ (__builtin_constant_p (' ') && !__builtin_constant_p
(ast_str_buffer(str2)) && (' ') == '\0' ? (char *) __rawmemchr
(ast_str_buffer(str2), ' ') : __builtin_strchr (ast_str_buffer
(str2), ' ')))
)) {
5533 *ptr = '\0';
5534 fprintf(p, "%s %s" ENDL"\n", first_line ? "To:" : "", ast_str_buffer(str2));
5535 first_line = 0;
5536 /* Substring is smaller, so this will never grow */
5537 ast_str_set(&str2, 0, "%s", ptr + 1);
5538 }
5539 fprintf(p, "%s %s <%s>" ENDL"\n", first_line ? "To:" : "", ast_str_buffer(str2), pager);
5540 } else {
5541 fprintf(p, "To: %s <%s>" ENDL"\n", ast_str_quote(&str2, 0, vmu->fullname), pager);
5542 }
5543
5544 if (!ast_strlen_zero(pagersubject)_ast_strlen_zero(pagersubject, "app_voicemail.c", __PRETTY_FUNCTION__
, 5544)
) {
5545 struct ast_channel *ast;
5546 if ((ast = ast_dummy_channel_alloc()__ast_dummy_channel_alloc("app_voicemail.c", 5546, __PRETTY_FUNCTION__
)
)) {
5547 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
5548 ast_str_substitute_variables(&str1, 0, ast, pagersubject);
5549 if (check_mime(ast_str_buffer(str1))) {
5550 int first_line = 1;
5551 char *ptr;
5552 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
5553 while ((ptr = strchr(ast_str_buffer(str2), ' ')(__extension__ (__builtin_constant_p (' ') && !__builtin_constant_p
(ast_str_buffer(str2)) && (' ') == '\0' ? (char *) __rawmemchr
(ast_str_buffer(str2), ' ') : __builtin_strchr (ast_str_buffer
(str2), ' ')))
)) {
5554 *ptr = '\0';
5555 fprintf(p, "%s %s" ENDL"\n", first_line ? "Subject:" : "", ast_str_buffer(str2));
5556 first_line = 0;
5557 /* Substring is smaller, so this will never grow */
5558 ast_str_set(&str2, 0, "%s", ptr + 1);
5559 }
5560 fprintf(p, "%s %s" ENDL"\n", first_line ? "Subject:" : "", ast_str_buffer(str2));
5561 } else {
5562 fprintf(p, "Subject: %s" ENDL"\n", ast_str_buffer(str1));
5563 }
5564 ast = ast_channel_unref(ast)({ __ao2_ref((ast), (-1), "", "app_voicemail.c", 5564, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
5565 } else {
5566 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 5566, __PRETTY_FUNCTION__, "Cannot allocate the channel for variables substitution\n");
5567 }
5568 } else {
5569 if (ast_strlen_zero(flag)_ast_strlen_zero(flag, "app_voicemail.c", __PRETTY_FUNCTION__
, 5569)
) {
5570 fprintf(p, "Subject: New VM\n\n");
5571 } else {
5572 fprintf(p, "Subject: New %s VM\n\n", flag);
5573 }
5574 }
5575
5576 if (pagerbody) {
5577 struct ast_channel *ast;
5578 if ((ast = ast_dummy_channel_alloc()__ast_dummy_channel_alloc("app_voicemail.c", 5578, __PRETTY_FUNCTION__
)
)) {
5579 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
5580 ast_str_substitute_variables(&str1, 0, ast, pagerbody);
5581 fprintf(p, "%s" ENDL"\n", ast_str_buffer(str1));
5582 ast = ast_channel_unref(ast)({ __ao2_ref((ast), (-1), "", "app_voicemail.c", 5582, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
5583 } else {
5584 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 5584, __PRETTY_FUNCTION__, "Cannot allocate the channel for variables substitution\n");
5585 }
5586 } else {
5587 fprintf(p, "New %s long %s msg in box %s\n"
5588 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
5589 }
5590
5591 fclose(p);
5592 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
5593 ast_safe_system(tmp2);
5594 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 5594, __PRETTY_FUNCTION__, "Sent page to %s with command '%s'\n"
, pager, mailcmd); } } while (0)
;
5595 ast_freefree(str1);
5596 ast_freefree(str2);
5597 return 0;
5598}
5599
5600/*!
5601 * \brief Gets the current date and time, as formatted string.
5602 * \param s The buffer to hold the output formatted date.
5603 * \param len the length of the buffer. Used to prevent buffer overflow in ast_strftime.
5604 *
5605 * The date format string used is "%a %b %e %r UTC %Y".
5606 *
5607 * \return zero on success, -1 on error.
5608 */
5609static int get_date(char *s, int len)
5610{
5611 struct ast_tm tm;
5612 struct timeval t = ast_tvnow();
5613
5614 ast_localtime(&t, &tm, "UTC");
5615
5616 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
5617}
5618
5619static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
5620{
5621 int res;
5622 char fn[PATH_MAX4096];
5623 char dest[PATH_MAX4096];
5624
5625 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
5626
5627 if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
5628 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 5628, __PRETTY_FUNCTION__, "Failed to make directory(%s)\n", fn);
5629 return -1;
5630 }
5631
5632 RETRIEVE(fn, -1, ext, context);
5633 if (ast_fileexists(fn, NULL((void*)0), NULL((void*)0)) > 0) {
5634 res = ast_stream_and_wait(chan, fn, ecodes);
5635 if (res) {
5636 DISPOSE(fn, -1);
5637 return res;
5638 }
5639 } else {
5640 /* Dispose just in case */
5641 DISPOSE(fn, -1);
5642 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
5643 if (res)
5644 return res;
5645 res = ast_say_digit_str(chan, ext, ecodes, ast_channel_language(chan));
5646 if (res)
5647 return res;
5648 }
5649 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
5650 return res;
5651}
5652
5653static void free_zone(struct vm_zone *z)
5654{
5655 ast_freefree(z);
5656}
5657
5658#ifdef ODBC_STORAGE
5659static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
5660{
5661 int x = -1;
5662 int res;
5663 SQLHSTMT stmt = NULL((void*)0);
5664 char sql[PATH_MAX4096];
5665 char rowdata[20];
5666 char tmp[PATH_MAX4096] = "";
5667 struct odbc_obj *obj = NULL((void*)0);
5668 char *context;
5669 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
5670
5671 if (newmsgs)
5672 *newmsgs = 0;
5673 if (oldmsgs)
5674 *oldmsgs = 0;
5675 if (urgentmsgs)
5676 *urgentmsgs = 0;
5677
5678 /* If no mailbox, return immediately */
5679 if (ast_strlen_zero(mailbox)_ast_strlen_zero(mailbox, "app_voicemail.c", __PRETTY_FUNCTION__
, 5679)
)
5680 return 0;
5681
5682 ast_copy_string(tmp, mailbox, sizeof(tmp));
5683
5684 if (strchr(mailbox, ' ')(__extension__ (__builtin_constant_p (' ') && !__builtin_constant_p
(mailbox) && (' ') == '\0' ? (char *) __rawmemchr (mailbox
, ' ') : __builtin_strchr (mailbox, ' ')))
|| strchr(mailbox, ',')(__extension__ (__builtin_constant_p (',') && !__builtin_constant_p
(mailbox) && (',') == '\0' ? (char *) __rawmemchr (mailbox
, ',') : __builtin_strchr (mailbox, ',')))
) {
5685 int u, n, o;
5686 char *next, *remaining = tmp;
5687 while ((next = strsep(&remaining, " ,"))) {
5688 if (inboxcount2(next, urgentmsgs ? &u : NULL((void*)0), &n, &o)) {
5689 return -1;
5690 }
5691 if (urgentmsgs) {
5692 *urgentmsgs += u;
5693 }
5694 if (newmsgs) {
5695 *newmsgs += n;
5696 }
5697 if (oldmsgs) {
5698 *oldmsgs += o;
5699 }
5700 }
5701 return 0;
5702 }
5703
5704 context = strchr(tmp, '@')(__extension__ (__builtin_constant_p ('@') && !__builtin_constant_p
(tmp) && ('@') == '\0' ? (char *) __rawmemchr (tmp, '@'
) : __builtin_strchr (tmp, '@')))
;
5705 if (context) {
5706 *context = '\0';
5707 context++;
5708 } else
5709 context = "default";
5710
5711 if ((obj = ast_odbc_request_obj(odbc_database, 0))) {
5712 do {
5713 if (newmsgs) {
5714 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
5715 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
5716 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 5716, __PRETTY_FUNCTION__, "SQL Execute error!\n[%s]\n\n", sql);
5717 break;
5718 }
5719 res = SQLFetch(stmt);
5720 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
5721 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 5721, __PRETTY_FUNCTION__, "SQL Fetch error!\n[%s]\n\n", sql);
5722 break;
5723 }
5724 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL((void*)0));
5725 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
5726 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 5726, __PRETTY_FUNCTION__, "SQL Get Data error!\n[%s]\n\n", sql);
5727 break;
5728 }
5729 *newmsgs = atoi(rowdata);
5730 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
5731 }
5732
5733 if (oldmsgs) {
5734 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
5735 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
5736 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 5736, __PRETTY_FUNCTION__, "SQL Execute error!\n[%s]\n\n", sql);
5737 break;
5738 }
5739 res = SQLFetch(stmt);
5740 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
5741 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 5741, __PRETTY_FUNCTION__, "SQL Fetch error!\n[%s]\n\n", sql);
5742 break;
5743 }
5744 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL((void*)0));
5745 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
5746 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 5746, __PRETTY_FUNCTION__, "SQL Get Data error!\n[%s]\n\n", sql);
5747 break;
5748 }
5749 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
5750 *oldmsgs = atoi(rowdata);
5751 }
5752
5753 if (urgentmsgs) {
5754 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent");
5755 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
5756 ast_log(LOG_WARNING3, "app_voicemail.c", 5756, __PRETTY_FUNCTION__, "SQL Execute error!\n[%s]\n\n", sql);
5757 break;
5758 }
5759 res = SQLFetch(stmt);
5760 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
5761 ast_log(LOG_WARNING3, "app_voicemail.c", 5761, __PRETTY_FUNCTION__, "SQL Fetch error!\n[%s]\n\n", sql);
5762 break;
5763 }
5764 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL((void*)0));
5765 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
5766 ast_log(LOG_WARNING3, "app_voicemail.c", 5766, __PRETTY_FUNCTION__, "SQL Get Data error!\n[%s]\n\n", sql);
5767 break;
5768 }
5769 *urgentmsgs = atoi(rowdata);
5770 }
5771
5772 x = 0;
5773 } while (0);
5774 } else {
5775 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 5775, __PRETTY_FUNCTION__, "Failed to obtain database object for '%s'!\n", odbc_database);
5776 }
5777
5778 if (stmt) {
5779 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
5780 }
5781 if (obj) {
5782 ast_odbc_release_obj(obj);
5783 }
5784 return x;
5785}
5786
5787/*!
5788 * \brief Gets the number of messages that exist in a mailbox folder.
5789 * \param mailbox_id
5790 * \param folder
5791 *
5792 * This method is used when ODBC backend is used.
5793 * \return The number of messages in this mailbox folder (zero or more).
5794 */
5795static int messagecount(const char *mailbox_id, const char *folder)
5796{
5797 struct odbc_obj *obj = NULL((void*)0);
5798 char *context;
5799 char *mailbox;
5800 int nummsgs = 0;
5801 int res;
5802 SQLHSTMT stmt = NULL((void*)0);
5803 char sql[PATH_MAX4096];
5804 char rowdata[20];
5805 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
5806
5807 /* If no mailbox, return immediately */
5808 if (ast_strlen_zero(mailbox_id)_ast_strlen_zero(mailbox_id, "app_voicemail.c", __PRETTY_FUNCTION__
, 5808)
5809 || separate_mailbox(ast_strdupa(mailbox_id)(__extension__ ({ const char *__old = (mailbox_id); size_t __len
= strlen(__old) + 1; char *__new = __builtin_alloca(__len); memcpy
(__new, __old, __len); __new; }))
, &mailbox, &context)) {
5810 return 0;
5811 }
5812
5813 if (ast_strlen_zero(folder)_ast_strlen_zero(folder, "app_voicemail.c", __PRETTY_FUNCTION__
, 5813)
) {
5814 folder = "INBOX";
5815 }
5816
5817 obj = ast_odbc_request_obj(odbc_database, 0);
5818 if (obj) {
5819 if (!strcmp(folder, "INBOX")) {
5820 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/INBOX' OR dir = '%s%s/%s/Urgent'", odbc_table, VM_SPOOL_DIR, context, mailbox, VM_SPOOL_DIR, context, mailbox);
5821 } else {
5822 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
5823 }
5824 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
5825 if (!stmt) {
5826 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 5826, __PRETTY_FUNCTION__, "SQL Execute error!\n[%s]\n\n", sql);
5827 goto yuck;
5828 }
5829 res = SQLFetch(stmt);
5830 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
5831 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 5831, __PRETTY_FUNCTION__, "SQL Fetch error!\n[%s]\n\n", sql);
5832 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
5833 goto yuck;
5834 }
5835 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL((void*)0));
5836 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
5837 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 5837, __PRETTY_FUNCTION__, "SQL Get Data error!\n[%s]\n\n", sql);
5838 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
5839 goto yuck;
5840 }
5841 nummsgs = atoi(rowdata);
5842 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
5843 } else
5844 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 5844, __PRETTY_FUNCTION__, "Failed to obtain database object for '%s'!\n", odbc_database);
5845
5846yuck:
5847 if (obj)
5848 ast_odbc_release_obj(obj);
5849 return nummsgs;
5850}
5851
5852/**
5853 * \brief Determines if the given folder has messages.
5854 * \param mailbox The @ delimited string for user@context. If no context is found, uses 'default' for the context.
5855 *
5856 * This function is used when the mailbox is stored in an ODBC back end.
5857 * This invokes the messagecount(). Here we are interested in the presence of messages (> 0) only, not the actual count.
5858 * \return 1 if the folder has one or more messages. zero otherwise.
5859 */
5860static int has_voicemail(const char *mailboxes, const char *folder)
5861{
5862 char *parse;
5863 char *mailbox;
5864
5865 parse = ast_strdupa(mailboxes)(__extension__ ({ const char *__old = (mailboxes); size_t __len
= strlen(__old) + 1; char *__new = __builtin_alloca(__len); memcpy
(__new, __old, __len); __new; }))
;
5866 while ((mailbox = strsep(&parse, ",&"))) {
5867 if (messagecount(mailbox, folder)) {
5868 return 1;
5869 }
5870 }
5871 return 0;
5872}
5873#endif
5874#ifndef IMAP_STORAGE
5875/*!
5876 * \brief Copies a message from one mailbox to another.
5877 * \param chan
5878 * \param vmu
5879 * \param imbox
5880 * \param msgnum
5881 * \param duration
5882 * \param recip
5883 * \param fmt
5884 * \param dir
5885 * \param flag, dest_folder
5886 *
5887 * This is only used by file storage based mailboxes.
5888 *
5889 * \return zero on success, -1 on error.
5890 */
5891static int copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int imbox, int msgnum, long duration, struct ast_vm_user *recip, char *fmt, char *dir, const char *flag, const char *dest_folder)
5892{
5893 char fromdir[PATH_MAX4096], todir[PATH_MAX4096], frompath[PATH_MAX4096], topath[PATH_MAX4096];
5894 const char *frombox = mbox(vmu, imbox);
5895 const char *userfolder;
5896 int recipmsgnum;
5897 int res = 0;
5898
5899 ast_log(AST_LOG_NOTICE2, "app_voicemail.c", 5899, __PRETTY_FUNCTION__, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
5900
5901 if (!ast_strlen_zero(flag)_ast_strlen_zero(flag, "app_voicemail.c", __PRETTY_FUNCTION__
, 5901)
&& !strcmp(flag, "Urgent")) { /* If urgent, copy to Urgent folder */
5902 userfolder = "Urgent";
5903 } else if (!ast_strlen_zero(dest_folder)_ast_strlen_zero(dest_folder, "app_voicemail.c", __PRETTY_FUNCTION__
, 5903)
) {
5904 userfolder = dest_folder;
5905 } else {
5906 userfolder = "INBOX";
5907 }
5908
5909 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
5910
5911 if (!dir)
5912 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
5913 else
5914 ast_copy_string(fromdir, dir, sizeof(fromdir));
5915
5916 make_file(frompath, sizeof(frompath), fromdir, msgnum);
5917 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
5918
5919 if (vm_lock_path(todir))
5920 return ERROR_LOCK_PATH-100;
5921
5922 recipmsgnum = last_message_index(recip, todir) + 1;
5923 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
5924 make_file(topath, sizeof(topath), todir, recipmsgnum);
5925#ifndef ODBC_STORAGE
5926 if (EXISTS(fromdir, msgnum, frompath, chan ? ast_channel_language(chan) : "")(ast_fileexists(frompath,((void*)0),chan ? ast_channel_language
(chan) : "") > 0)
) {
5927 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath)(copy_plain_file(frompath,topath));;
5928 } else {
5929#endif
5930 /* If we are prepending a message for ODBC, then the message already
5931 * exists in the database, but we want to force copying from the
5932 * filesystem (since only the FS contains the prepend). */
5933 copy_plain_file(frompath, topath);
5934 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL, NULL);
5935 vm_delete(topath);
5936#ifndef ODBC_STORAGE
5937 }
5938#endif
5939 } else {
5940 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 5940, __PRETTY_FUNCTION__, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
5941 res = -1;
5942 }
5943 ast_unlock_path(todir);
5944 if (chan) {
5945 struct ast_party_caller *caller = ast_channel_caller(chan);
5946 notify_new_message(chan, recip, NULL((void*)0), recipmsgnum, duration, fmt,
5947 S_COR(caller->id.number.valid, caller->id.number.str, NULL)({typeof(&((caller->id.number.str)[0])) __x = (caller->
id.number.str); (caller->id.number.valid) && !_ast_strlen_zero
(__x, "app_voicemail.c", __PRETTY_FUNCTION__, 5947) ? (__x) :
(((void*)0));})
,
5948 S_COR(caller->id.name.valid, caller->id.name.str, NULL)({typeof(&((caller->id.name.str)[0])) __x = (caller->
id.name.str); (caller->id.name.valid) && !_ast_strlen_zero
(__x, "app_voicemail.c", __PRETTY_FUNCTION__, 5948) ? (__x) :
(((void*)0));})
,
5949 flag);
5950 }
5951
5952 return res;
5953}
5954#endif
5955#if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
5956
5957static int messagecount(const char *mailbox_id, const char *folder)
5958{
5959 char *context;
5960 char *mailbox;
5961
5962 if (ast_strlen_zero(mailbox_id)_ast_strlen_zero(mailbox_id, "app_voicemail.c", __PRETTY_FUNCTION__
, 5962)
5963 || separate_mailbox(ast_strdupa(mailbox_id)(__extension__ ({ const char *__old = (mailbox_id); size_t __len
= strlen(__old) + 1; char *__new = __builtin_alloca(__len); memcpy
(__new, __old, __len); __new; }))
, &mailbox, &context)) {
5964 return 0;
5965 }
5966
5967 return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
5968}
5969
5970static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
5971{
5972 DIR *dir;
5973 struct dirent *de;
5974 char fn[256];
5975 int ret = 0;
5976
5977 /* If no mailbox, return immediately */
5978 if (ast_strlen_zero(mailbox)_ast_strlen_zero(mailbox, "app_voicemail.c", __PRETTY_FUNCTION__
, 5978)
)
5979 return 0;
5980
5981 if (ast_strlen_zero(folder)_ast_strlen_zero(folder, "app_voicemail.c", __PRETTY_FUNCTION__
, 5981)
)
5982 folder = "INBOX";
5983 if (ast_strlen_zero(context)_ast_strlen_zero(context, "app_voicemail.c", __PRETTY_FUNCTION__
, 5983)
)
5984 context = "default";
5985
5986 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
5987
5988 if (!(dir = opendir(fn)))
5989 return 0;
5990
5991 while ((de = readdir(dir))) {
5992 if (!strncasecmp(de->d_name, "msg", 3)) {
5993 if (shortcircuit) {
5994 ret = 1;
5995 break;
5996 } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
5997 ret++;
5998 }
5999 }
6000 }
6001
6002 closedir(dir);
6003
6004 return ret;
6005}
6006
6007/**
6008 * \brief Determines if the given folder has messages.
6009 * \param mailbox The \@ delimited string for user\@context. If no context is found, uses 'default' for the context.
6010 * \param folder the folder to look in
6011 *
6012 * This function is used when the mailbox is stored in a filesystem back end.
6013 * This invokes the __has_voicemail(). Here we are interested in the presence of messages (> 0) only, not the actual count.
6014 * \return 1 if the folder has one or more messages. zero otherwise.
6015 */
6016static int has_voicemail(const char *mailbox, const char *folder)
6017{
6018 char tmp[256], *tmp2 = tmp, *box, *context;
6019 ast_copy_string(tmp, mailbox, sizeof(tmp));
6020 if (ast_strlen_zero(folder)_ast_strlen_zero(folder, "app_voicemail.c", __PRETTY_FUNCTION__
, 6020)
) {
6021 folder = "INBOX";
6022 }
6023 while ((box = strsep(&tmp2, ",&"))) {
6024 if ((context = strchr(box, '@')(__extension__ (__builtin_constant_p ('@') && !__builtin_constant_p
(box) && ('@') == '\0' ? (char *) __rawmemchr (box, '@'
) : __builtin_strchr (box, '@')))
))
6025 *context++ = '\0';
6026 else
6027 context = "default";
6028 if (__has_voicemail(context, box, folder, 1))
6029 return 1;
6030 /* If we are checking INBOX, we should check Urgent as well */
6031 if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
6032 return 1;
6033 }
6034 }
6035 return 0;
6036}
6037
6038
6039static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
6040{
6041 char tmp[256];
6042 char *context;
6043
6044 /* If no mailbox, return immediately */
6045 if (ast_strlen_zero(mailbox)_ast_strlen_zero(mailbox, "app_voicemail.c", __PRETTY_FUNCTION__
, 6045)
)
6046 return 0;
6047
6048 if (newmsgs)
6049 *newmsgs = 0;
6050 if (oldmsgs)
6051 *oldmsgs = 0;
6052 if (urgentmsgs)
6053 *urgentmsgs = 0;
6054
6055 if (strchr(mailbox, ',')(__extension__ (__builtin_constant_p (',') && !__builtin_constant_p
(mailbox) && (',') == '\0' ? (char *) __rawmemchr (mailbox
, ',') : __builtin_strchr (mailbox, ',')))
) {
6056 int tmpnew, tmpold, tmpurgent;
6057 char *mb, *cur;
6058
6059 ast_copy_string(tmp, mailbox, sizeof(tmp));
6060 mb = tmp;
6061 while ((cur = strsep(&mb, ", "))) {
6062 if (!ast_strlen_zero(cur)_ast_strlen_zero(cur, "app_voicemail.c", __PRETTY_FUNCTION__,
6062)
) {
6063 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL((void*)0), newmsgs ? &tmpnew : NULL((void*)0), oldmsgs ? &tmpold : NULL((void*)0)))
6064 return -1;
6065 else {
6066 if (newmsgs)
6067 *newmsgs += tmpnew;
6068 if (oldmsgs)
6069 *oldmsgs += tmpold;
6070 if (urgentmsgs)
6071 *urgentmsgs += tmpurgent;
6072 }
6073 }
6074 }
6075 return 0;
6076 }
6077
6078 ast_copy_string(tmp, mailbox, sizeof(tmp));
6079
6080 if ((context = strchr(tmp, '@')(__extension__ (__builtin_constant_p ('@') && !__builtin_constant_p
(tmp) && ('@') == '\0' ? (char *) __rawmemchr (tmp, '@'
) : __builtin_strchr (tmp, '@')))
))
6081 *context++ = '\0';
6082 else
6083 context = "default";
6084
6085 if (newmsgs)
6086 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
6087 if (oldmsgs)
6088 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
6089 if (urgentmsgs)
6090 *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
6091
6092 return 0;
6093}
6094
6095#endif
6096
6097/* Exactly the same function for file-based, ODBC-based, and IMAP-based, so why create 3 different copies? */
6098static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
6099{
6100 int urgentmsgs = 0;
6101 int res = inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
6102 if (newmsgs) {
6103 *newmsgs += urgentmsgs;
6104 }
6105 return res;
6106}
6107
6108static void run_externnotify(char *context, char *extension, const char *flag)
6109{
6110 char arguments[255];
6111 char ext_context[256] = "";
6112 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
6113 struct ast_smdi_mwi_message *mwi_msg;
6114
6115 if (!ast_strlen_zero(context)_ast_strlen_zero(context, "app_voicemail.c", __PRETTY_FUNCTION__
, 6115)
)
6116 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
6117 else
6118 ast_copy_string(ext_context, extension, sizeof(ext_context));
6119
6120 if (smdi_iface) {
6121 if (ast_app_has_voicemail(ext_context, NULL((void*)0)))
6122 ast_smdi_mwi_set(smdi_iface, extension);
6123 else
6124 ast_smdi_mwi_unset(smdi_iface, extension);
6125
6126 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT1000, extension))) {
6127 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 6127, __PRETTY_FUNCTION__, "Error executing SMDI MWI change for %s\n", extension);
6128 if (!strncmp(mwi_msg->cause, "INV", 3)(__extension__ (__builtin_constant_p (3) && ((__builtin_constant_p
(mwi_msg->cause) && strlen (mwi_msg->cause) <
((size_t) (3))) || (__builtin_constant_p ("INV") && strlen
("INV") < ((size_t) (3)))) ? strcmp (mwi_msg->cause, "INV"
) : strncmp (mwi_msg->cause, "INV", 3)))
)
6129 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 6129, __PRETTY_FUNCTION__, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
6130 else if (!strncmp(mwi_msg->cause, "BLK", 3)(__extension__ (__builtin_constant_p (3) && ((__builtin_constant_p
(mwi_msg->cause) && strlen (mwi_msg->cause) <
((size_t) (3))) || (__builtin_constant_p ("BLK") && strlen
("BLK") < ((size_t) (3)))) ? strcmp (mwi_msg->cause, "BLK"
) : strncmp (mwi_msg->cause, "BLK", 3)))
)
6131 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 6131, __PRETTY_FUNCTION__, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
6132 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 6132, __PRETTY_FUNCTION__, "The switch reported '%s'\n", mwi_msg->cause);
6133 ao2_ref(mwi_msg, -1)__ao2_ref((mwi_msg), (-1), "", "app_voicemail.c", 6133, __PRETTY_FUNCTION__
)
;
6134 } else {
6135 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 6135, __PRETTY_FUNCTION__, "Successfully executed SMDI MWI change for %s\n"
, extension); } } while (0)
;
6136 }
6137 }
6138
6139 if (!ast_strlen_zero(externnotify)_ast_strlen_zero(externnotify, "app_voicemail.c", __PRETTY_FUNCTION__
, 6139)
) {
6140 if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
6141 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 6141, __PRETTY_FUNCTION__, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
6142 } else {
6143 snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &",
6144 externnotify, S_OR(context, "\"\"")({typeof(&((context)[0])) __x = (context); _ast_strlen_zero
(__x, "app_voicemail.c", __PRETTY_FUNCTION__, 6144) ? ("\"\""
) : __x;})
,
6145 extension, newvoicemails,
6146 oldvoicemails, urgentvoicemails);
6147 ast_debug(1, "Executing %s\n", arguments)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 6147, __PRETTY_FUNCTION__, "Executing %s\n"
, arguments); } } while (0)
;
6148 ast_safe_system(arguments);
6149 }
6150 }
6151}
6152
6153/*!
6154 * \brief Variables used for saving a voicemail.
6155 *
6156 * This includes the record gain, mode flags, and the exit context of the chanel that was used for leaving the voicemail.
6157 */
6158struct leave_vm_options {
6159 unsigned int flags;
6160 signed char record_gain;
6161 char *exitcontext;
6162};
6163
6164static void generate_msg_id(char *dst)
6165{
6166 /* msg id is time of msg_id generation plus an incrementing value
6167 * called each time a new msg_id is generated. This should achieve uniqueness,
6168 * but only in single system solutions.
6169 */
6170 unsigned int unique_counter = ast_atomic_fetchadd_int(&msg_id_incrementor, +1);
6171 snprintf(dst, MSG_ID_LEN256, "%ld-%08x", (long) time(NULL((void*)0)), unique_counter);
6172}
6173
6174/*!
6175 * \internal
6176 * \brief Creates a voicemail based on a specified file to a mailbox.
6177 * \param recdata A vm_recording_data containing filename and voicemail txt info.
6178 * \retval -1 failure
6179 * \retval 0 success
6180 *
6181 * This is installed to the app.h voicemail functions and accommodates all voicemail
6182 * storage methods. It should probably be broken out along with leave_voicemail at
6183 * some point in the future.
6184 *
6185 * This function currently only works for a single recipient and only uses the format
6186 * specified in recording_ext.
6187 */
6188static int msg_create_from_file(struct ast_vm_recording_data *recdata)
6189{
6190 /* voicemail recipient structure */
6191 struct ast_vm_user *recipient; /* points to svm once it's been created */
6192 struct ast_vm_user svm; /* struct storing the voicemail recipient */
6193
6194 /* File paths */
6195 char tmpdir[PATH_MAX4096]; /* directory temp files are stored in */
6196 char tmptxtfile[PATH_MAX4096]; /* tmp file for voicemail txt file */
6197 char desttxtfile[PATH_MAX4096]; /* final destination for txt file */
6198 char tmpaudiofile[PATH_MAX4096]; /* tmp file where audio is stored */
6199 char dir[PATH_MAX4096]; /* destination for tmp files on completion */
6200 char destination[PATH_MAX4096]; /* destination with msgXXXX. Basically <dir>/msgXXXX */
6201
6202 /* stuff that only seems to be needed for IMAP */
6203 #ifdef IMAP_STORAGE
6204 struct vm_state *vms = NULL((void*)0);
6205 char ext_context[256] = "";
6206 char *fmt = ast_strdupa(recdata->recording_ext)(__extension__ ({ const char *__old = (recdata->recording_ext
); size_t __len = strlen(__old) + 1; char *__new = __builtin_alloca
(__len); memcpy (__new, __old, __len); __new; }))
;
6207 int newmsgs = 0;
6208 int oldmsgs = 0;
6209 #endif
6210
6211 /* miscellaneous operational variables */
6212 int res = 0; /* Used to store error codes from functions */
6213 int txtdes /* File descriptor for the text file used to write the voicemail info */;
6214 FILE *txt; /* FILE pointer to text file used to write the voicemail info */
6215 char date[256]; /* string used to hold date of the voicemail (only used for ODBC) */
6216 int msgnum; /* the 4 digit number designated to the voicemail */
6217 int duration = 0; /* Length of the audio being recorded in seconds */
6218 struct ast_filestream *recording_fs; /*used to read the recording to get duration data */
6219
6220 /* We aren't currently doing anything with category, since it comes from a channel variable and
6221 * this function doesn't use channels, but this function could add that as an argument later. */
6222 const char *category = NULL((void*)0); /* pointless for now */
6223 char msg_id[MSG_ID_LEN256];
6224
6225 /* Start by checking to see if the file actually exists... */
6226 if (!(ast_fileexists(recdata->recording_file, recdata->recording_ext, NULL((void*)0)))) {
6227 ast_log(LOG_ERROR4, "app_voicemail.c", 6227, __PRETTY_FUNCTION__, "File: %s not found.\n", recdata->recording_file);
6228 return -1;
6229 }
6230
6231 memset(&svm, 0, sizeof(svm));
6232 if (!(recipient = find_user(&svm, recdata->context, recdata->mailbox))) {
6233 ast_log(LOG_ERROR4, "app_voicemail.c", 6233, __PRETTY_FUNCTION__, "No entry in voicemail config file for '%s@%s'\n", recdata->mailbox, recdata->context);
6234 return -1;
6235 }
6236
6237 /* determine duration in seconds */
6238 if ((recording_fs = ast_readfile(recdata->recording_file, recdata->recording_ext, NULL((void*)0), 0, 0, VOICEMAIL_DIR_MODE0777))) {
6239 if (!ast_seekstream(recording_fs, 0, SEEK_END2)) {
6240 long framelength = ast_tellstream(recording_fs);
6241 int sample_rate = ast_ratestream(recording_fs);
6242 if (sample_rate) {
6243 duration = (int) (framelength / sample_rate);
6244 } else {
6245 ast_log(LOG_ERROR4, "app_voicemail.c", 6245, __PRETTY_FUNCTION__,"Unable to determine sample rate of recording %s\n", recdata->recording_file);
6246 }
6247 }
6248 ast_closestream(recording_fs);
6249 }
6250
6251 /* If the duration was below the minimum duration for the user, let's just drop the whole thing now */
6252 if (duration < recipient->minsecs) {
6253 ast_log(LOG_NOTICE2, "app_voicemail.c", 6253, __PRETTY_FUNCTION__, "Copying recording to voicemail %s@%s skipped because duration was shorter than "
6254 "minmessage of recipient\n", recdata->mailbox, recdata->context);
6255 return -1;
6256 }
6257
6258 /* Note that this number must be dropped back to a net sum of zero before returning from this function */
6259
6260 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), recipient->context, recdata->mailbox, "tmp"))) {
6261 ast_log(LOG_ERROR4, "app_voicemail.c", 6261, __PRETTY_FUNCTION__, "Failed to make directory.\n");
6262 }
6263
6264 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
6265 txtdes = mkstemp(tmptxtfile);
6266 if (txtdes < 0) {
6267 chmod(tmptxtfile, VOICEMAIL_FILE_MODE0666 & ~my_umask);
6268 /* Something screwed up. Abort. */
6269 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 6269, __PRETTY_FUNCTION__, "Unable to create message file: %s\n", strerror(errno(*__errno_location ())));
6270 free_user(recipient);
6271 return -1;
6272 }
6273
6274 /* Store information */
6275 txt = fdopen(txtdes, "w+");
6276 if (txt) {
6277 generate_msg_id(msg_id);
6278 get_date(date, sizeof(date));
6279 fprintf(txt,
6280 ";\n"
6281 "; Message Information file\n"
6282 ";\n"
6283 "[message]\n"
6284 "origmailbox=%s\n"
6285 "context=%s\n"
6286 "macrocontext=%s\n"
6287 "exten=%s\n"
6288 "rdnis=Unknown\n"
6289 "priority=%d\n"
6290 "callerchan=%s\n"
6291 "callerid=%s\n"
6292 "origdate=%s\n"
6293 "origtime=%ld\n"
6294 "category=%s\n"
6295 "msg_id=%s\n"
6296 "flag=\n" /* flags not supported in copy from file yet */
6297 "duration=%d\n", /* Don't have any reliable way to get duration of file. */
6298
6299 recdata->mailbox,
6300 S_OR(recdata->call_context, "")({typeof(&((recdata->call_context)[0])) __x = (recdata
->call_context); _ast_strlen_zero(__x, "app_voicemail.c", __PRETTY_FUNCTION__
, 6300) ? ("") : __x;})
,
6301 S_OR(recdata->call_macrocontext, "")({typeof(&((recdata->call_macrocontext)[0])) __x = (recdata
->call_macrocontext); _ast_strlen_zero(__x, "app_voicemail.c"
, __PRETTY_FUNCTION__, 6301) ? ("") : __x;})
,
6302 S_OR(recdata->call_extension, "")({typeof(&((recdata->call_extension)[0])) __x = (recdata
->call_extension); _ast_strlen_zero(__x, "app_voicemail.c"
, __PRETTY_FUNCTION__, 6302) ? ("") : __x;})
,
6303 recdata->call_priority,
6304 S_OR(recdata->call_callerchan, "Unknown")({typeof(&((recdata->call_callerchan)[0])) __x = (recdata
->call_callerchan); _ast_strlen_zero(__x, "app_voicemail.c"
, __PRETTY_FUNCTION__, 6304) ? ("Unknown") : __x;})
,
6305 S_OR(recdata->call_callerid, "Unknown")({typeof(&((recdata->call_callerid)[0])) __x = (recdata
->call_callerid); _ast_strlen_zero(__x, "app_voicemail.c",
__PRETTY_FUNCTION__, 6305) ? ("Unknown") : __x;})
,
6306 date, (long) time(NULL((void*)0)),
6307 S_OR(category, "")({typeof(&((category)[0])) __x = (category); _ast_strlen_zero
(__x, "app_voicemail.c", __PRETTY_FUNCTION__, 6307) ? ("") : __x
;})
,
6308 msg_id,
6309 duration);
6310
6311 /* Since we are recording from a file, we shouldn't need to do anything else with
6312 * this txt file */
6313 fclose(txt);
6314
6315 } else {
6316 ast_log(LOG_WARNING3, "app_voicemail.c", 6316, __PRETTY_FUNCTION__, "Error opening text file for output\n");
6317 if (ast_check_realtime("voicemail_data")) {
6318 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL((char *)((void*)0)));
6319 }
6320 free_user(recipient);
6321 return -1;
6322 }
6323
6324 /* At this point, the actual creation of a voicemail message should be finished.
6325 * Now we just need to copy the files being recorded into the receiving folder. */
6326
6327 create_dirpath(dir, sizeof(dir), recipient->context, recipient->mailbox, recdata->folder);
6328
6329#ifdef IMAP_STORAGE
6330 /* make recipient info into an inboxcount friendly string */
6331 snprintf(ext_context, sizeof(ext_context), "%s@%s", recipient->mailbox, recipient->context);
6332
6333 /* Is ext a mailbox? */
6334 /* must open stream for this user to get info! */
6335 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
6336 if (res < 0) {
6337 ast_log(LOG_NOTICE2, "app_voicemail.c", 6337, __PRETTY_FUNCTION__, "Can not leave voicemail, unable to count messages\n");
6338 free_user(recipient);
6339 unlink(tmptxtfile);
6340 return -1;
6341 }
6342 if (!(vms = get_vm_state_by_mailbox(recipient->mailbox, recipient->context, 0))) {
6343 /* It is possible under certain circumstances that inboxcount did not
6344 * create a vm_state when it was needed. This is a catchall which will
6345 * rarely be used.
6346 */
6347 if (!(vms = create_vm_state_from_user(recipient))) {
6348 ast_log(LOG_ERROR4, "app_voicemail.c", 6348, __PRETTY_FUNCTION__, "Couldn't allocate necessary space\n");
6349 free_user(recipient);
6350 unlink(tmptxtfile);
6351 return -1;
6352 }
6353 }
6354 vms->newmessages++;
6355
6356 /* here is a big difference! We add one to it later */
6357 msgnum = newmsgs + oldmsgs;
6358 ast_debug(3, "Messagecount set to %d\n", msgnum)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 6358, __PRETTY_FUNCTION__, "Messagecount set to %d\n"
, msgnum); } } while (0)
;
6359 snprintf(destination, sizeof(destination), "%simap/msg%s%04d", VM_SPOOL_DIR, recipient->mailbox, msgnum);
6360
6361 /* Check to see if we have enough room in the mailbox. If not, spit out an error and end
6362 * Note that imap_check_limits raises inprocess_count if successful */
6363 if ((res = imap_check_limits(NULL((void*)0), vms, recipient, msgnum))) {
6364 ast_log(LOG_NOTICE2, "app_voicemail.c", 6364, __PRETTY_FUNCTION__, "Didn't copy to voicemail. Mailbox for %s@%s is full.\n", recipient->mailbox, recipient->context);
6365 inprocess_count(recipient->mailbox, recipient->context, -1);
6366 free_user(recipient);
6367 unlink(tmptxtfile);
6368 return -1;
6369 }
6370
6371#else
6372
6373 /* Check to see if the mailbox is full for ODBC/File storage */
6374 ast_debug(3, "mailbox = %d : inprocess = %d\n", count_messages(recipient, dir),do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 6375, __PRETTY_FUNCTION__, "mailbox = %d : inprocess = %d\n"
, count_messages(recipient, dir), inprocess_count(recipient->
mailbox, recipient->context, 0)); } } while (0)
6375 inprocess_count(recipient->mailbox, recipient->context, 0))do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 6375, __PRETTY_FUNCTION__, "mailbox = %d : inprocess = %d\n"
, count_messages(recipient, dir), inprocess_count(recipient->
mailbox, recipient->context, 0)); } } while (0)
;
6376 if (count_messages(recipient, dir) > recipient->maxmsg - inprocess_count(recipient->mailbox, recipient->context, +1)) {
6377 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 6377, __PRETTY_FUNCTION__, "Didn't copy to voicemail. Mailbox for %s@%s is full.\n", recipient->mailbox, recipient->context);
6378 inprocess_count(recipient->mailbox, recipient->context, -1);
6379 free_user(recipient);
6380 unlink(tmptxtfile);
6381 return -1;
6382 }
6383
6384 msgnum = last_message_index(recipient, dir) + 1;
6385#endif
6386
6387 /* Lock the directory receiving the voicemail since we want it to still exist when we attempt to copy the voicemail.
6388 * We need to unlock it before we return. */
6389 if (vm_lock_path(dir)) {
6390 ast_log(LOG_ERROR4, "app_voicemail.c", 6390, __PRETTY_FUNCTION__, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
6391 /* Delete files */
6392 ast_filedelete(tmptxtfile, NULL((void*)0));
6393 unlink(tmptxtfile);
6394 free_user(recipient);
6395 return -1;
6396 }
6397
6398 make_file(destination, sizeof(destination), dir, msgnum);
6399
6400 make_file(tmpaudiofile, sizeof(tmpaudiofile), tmpdir, msgnum);
6401
6402 if (ast_filecopy(recdata->recording_file, tmpaudiofile, recdata->recording_ext)) {
6403 ast_log(LOG_ERROR4, "app_voicemail.c", 6403, __PRETTY_FUNCTION__, "Audio file failed to copy to tmp dir. Probably low disk space.\n");
6404
6405 inprocess_count(recipient->mailbox, recipient->context, -1);
6406 ast_unlock_path(dir);
6407 free_user(recipient);
6408 unlink(tmptxtfile);
6409 return -1;
6410 }
6411
6412 /* Alright, try to copy to the destination folder now. */
6413 if (ast_filerename(tmpaudiofile, destination, recdata->recording_ext)) {
6414 ast_log(LOG_ERROR4, "app_voicemail.c", 6414, __PRETTY_FUNCTION__, "Audio file failed to move to destination directory. Permissions/Overlap?\n");
6415 inprocess_count(recipient->mailbox, recipient->context, -1);
6416 ast_unlock_path(dir);
6417 free_user(recipient);
6418 unlink(tmptxtfile);
6419 return -1;
6420 }
6421
6422 snprintf(desttxtfile, sizeof(desttxtfile), "%s.txt", destination);
6423 rename(tmptxtfile, desttxtfile);
6424
6425 if (chmod(desttxtfile, VOICEMAIL_FILE_MODE0666) < 0) {
6426 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 6426, __PRETTY_FUNCTION__, "Couldn't set permissions on voicemail text file %s: %s", desttxtfile, strerror(errno(*__errno_location ())));
6427 }
6428
6429
6430 ast_unlock_path(dir);
6431 inprocess_count(recipient->mailbox, recipient->context, -1);
6432
6433 /* If we copied something, we should store it either to ODBC or IMAP if we are using those. The STORE macro allows us
6434 * to do both with one line and is also safe to use with file storage mode. Also, if we are using ODBC, now is a good
6435 * time to create the voicemail database entry. */
6436 if (ast_fileexists(destination, NULL((void*)0), NULL((void*)0)) > 0) {
6437 if (ast_check_realtime("voicemail_data")) {
6438 get_date(date, sizeof(date));
6439 ast_store_realtime("voicemail_data",
6440 "origmailbox", recdata->mailbox,
6441 "context", S_OR(recdata->context, "")({typeof(&((recdata->context)[0])) __x = (recdata->
context); _ast_strlen_zero(__x, "app_voicemail.c", __PRETTY_FUNCTION__
, 6441) ? ("") : __x;})
,
6442 "macrocontext", S_OR(recdata->call_macrocontext, "")({typeof(&((recdata->call_macrocontext)[0])) __x = (recdata
->call_macrocontext); _ast_strlen_zero(__x, "app_voicemail.c"
, __PRETTY_FUNCTION__, 6442) ? ("") : __x;})
,
6443 "exten", S_OR(recdata->call_extension, "")({typeof(&((recdata->call_extension)[0])) __x = (recdata
->call_extension); _ast_strlen_zero(__x, "app_voicemail.c"
, __PRETTY_FUNCTION__, 6443) ? ("") : __x;})
,
6444 "priority", recdata->call_priority,
6445 "callerchan", S_OR(recdata->call_callerchan, "Unknown")({typeof(&((recdata->call_callerchan)[0])) __x = (recdata
->call_callerchan); _ast_strlen_zero(__x, "app_voicemail.c"
, __PRETTY_FUNCTION__, 6445) ? ("Unknown") : __x;})
,
6446 "callerid", S_OR(recdata->call_callerid, "Unknown")({typeof(&((recdata->call_callerid)[0])) __x = (recdata
->call_callerid); _ast_strlen_zero(__x, "app_voicemail.c",
__PRETTY_FUNCTION__, 6446) ? ("Unknown") : __x;})
,
6447 "origdate", date,
6448 "origtime", time(NULL((void*)0)),
6449 "category", S_OR(category, "")({typeof(&((category)[0])) __x = (category); _ast_strlen_zero
(__x, "app_voicemail.c", __PRETTY_FUNCTION__, 6449) ? ("") : __x
;})
,
6450 "filename", tmptxtfile,
6451 "duration", duration,
6452 SENTINEL((char *)((void*)0)));
6453 }
6454
6455 STORE(dir, recipient->mailbox, recipient->context, msgnum, NULL, recipient, fmt, 0, vms, "", msg_id);
6456 notify_new_state(recipient);
6457 }
6458
6459 free_user(recipient);
6460 unlink(tmptxtfile);
6461 return 0;
6462}
6463
6464/*!
6465 * \brief Prompts the user and records a voicemail to a mailbox.
6466 * \param chan
6467 * \param ext
6468 * \param options OPT_BUSY_GREETING, OPT_UNAVAIL_GREETING
6469 *
6470 *
6471 *
6472 * \return zero on success, -1 on error.
6473 */
6474static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
6475{
6476#ifdef IMAP_STORAGE
6477 int newmsgs, oldmsgs;
6478#else
6479 char urgdir[PATH_MAX4096];
6480#endif
6481 char txtfile[PATH_MAX4096];
6482 char tmptxtfile[PATH_MAX4096];
6483 struct vm_state *vms = NULL((void*)0);
6484 char callerid[256];
6485 FILE *txt;
6486 char date[256];
6487 int txtdes;
6488 int res = 0;
6489 int msgnum;
6490 int duration = 0;
6491 int sound_duration = 0;
6492 int ausemacro = 0;
6493 int ousemacro = 0;
6494 int ouseexten = 0;
6495 char tmpdur[16];
6496 char priority[16];
6497 char origtime[16];
6498 char dir[PATH_MAX4096];
6499 char tmpdir[PATH_MAX4096];
6500 char fn[PATH_MAX4096];
6501 char prefile[PATH_MAX4096] = "";
6502 char tempfile[PATH_MAX4096] = "";
6503 char ext_context[256] = "";
6504 char fmt[80];
6505 char *context;
6506 char ecodes[17] = "#";
6507 struct ast_str *tmp = ast_str_create(16);
6508 char *tmpptr;
6509 struct ast_vm_user *vmu;
6510 struct ast_vm_user svm;
6511 const char *category = NULL((void*)0);
6512 const char *code;
6513 const char *alldtmf = "0123456789ABCD*#";
6514 char flag[80];
6515
6516 if (!tmp) {
6517 return -1;
6518 }
6519
6520 ast_str_set(&tmp, 0, "%s", ext);
6521 ext = ast_str_buffer(tmp);
6522 if ((context = strchr(ext, '@')(__extension__ (__builtin_constant_p ('@') && !__builtin_constant_p
(ext) && ('@') == '\0' ? (char *) __rawmemchr (ext, '@'
) : __builtin_strchr (ext, '@')))
)) {
6523 *context++ = '\0';
6524 tmpptr = strchr(context, '&')(__extension__ (__builtin_constant_p ('&') && !__builtin_constant_p
(context) && ('&') == '\0' ? (char *) __rawmemchr
(context, '&') : __builtin_strchr (context, '&')))
;
6525 } else {
6526 tmpptr = strchr(ext, '&')(__extension__ (__builtin_constant_p ('&') && !__builtin_constant_p
(ext) && ('&') == '\0' ? (char *) __rawmemchr (ext
, '&') : __builtin_strchr (ext, '&')))
;
6527 }
6528
6529 if (tmpptr)
6530 *tmpptr++ = '\0';
6531
6532 ast_channel_lock(chan)__ao2_lock(chan, AO2_LOCK_REQ_MUTEX, "app_voicemail.c", __PRETTY_FUNCTION__
, 6532, "chan")
;
6533 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
6534 category = ast_strdupa(category)(__extension__ ({ const char *__old = (category); size_t __len
= strlen(__old) + 1; char *__new = __builtin_alloca(__len); memcpy
(__new, __old, __len); __new; }))
;
6535 }
6536 ast_channel_unlock(chan)__ao2_unlock(chan, "app_voicemail.c", __PRETTY_FUNCTION__, 6536
, "chan")
;
6537
6538 if (ast_test_flag(options, OPT_MESSAGE_Urgent)({ typeof ((options)->flags) __p = (options)->flags; typeof
(__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); ((options)->flags & (OPT_MESSAGE_Urgent)); })
) {
6539 ast_copy_string(flag, "Urgent", sizeof(flag));
6540 } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)({ typeof ((options)->flags) __p = (options)->flags; typeof
(__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); ((options)->flags & (OPT_MESSAGE_PRIORITY)); })
) {
6541 ast_copy_string(flag, "PRIORITY", sizeof(flag));
6542 } else {
6543 flag[0] = '\0';
6544 }
6545
6546 ast_debug(3, "Before find_user\n")do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 6546, __PRETTY_FUNCTION__, "Before find_user\n"
); } } while (0)
;
6547 memset(&svm, 0, sizeof(svm));
6548 if (!(vmu = find_user(&svm, context, ext))) {
6549 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 6549, __PRETTY_FUNCTION__, "No entry in voicemail config file for '%s'\n", ext);
6550 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
6551 ast_freefree(tmp);
6552 return res;
6553 }
6554 /* Setup pre-file if appropriate */
6555 if (strcmp(vmu->context, "default"))
6556 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
6557 else
6558 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
6559
6560 /* Set the path to the prefile. Will be one of
6561 VM_SPOOL_DIRcontext/ext/busy
6562 VM_SPOOL_DIRcontext/ext/unavail
6563 Depending on the flag set in options.
6564 */
6565 if (ast_test_flag(options, OPT_BUSY_GREETING)({ typeof ((options)->flags) __p = (options)->flags; typeof
(__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); ((options)->flags & (OPT_BUSY_GREETING)); })
) {
6566 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
6567 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)({ typeof ((options)->flags) __p = (options)->flags; typeof
(__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); ((options)->flags & (OPT_UNAVAIL_GREETING)); })
) {
6568 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
6569 }
6570 /* Set the path to the tmpfile as
6571 VM_SPOOL_DIR/context/ext/temp
6572 and attempt to create the folder structure.
6573 */
6574 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
6575 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
6576 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 6576, __PRETTY_FUNCTION__, "Failed to make directory (%s)\n", tempfile);
6577 free_user(vmu);
6578 ast_freefree(tmp);
6579 return -1;
6580 }
6581 RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
6582 if (ast_fileexists(tempfile, NULL((void*)0), NULL((void*)0)) > 0)
6583 ast_copy_string(prefile, tempfile, sizeof(prefile));
6584
6585 DISPOSE(tempfile, -1);
6586 /* It's easier just to try to make it than to check for its existence */
6587#ifndef IMAP_STORAGE
6588 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
6589#else
6590 snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
6591 if (mkdir(dir, VOICEMAIL_DIR_MODE0777) && errno(*__errno_location ()) != EEXIST17) {
6592 ast_log(LOG_WARNING3, "app_voicemail.c", 6592, __PRETTY_FUNCTION__, "mkdir '%s' failed: %s\n", dir, strerror(errno(*__errno_location ())));
6593 }
6594#endif
6595
6596 /* Check current or macro-calling context for special extensions */
6597 if (ast_test_flag(vmu, VM_OPERATOR)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 1))); })
) {
6598 if (!ast_strlen_zero(vmu->exit)_ast_strlen_zero(vmu->exit, "app_voicemail.c", __PRETTY_FUNCTION__
, 6598)
) {
6599 if (ast_exists_extension(chan, vmu->exit, "o", 1,
6600 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL)({typeof(&((ast_channel_caller(chan)->id.number.str)[0
])) __x = (ast_channel_caller(chan)->id.number.str); (ast_channel_caller
(chan)->id.number.valid) && !_ast_strlen_zero(__x,
"app_voicemail.c", __PRETTY_FUNCTION__, 6600) ? (__x) : (((void
*)0));})
)) {
6601 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1)__builtin_strncat (ecodes, "0", sizeof(ecodes) - strlen(ecodes
) - 1)
;
6602 ouseexten = 1;
6603 }
6604 } else if (ast_exists_extension(chan, ast_channel_context(chan), "o", 1,
6605 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL)({typeof(&((ast_channel_caller(chan)->id.number.str)[0
])) __x = (ast_channel_caller(chan)->id.number.str); (ast_channel_caller
(chan)->id.number.valid) && !_ast_strlen_zero(__x,
"app_voicemail.c", __PRETTY_FUNCTION__, 6605) ? (__x) : (((void
*)0));})
)) {
6606 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1)__builtin_strncat (ecodes, "0", sizeof(ecodes) - strlen(ecodes
) - 1)
;
6607 ouseexten = 1;
6608 } else if (!ast_strlen_zero(ast_channel_macrocontext(chan))_ast_strlen_zero(ast_channel_macrocontext(chan), "app_voicemail.c"
, __PRETTY_FUNCTION__, 6608)
6609 && ast_exists_extension(chan, ast_channel_macrocontext(chan), "o", 1,
6610 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL)({typeof(&((ast_channel_caller(chan)->id.number.str)[0
])) __x = (ast_channel_caller(chan)->id.number.str); (ast_channel_caller
(chan)->id.number.valid) && !_ast_strlen_zero(__x,
"app_voicemail.c", __PRETTY_FUNCTION__, 6610) ? (__x) : (((void
*)0));})
)) {
6611 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1)__builtin_strncat (ecodes, "0", sizeof(ecodes) - strlen(ecodes
) - 1)
;
6612 ousemacro = 1;
6613 }
6614 }
6615
6616 if (!ast_strlen_zero(vmu->exit)_ast_strlen_zero(vmu->exit, "app_voicemail.c", __PRETTY_FUNCTION__
, 6616)
) {
6617 if (ast_exists_extension(chan, vmu->exit, "a", 1,
6618 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL)({typeof(&((ast_channel_caller(chan)->id.number.str)[0
])) __x = (ast_channel_caller(chan)->id.number.str); (ast_channel_caller
(chan)->id.number.valid) && !_ast_strlen_zero(__x,
"app_voicemail.c", __PRETTY_FUNCTION__, 6618) ? (__x) : (((void
*)0));})
)) {
6619 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1)__builtin_strncat (ecodes, "*", sizeof(ecodes) - strlen(ecodes
) - 1)
;
6620 }
6621 } else if (ast_exists_extension(chan, ast_channel_context(chan), "a", 1,
6622 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL)({typeof(&((ast_channel_caller(chan)->id.number.str)[0
])) __x = (ast_channel_caller(chan)->id.number.str); (ast_channel_caller
(chan)->id.number.valid) && !_ast_strlen_zero(__x,
"app_voicemail.c", __PRETTY_FUNCTION__, 6622) ? (__x) : (((void
*)0));})
)) {
6623 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1)__builtin_strncat (ecodes, "*", sizeof(ecodes) - strlen(ecodes
) - 1)
;
6624 } else if (!ast_strlen_zero(ast_channel_macrocontext(chan))_ast_strlen_zero(ast_channel_macrocontext(chan), "app_voicemail.c"
, __PRETTY_FUNCTION__, 6624)
6625 && ast_exists_extension(chan, ast_channel_macrocontext(chan), "a", 1,
6626 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL)({typeof(&((ast_channel_caller(chan)->id.number.str)[0
])) __x = (ast_channel_caller(chan)->id.number.str); (ast_channel_caller
(chan)->id.number.valid) && !_ast_strlen_zero(__x,
"app_voicemail.c", __PRETTY_FUNCTION__, 6626) ? (__x) : (((void
*)0));})
)) {
6627 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1)__builtin_strncat (ecodes, "*", sizeof(ecodes) - strlen(ecodes
) - 1)
;
6628 ausemacro = 1;
6629 }
6630
6631 if (ast_test_flag(options, OPT_DTMFEXIT)({ typeof ((options)->flags) __p = (options)->flags; typeof
(__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); ((options)->flags & (OPT_DTMFEXIT)); })
) {
6632 for (code = alldtmf; *code; code++) {
6633 char e[2] = "";
6634 e[0] = *code;
6635 if (strchr(ecodes, e[0])(__extension__ (__builtin_constant_p (e[0]) && !__builtin_constant_p
(ecodes) && (e[0]) == '\0' ? (char *) __rawmemchr (ecodes
, e[0]) : __builtin_strchr (ecodes, e[0])))
== NULL((void*)0)
6636 && ast_canmatch_extension(chan,
6637 (!ast_strlen_zero(options->exitcontext)_ast_strlen_zero(options->exitcontext, "app_voicemail.c", __PRETTY_FUNCTION__
, 6637)
? options->exitcontext : ast_channel_context(chan)),
6638 e, 1, S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL)({typeof(&((ast_channel_caller(chan)->id.number.str)[0
])) __x = (ast_channel_caller(chan)->id.number.str); (ast_channel_caller
(chan)->id.number.valid) && !_ast_strlen_zero(__x,
"app_voicemail.c", __PRETTY_FUNCTION__, 6638) ? (__x) : (((void
*)0));})
)) {
6639 strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1)__builtin_strncat (ecodes, e, sizeof(ecodes) - strlen(ecodes)
- 1)
;
6640 }
6641 }
6642 }
6643
6644 /* Play the beginning intro if desired */
6645 if (!ast_strlen_zero(prefile)_ast_strlen_zero(prefile, "app_voicemail.c", __PRETTY_FUNCTION__
, 6645)
) {
6646#ifdef ODBC_STORAGE
6647 int success =
6648#endif
6649 RETRIEVE(prefile, -1, ext, context);
6650 if (ast_fileexists(prefile, NULL((void*)0), NULL((void*)0)) > 0) {
6651 if (ast_streamfile(chan, prefile, ast_channel_language(chan)) > -1)
6652 res = ast_waitstream(chan, ecodes);
6653#ifdef ODBC_STORAGE
6654 if (success == -1) {
6655 /* We couldn't retrieve the file from the database, but we found it on the file system. Let's put it in the database. */
6656 ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 6656, __PRETTY_FUNCTION__, "Greeting not retrieved from database, but found in file storage. Inserting into database\n"
); } } while (0)
;
6657 store_file(prefile, vmu->mailbox, vmu->context, -1);
6658 }
6659#endif
6660 } else {
6661 ast_debug(1, "%s doesn't exist, doing what we can\n", prefile)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 6661, __PRETTY_FUNCTION__, "%s doesn't exist, doing what we can\n"
, prefile); } } while (0)
;
6662 res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING)({ typeof ((options)->flags) __p = (options)->flags; typeof
(__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); ((options)->flags & (OPT_BUSY_GREETING)); })
, ecodes);
6663 }
6664 DISPOSE(prefile, -1);
6665 if (res < 0) {
6666 ast_debug(1, "Hang up during prefile playback\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 6666, __PRETTY_FUNCTION__, "Hang up during prefile playback\n"
); } } while (0)
;
6667 free_user(vmu);
6668 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
6669 ast_freefree(tmp);
6670 return -1;
6671 }
6672 }
6673 if (res == '#') {
6674 /* On a '#' we skip the instructions */
6675 ast_set_flag(options, OPT_SILENT)do { typeof ((options)->flags) __p = (options)->flags; typeof
(__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); ((options)->flags |= (OPT_SILENT)); } while(0)
;
6676 res = 0;
6677 }
6678 /* If maxmsg is zero, act as a "greetings only" voicemail: Exit successfully without recording */
6679 if (vmu->maxmsg == 0) {
6680 ast_debug(3, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n")do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 6680, __PRETTY_FUNCTION__, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n"
); } } while (0)
;
6681 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
6682 goto leave_vm_out;
6683 }
6684 if (!res && !ast_test_flag(options, OPT_SILENT)({ typeof ((options)->flags) __p = (options)->flags; typeof
(__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); ((options)->flags & (OPT_SILENT)); })
) {
6685 res = ast_stream_and_wait(chan, INTRO"vm-intro", ecodes);
6686 if (res == '#') {
6687 ast_set_flag(options, OPT_SILENT)do { typeof ((options)->flags) __p = (options)->flags; typeof
(__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); ((options)->flags |= (OPT_SILENT)); } while(0)
;
6688 res = 0;
6689 }
6690 }
6691 if (res > 0)
6692 ast_stopstream(chan);
6693 /* Check for a '*' here in case the caller wants to escape from voicemail to something
6694 other than the operator -- an automated attendant or mailbox login for example */
6695 if (res == '*') {
6696 ast_channel_exten_set(chan, "a");
6697 if (!ast_strlen_zero(vmu->exit)_ast_strlen_zero(vmu->exit, "app_voicemail.c", __PRETTY_FUNCTION__
, 6697)
) {
6698 ast_channel_context_set(chan, vmu->exit);
6699 } else if (ausemacro && !ast_strlen_zero(ast_channel_macrocontext(chan))_ast_strlen_zero(ast_channel_macrocontext(chan), "app_voicemail.c"
, __PRETTY_FUNCTION__, 6699)
) {
6700 ast_channel_context_set(chan, ast_channel_macrocontext(chan));
6701 }
6702 ast_channel_priority_set(chan, 0);
6703 free_user(vmu);
6704 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
6705 ast_freefree(tmp);
6706 return 0;
6707 }
6708
6709 /* Check for a '0' here */
6710 if (ast_test_flag(vmu, VM_OPERATOR)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 1))); })
&& res == '0') {
6711 transfer:
6712 if (ouseexten || ousemacro) {
6713 ast_channel_exten_set(chan, "o");
6714 if (!ast_strlen_zero(vmu->exit)_ast_strlen_zero(vmu->exit, "app_voicemail.c", __PRETTY_FUNCTION__
, 6714)
) {
6715 ast_channel_context_set(chan, vmu->exit);
6716 } else if (ousemacro && !ast_strlen_zero(ast_channel_macrocontext(chan))_ast_strlen_zero(ast_channel_macrocontext(chan), "app_voicemail.c"
, __PRETTY_FUNCTION__, 6716)
) {
6717 ast_channel_context_set(chan, ast_channel_macrocontext(chan));
6718 }
6719 ast_play_and_wait(chan, "transfer");
6720 ast_channel_priority_set(chan, 0);
6721 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
6722 }
6723 free_user(vmu);
6724 ast_freefree(tmp);
6725 return OPERATOR_EXIT300;
6726 }
6727
6728 /* Allow all other digits to exit Voicemail and return to the dialplan */
6729 if (ast_test_flag(options, OPT_DTMFEXIT)({ typeof ((options)->flags) __p = (options)->flags; typeof
(__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); ((options)->flags & (OPT_DTMFEXIT)); })
&& res > 0) {
6730 if (!ast_strlen_zero(options->exitcontext)_ast_strlen_zero(options->exitcontext, "app_voicemail.c", __PRETTY_FUNCTION__
, 6730)
) {
6731 ast_channel_context_set(chan, options->exitcontext);
6732 }
6733 free_user(vmu);
6734 ast_freefree(tmp);
6735 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
6736 return res;
6737 }
6738
6739 if (res < 0) {
6740 free_user(vmu);
6741 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
6742 ast_freefree(tmp);
6743 return -1;
6744 }
6745 /* The meat of recording the message... All the announcements and beeps have been played*/
6746 ast_copy_string(fmt, vmfmts, sizeof(fmt));
6747 if (!ast_strlen_zero(fmt)_ast_strlen_zero(fmt, "app_voicemail.c", __PRETTY_FUNCTION__,
6747)
) {
6748 char msg_id[MSG_ID_LEN256] = "";
6749 msgnum = 0;
6750
6751#ifdef IMAP_STORAGE
6752 /* Is ext a mailbox? */
6753 /* must open stream for this user to get info! */
6754 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
6755 if (res < 0) {
6756 ast_log(AST_LOG_NOTICE2, "app_voicemail.c", 6756, __PRETTY_FUNCTION__, "Can not leave voicemail, unable to count messages\n");
6757 free_user(vmu);
6758 ast_freefree(tmp);
6759 return -1;
6760 }
6761 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
6762 /* It is possible under certain circumstances that inboxcount did not
6763 * create a vm_state when it was needed. This is a catchall which will
6764 * rarely be used.
6765 */
6766 if (!(vms = create_vm_state_from_user(vmu))) {
6767 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 6767, __PRETTY_FUNCTION__, "Couldn't allocate necessary space\n");
6768 free_user(vmu);
6769 ast_freefree(tmp);
6770 return -1;
6771 }
6772 }
6773 vms->newmessages++;
6774
6775 /* here is a big difference! We add one to it later */
6776 msgnum = newmsgs + oldmsgs;
6777 ast_debug(3, "Messagecount set to %d\n", msgnum)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 6777, __PRETTY_FUNCTION__, "Messagecount set to %d\n"
, msgnum); } } while (0)
;
6778 snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
6779 /* set variable for compatibility */
6780 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
6781
6782 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
6783 goto leave_vm_out;
6784 }
6785#else
6786 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
6787 res = ast_streamfile(chan, "vm-mailboxfull", ast_channel_language(chan));
6788 if (!res)
6789 res = ast_waitstream(chan, "");
6790 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 6790, __PRETTY_FUNCTION__, "No more messages possible\n");
6791 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
6792 inprocess_count(vmu->mailbox, vmu->context, -1);
6793 goto leave_vm_out;
6794 }
6795
6796#endif
6797 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
6798 txtdes = mkstemp(tmptxtfile);
6799 chmod(tmptxtfile, VOICEMAIL_FILE_MODE0666 & ~my_umask);
6800 if (txtdes < 0) {
6801 res = ast_streamfile(chan, "vm-mailboxfull", ast_channel_language(chan));
6802 if (!res)
6803 res = ast_waitstream(chan, "");
6804 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 6804, __PRETTY_FUNCTION__, "Unable to create message file: %s\n", strerror(errno(*__errno_location ())));
6805 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
6806 inprocess_count(vmu->mailbox, vmu->context, -1);
6807 goto leave_vm_out;
6808 }
6809
6810 /* Now play the beep once we have the message number for our next message. */
6811 if (res >= 0) {
6812 /* Unless we're *really* silent, try to send the beep */
6813 res = ast_stream_and_wait(chan, "beep", "");
6814 }
6815
6816 /* Store information in real-time storage */
6817 if (ast_check_realtime("voicemail_data")) {
6818 snprintf(priority, sizeof(priority), "%d", ast_channel_priority(chan));
6819 snprintf(origtime, sizeof(origtime), "%ld", (long) time(NULL((void*)0)));
6820 get_date(date, sizeof(date));
6821 ast_callerid_merge(callerid, sizeof(callerid),
6822 S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL)({typeof(&((ast_channel_caller(chan)->id.name.str)[0])
) __x = (ast_channel_caller(chan)->id.name.str); (ast_channel_caller
(chan)->id.name.valid) && !_ast_strlen_zero(__x, "app_voicemail.c"
, __PRETTY_FUNCTION__, 6822) ? (__x) : (((void*)0));})
,
6823 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL)({typeof(&((ast_channel_caller(chan)->id.number.str)[0
])) __x = (ast_channel_caller(chan)->id.number.str); (ast_channel_caller
(chan)->id.number.valid) && !_ast_strlen_zero(__x,
"app_voicemail.c", __PRETTY_FUNCTION__, 6823) ? (__x) : (((void
*)0));})
,
6824 "Unknown");
6825 ast_store_realtime("voicemail_data",
6826 "origmailbox", ext,
6827 "context", ast_channel_context(chan),
6828 "macrocontext", ast_channel_macrocontext(chan),
6829 "exten", ast_channel_exten(chan),
6830 "priority", priority,
6831 "callerchan", ast_channel_name(chan),
6832 "callerid", callerid,
6833 "origdate", date,
6834 "origtime", origtime,
6835 "category", S_OR(category, "")({typeof(&((category)[0])) __x = (category); _ast_strlen_zero
(__x, "app_voicemail.c", __PRETTY_FUNCTION__, 6835) ? ("") : __x
;})
,
6836 "filename", tmptxtfile,
6837 SENTINEL((char *)((void*)0)));
6838 }
6839
6840 /* Store information */
6841 txt = fdopen(txtdes, "w+");
6842 if (txt) {
6843 generate_msg_id(msg_id);
6844 get_date(date, sizeof(date));
6845 ast_callerid_merge(callerid, sizeof(callerid),
6846 S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL)({typeof(&((ast_channel_caller(chan)->id.name.str)[0])
) __x = (ast_channel_caller(chan)->id.name.str); (ast_channel_caller
(chan)->id.name.valid) && !_ast_strlen_zero(__x, "app_voicemail.c"
, __PRETTY_FUNCTION__, 6846) ? (__x) : (((void*)0));})
,
6847 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL)({typeof(&((ast_channel_caller(chan)->id.number.str)[0
])) __x = (ast_channel_caller(chan)->id.number.str); (ast_channel_caller
(chan)->id.number.valid) && !_ast_strlen_zero(__x,
"app_voicemail.c", __PRETTY_FUNCTION__, 6847) ? (__x) : (((void
*)0));})
,
6848 "Unknown");
6849 fprintf(txt,
6850 ";\n"
6851 "; Message Information file\n"
6852 ";\n"
6853 "[message]\n"
6854 "origmailbox=%s\n"
6855 "context=%s\n"
6856 "macrocontext=%s\n"
6857 "exten=%s\n"
6858 "rdnis=%s\n"
6859 "priority=%d\n"
6860 "callerchan=%s\n"
6861 "callerid=%s\n"
6862 "origdate=%s\n"
6863 "origtime=%ld\n"
6864 "category=%s\n"
6865 "msg_id=%s\n",
6866 ext,
6867 ast_channel_context(chan),
6868 ast_channel_macrocontext(chan),
6869 ast_channel_exten(chan),
6870 S_COR(ast_channel_redirecting(chan)->from.number.valid,({typeof(&((ast_channel_redirecting(chan)->from.number
.str)[0])) __x = (ast_channel_redirecting(chan)->from.number
.str); (ast_channel_redirecting(chan)->from.number.valid) &&
!_ast_strlen_zero(__x, "app_voicemail.c", __PRETTY_FUNCTION__
, 6871) ? (__x) : ("unknown");})
6871 ast_channel_redirecting(chan)->from.number.str, "unknown")({typeof(&((ast_channel_redirecting(chan)->from.number
.str)[0])) __x = (ast_channel_redirecting(chan)->from.number
.str); (ast_channel_redirecting(chan)->from.number.valid) &&
!_ast_strlen_zero(__x, "app_voicemail.c", __PRETTY_FUNCTION__
, 6871) ? (__x) : ("unknown");})
,
6872 ast_channel_priority(chan),
6873 ast_channel_name(chan),
6874 callerid,
6875 date, (long) time(NULL((void*)0)),
6876 category ? category : "",
6877 msg_id);
6878 } else {
6879 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 6879, __PRETTY_FUNCTION__, "Error opening text file for output\n");
6880 inprocess_count(vmu->mailbox, vmu->context, -1);
6881 if (ast_check_realtime("voicemail_data")) {
6882 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL((char *)((void*)0)));
6883 }
6884 res = ast_streamfile(chan, "vm-mailboxfull", ast_channel_language(chan));
6885 goto leave_vm_out;
6886 }
6887 res = play_record_review(chan, NULL((void*)0), tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, &sound_duration, NULL((void*)0), options->record_gain, vms, flag, msg_id, 0);
6888
6889 if (txt) {
6890 fprintf(txt, "flag=%s\n", flag);
6891 if (sound_duration < vmu->minsecs) {
6892 fclose(txt);
6893 ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", sound_duration, vmu->minsecs)do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 6893, __PRETTY_FUNCTION__, 3, "Recording was %d seconds long but needs to be at least %d - abandoning\n"
, sound_duration, vmu->minsecs); } } while (0)
;
6894 ast_filedelete(tmptxtfile, NULL((void*)0));
6895 unlink(tmptxtfile);
6896 if (ast_check_realtime("voicemail_data")) {
6897 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL((char *)((void*)0)));
6898 }
6899 inprocess_count(vmu->mailbox, vmu->context, -1);
6900 } else {
6901 fprintf(txt, "duration=%d\n", duration);
6902 fclose(txt);
6903 if (vm_lock_path(dir)) {
6904 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 6904, __PRETTY_FUNCTION__, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
6905 /* Delete files */
6906 ast_filedelete(tmptxtfile, NULL((void*)0));
6907 unlink(tmptxtfile);
6908 inprocess_count(vmu->mailbox, vmu->context, -1);
6909 } else if (ast_fileexists(tmptxtfile, NULL((void*)0), NULL((void*)0)) <= 0) {
6910 ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 6910, __PRETTY_FUNCTION__, "The recorded media file is gone, so we should remove the .txt file too!\n"
); } } while (0)
;
6911 unlink(tmptxtfile);
6912 ast_unlock_path(dir);
6913 inprocess_count(vmu->mailbox, vmu->context, -1);
6914 if (ast_check_realtime("voicemail_data")) {
6915 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL((char *)((void*)0)));
6916 }
6917 } else {
6918#ifndef IMAP_STORAGE
6919 msgnum = last_message_index(vmu, dir) + 1;
6920#endif
6921 make_file(fn, sizeof(fn), dir, msgnum);
6922
6923 /* assign a variable with the name of the voicemail file */
6924#ifndef IMAP_STORAGE
6925 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
6926#else
6927 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
6928#endif
6929
6930 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
6931 ast_filerename(tmptxtfile, fn, NULL((void*)0));
6932 rename(tmptxtfile, txtfile);
6933 inprocess_count(vmu->mailbox, vmu->context, -1);
6934
6935 /* Properly set permissions on voicemail text descriptor file.
6936 Unfortunately mkstemp() makes this file 0600 on most unix systems. */
6937 if (chmod(txtfile, VOICEMAIL_FILE_MODE0666) < 0)
6938 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 6938, __PRETTY_FUNCTION__, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno(*__errno_location ())));
6939
6940 ast_unlock_path(dir);
6941 if (ast_check_realtime("voicemail_data")) {
6942 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
6943 ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL((char *)((void*)0)));
6944 }
6945 /* We must store the file first, before copying the message, because
6946 * ODBC storage does the entire copy with SQL.
6947 */
6948 if (ast_fileexists(fn, NULL((void*)0), NULL((void*)0)) > 0) {
6949 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag, msg_id);
6950 }
6951
6952 /* Are there to be more recipients of this message? */
6953 while (tmpptr) {
6954 struct ast_vm_user recipu, *recip;
6955 char *exten, *cntx;
6956
6957 exten = strsep(&tmpptr, "&");
6958 cntx = strchr(exten, '@')(__extension__ (__builtin_constant_p ('@') && !__builtin_constant_p
(exten) && ('@') == '\0' ? (char *) __rawmemchr (exten
, '@') : __builtin_strchr (exten, '@')))
;
6959 if (cntx) {
6960 *cntx = '\0';
6961 cntx++;
6962 }
6963 memset(&recipu, 0, sizeof(recipu));
6964 if ((recip = find_user(&recipu, cntx, exten))) {
6965 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag, NULL((void*)0));
6966 free_user(recip);
6967 }
6968 }
6969#ifndef IMAP_STORAGE
6970 if (!ast_strlen_zero(flag)_ast_strlen_zero(flag, "app_voicemail.c", __PRETTY_FUNCTION__
, 6970)
&& !strcmp(flag, "Urgent")) { /* If this is an Urgent message */
6971 /* Move the message from INBOX to Urgent folder if this is urgent! */
6972 char sfn[PATH_MAX4096];
6973 char dfn[PATH_MAX4096];
6974 int x;
6975 /* It's easier just to try to make it than to check for its existence */
6976 create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
6977 x = last_message_index(vmu, urgdir) + 1;
6978 make_file(sfn, sizeof(sfn), dir, msgnum);
6979 make_file(dfn, sizeof(dfn), urgdir, x);
6980 ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n", sfn, dfn)do { if ((option_debug >= (5) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (5)))) { ast_log
(0, "app_voicemail.c", 6980, __PRETTY_FUNCTION__, "Created an Urgent message, moving file from %s to %s.\n"
, sfn, dfn); } } while (0)
;
6981 RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn)(rename_file(sfn,dfn));;
6982 /* Notification must happen for this new message in Urgent folder, not INBOX */
6983 ast_copy_string(fn, dfn, sizeof(fn));
6984 msgnum = x;
6985 }
6986#endif
6987 /* Notification needs to happen after the copy, though. */
6988 if (ast_fileexists(fn, NULL((void*)0), NULL((void*)0))) {
6989#ifdef IMAP_STORAGE
6990 notify_new_message(chan, vmu, vms, msgnum, duration, fmt,
6991 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL)({typeof(&((ast_channel_caller(chan)->id.number.str)[0
])) __x = (ast_channel_caller(chan)->id.number.str); (ast_channel_caller
(chan)->id.number.valid) && !_ast_strlen_zero(__x,
"app_voicemail.c", __PRETTY_FUNCTION__, 6991) ? (__x) : (((void
*)0));})
,
6992 S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL)({typeof(&((ast_channel_caller(chan)->id.name.str)[0])
) __x = (ast_channel_caller(chan)->id.name.str); (ast_channel_caller
(chan)->id.name.valid) && !_ast_strlen_zero(__x, "app_voicemail.c"
, __PRETTY_FUNCTION__, 6992) ? (__x) : (((void*)0));})
,
6993 flag);
6994#else
6995 notify_new_message(chan, vmu, NULL((void*)0), msgnum, duration, fmt,
6996 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL)({typeof(&((ast_channel_caller(chan)->id.number.str)[0
])) __x = (ast_channel_caller(chan)->id.number.str); (ast_channel_caller
(chan)->id.number.valid) && !_ast_strlen_zero(__x,
"app_voicemail.c", __PRETTY_FUNCTION__, 6996) ? (__x) : (((void
*)0));})
,
6997 S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL)({typeof(&((ast_channel_caller(chan)->id.name.str)[0])
) __x = (ast_channel_caller(chan)->id.name.str); (ast_channel_caller
(chan)->id.name.valid) && !_ast_strlen_zero(__x, "app_voicemail.c"
, __PRETTY_FUNCTION__, 6997) ? (__x) : (((void*)0));})
,
6998 flag);
6999#endif
7000 }
7001
7002 /* Disposal needs to happen after the optional move and copy */
7003 if (ast_fileexists(fn, NULL((void*)0), NULL((void*)0))) {
7004 DISPOSE(dir, msgnum);
7005 }
7006 }
7007 }
7008 } else {
7009 inprocess_count(vmu->mailbox, vmu->context, -1);
7010 }
7011 if (res == '0') {
7012 goto transfer;
7013 } else if (res > 0 && res != 't')
7014 res = 0;
7015
7016 if (sound_duration < vmu->minsecs)
7017 /* XXX We should really give a prompt too short/option start again, with leave_vm_out called only after a timeout XXX */
7018 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
7019 else
7020 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
7021 } else
7022 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 7022, __PRETTY_FUNCTION__, "No format for saving voicemail?\n");
7023leave_vm_out:
7024 free_user(vmu);
7025
7026#ifdef IMAP_STORAGE
7027 /* expunge message - use UID Expunge if supported on IMAP server*/
7028 ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 7028, __PRETTY_FUNCTION__, "*** Checking if we can expunge, expungeonhangup set to %d\n"
, expungeonhangup); } } while (0)
;
7029 if (expungeonhangup == 1) {
7030 ast_mutex_lock(&vms->lock)__ast_pthread_mutex_lock("app_voicemail.c", 7030, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
7031#ifdef HAVE_IMAP_TK2006
7032 if (LEVELUIDPLUS (vms->mailstream)) {
7033 mail_expunge_full(vms->mailstream, NIL, EX_UID);
7034 } else
7035#endif
7036 mail_expunge(vms->mailstream);
7037 ast_mutex_unlock(&vms->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 7037, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
7038 }
7039#endif
7040
7041 ast_freefree(tmp);
7042 return res;
7043}
7044
7045#if !defined(IMAP_STORAGE)
7046static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount)
7047{
7048 /* we know the actual number of messages, so stop process when number is hit */
7049
7050 int x, dest;
7051 char sfn[PATH_MAX4096];
7052 char dfn[PATH_MAX4096];
7053
7054 if (vm_lock_path(dir)) {
7055 return ERROR_LOCK_PATH-100;
7056 }
7057
7058 for (x = 0, dest = 0; dest != stopcount && x < vmu->maxmsg + 10; x++) {
7059 make_file(sfn, sizeof(sfn), dir, x);
7060 if (EXISTS(dir, x, sfn, NULL)(ast_fileexists(sfn,((void*)0),((void*)0)) > 0)) {
7061
7062 if (x != dest) {
7063 make_file(dfn, sizeof(dfn), dir, dest);
7064 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn)(rename_file(sfn,dfn));;
7065 }
7066
7067 dest++;
7068 }
7069 }
7070 ast_unlock_path(dir);
7071
7072 return dest;
7073}
7074#endif
7075
7076static int say_and_wait(struct ast_channel *chan, int num, const char *language)
7077{
7078 int d;
7079 d = ast_say_number(chan, num, AST_DIGIT_ANY"0123456789#*ABCD", language, NULL((void*)0));
7080 return d;
7081}
7082
7083static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box, int *newmsg, int move)
7084{
7085#ifdef IMAP_STORAGE
7086 /* we must use mbox(x) folder names, and copy the message there */
7087 /* simple. huh? */
7088 char sequence[10];
7089 char mailbox[256];
7090 int res;
7091 int curr_mbox;
7092
7093 /* get the real IMAP message number for this message */
7094 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
7095
7096 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(vmu, box))do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 7096, __PRETTY_FUNCTION__, "Copying sequence %s to mailbox %s\n"
, sequence, mbox(vmu, box)); } } while (0)
;
7097 ast_mutex_lock(&vms->lock)__ast_pthread_mutex_lock("app_voicemail.c", 7097, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
7098 /* if save to Old folder, put in INBOX as read */
7099 if (box == OLD_FOLDER) {
7100 mail_setflag(vms->mailstream, sequence, "\\Seen");
7101 } else if (box == NEW_FOLDER) {
7102 mail_clearflag(vms->mailstream, sequence, "\\Seen");
7103 }
7104 if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
7105 ast_mutex_unlock(&vms->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 7105, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
7106 return 0;
7107 }
7108
7109 /* get the current mailbox so that we can point the mailstream back to it later */
7110 curr_mbox = get_folder_by_name(vms->curbox);
7111
7112 /* Create the folder if it dosn't exist */
7113 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1); /* Get the full mailbox name */
7114 if (vms->mailstream && !mail_status(vms->mailstream, mailbox, SA_UIDNEXT)) {
7115 if (mail_create(vms->mailstream, mailbox) != NIL) {
7116 ast_log(AST_LOG_NOTICE2, "app_voicemail.c", 7116, __PRETTY_FUNCTION__, "Folder %s created!\n", mbox(vmu, box));
7117 }
7118 }
7119
7120 /* restore previous mbox stream */
7121 if (init_mailstream(vms, curr_mbox) || !vms->mailstream) {
7122 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 7122, __PRETTY_FUNCTION__, "IMAP mailstream is NULL or can't init_mailstream\n");
7123 res = -1;
7124 } else {
7125 if (move) {
7126 res = !mail_move(vms->mailstream, sequence, (char *) mbox(vmu, box));
7127 } else {
7128 res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box));
7129 }
7130 }
7131 ast_mutex_unlock(&vms->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 7131, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
7132 return res;
7133#else
7134 char *dir = vms->curdir;
7135 char *username = vms->username;
7136 char *context = vmu->context;
7137 char sfn[PATH_MAX4096];
7138 char dfn[PATH_MAX4096];
7139 char ddir[PATH_MAX4096];
7140 const char *dbox = mbox(vmu, box);
7141 int x, i;
7142 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
7143
7144 if (vm_lock_path(ddir))
7145 return ERROR_LOCK_PATH-100;
7146
7147 x = last_message_index(vmu, ddir) + 1;
7148
7149 if (box == 10 && x >= vmu->maxdeletedmsg) { /* "Deleted" folder*/
7150 x--;
7151 for (i = 1; i <= x; i++) {
7152 /* Push files down a "slot". The oldest file (msg0000) will be deleted. */
7153 make_file(sfn, sizeof(sfn), ddir, i);
7154 make_file(dfn, sizeof(dfn), ddir, i - 1);
7155 if (EXISTS(ddir, i, sfn, NULL)(ast_fileexists(sfn,((void*)0),((void*)0)) > 0)) {
7156 RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn)(rename_file(sfn,dfn));;
7157 } else
7158 break;
7159 }
7160 } else {
7161 if (x >= vmu->maxmsg) {
7162 ast_unlock_path(ddir);
7163 return ERROR_MAX_MSGS-101;
7164 }
7165 }
7166 make_file(sfn, sizeof(sfn), dir, msg);
7167 make_file(dfn, sizeof(dfn), ddir, x);
7168 if (strcmp(sfn, dfn)) {
7169 COPY(dir, msg, ddir, x, username, context, sfn, dfn)(copy_plain_file(sfn,dfn));;
7170 }
7171 ast_unlock_path(ddir);
7172
7173 if (newmsg) {
7174 *newmsg = x;
7175 }
7176 return 0;
7177#endif
7178}
7179
7180static int adsi_logo(unsigned char *buf)
7181{
7182 int bytes = 0;
7183 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 1, ADSI_JUST_CENT0x0, 0, "Comedian Mail", "");
7184 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 2, ADSI_JUST_CENT0x0, 0, "(C)2002-2006 Digium, Inc.", "");
7185 return bytes;
7186}
7187
7188static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
7189{
7190 unsigned char buf[256];
7191 int bytes = 0;
7192 int x;
7193 char num[5];
7194
7195 *useadsi = 0;
7196 bytes += ast_adsi_data_mode(buf + bytes);
7197 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY132);
7198
7199 bytes = 0;
7200 bytes += adsi_logo(buf);
7201 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 3, ADSI_JUST_CENT0x0, 0, "Downloading Scripts", "");
7202#ifdef DISPLAY
7203 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 4, ADSI_JUST_LEFT0x2, 0, " .", "");
7204#endif
7205 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE0x1, 1);
7206 bytes += ast_adsi_data_mode(buf + bytes);
7207 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY132);
7208
7209 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
7210 bytes = 0;
7211 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 3, ADSI_JUST_CENT0x0, 0, "Load Cancelled.", "");
7212 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 4, ADSI_JUST_CENT0x0, 0, "ADSI Unavailable", "");
7213 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE0x1, 1);
7214 bytes += ast_adsi_voice_mode(buf + bytes, 0);
7215 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY132);
7216 return 0;
7217 }
7218
7219#ifdef DISPLAY
7220 /* Add a dot */
7221 bytes = 0;
7222 bytes += ast_adsi_logo(buf);
7223 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 3, ADSI_JUST_CENT0x0, 0, "Downloading Scripts", "");
7224 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 4, ADSI_JUST_LEFT0x2, 0, " ..", "");
7225 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE0x1, 1);
7226 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY132);
7227#endif
7228 bytes = 0;
7229 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS16 + 0, "Listen", "Listen", "1", 1);
7230 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS16 + 1, "Folder", "Folder", "2", 1);
7231 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS16 + 2, "Advanced", "Advnced", "3", 1);
7232 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS16 + 3, "Options", "Options", "0", 1);
7233 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS16 + 4, "Help", "Help", "*", 1);
7234 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS16 + 5, "Exit", "Exit", "#", 1);
7235 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD133);
7236
7237#ifdef DISPLAY
7238 /* Add another dot */
7239 bytes = 0;
7240 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 4, ADSI_JUST_LEFT0x2, 0, " ...", "");
7241 bytes += ast_adsi_voice_mode(buf + bytes, 0);
7242
7243 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE0x1, 1);
7244 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY132);
7245#endif
7246
7247 bytes = 0;
7248 /* These buttons we load but don't use yet */
7249 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS16 + 6, "Previous", "Prev", "4", 1);
7250 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS16 + 8, "Repeat", "Repeat", "5", 1);
7251 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS16 + 7, "Delete", "Delete", "7", 1);
7252 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS16 + 9, "Next", "Next", "6", 1);
7253 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS16 + 10, "Save", "Save", "9", 1);
7254 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS16 + 11, "Undelete", "Restore", "7", 1);
7255 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD133);
7256
7257#ifdef DISPLAY
7258 /* Add another dot */
7259 bytes = 0;
7260 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 4, ADSI_JUST_LEFT0x2, 0, " ....", "");
7261 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE0x1, 1);
7262 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY132);
7263#endif
7264
7265 bytes = 0;
7266 for (x = 0; x < 5; x++) {
7267 snprintf(num, sizeof(num), "%d", x);
7268 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS16 + 12 + x, mbox(NULL((void*)0), x), mbox(NULL((void*)0), x), num, 1);
7269 }
7270 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS16 + 12 + 5, "Cancel", "Cancel", "#", 1);
7271 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD133);
7272
7273#ifdef DISPLAY
7274 /* Add another dot */
7275 bytes = 0;
7276 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 4, ADSI_JUST_LEFT0x2, 0, " .....", "");
7277 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE0x1, 1);
7278 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY132);
7279#endif
7280
7281 if (ast_adsi_end_download(chan)) {
7282 bytes = 0;
7283 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 3, ADSI_JUST_CENT0x0, 0, "Download Unsuccessful.", "");
7284 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 4, ADSI_JUST_CENT0x0, 0, "ADSI Unavailable", "");
7285 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE0x1, 1);
7286 bytes += ast_adsi_voice_mode(buf + bytes, 0);
7287 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY132);
7288 return 0;
7289 }
7290 bytes = 0;
7291 bytes += ast_adsi_download_disconnect(buf + bytes);
7292 bytes += ast_adsi_voice_mode(buf + bytes, 0);
7293 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD133);
7294
7295 ast_debug(1, "Done downloading scripts...\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 7295, __PRETTY_FUNCTION__, "Done downloading scripts...\n"
); } } while (0)
;
7296
7297#ifdef DISPLAY
7298 /* Add last dot */
7299 bytes = 0;
7300 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 4, ADSI_JUST_CENT0x0, 0, " ......", "");
7301 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE0x1, 1);
7302#endif
7303 ast_debug(1, "Restarting session...\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 7303, __PRETTY_FUNCTION__, "Restarting session...\n"
); } } while (0)
;
7304
7305 bytes = 0;
7306 /* Load the session now */
7307 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
7308 *useadsi = 1;
7309 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 3, ADSI_JUST_CENT0x0, 0, "Scripts Loaded!", "");
7310 } else
7311 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 3, ADSI_JUST_CENT0x0, 0, "Load Failed!", "");
7312
7313 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY132);
7314 return 0;
7315}
7316
7317static void adsi_begin(struct ast_channel *chan, int *useadsi)
7318{
7319 int x;
7320 if (!ast_adsi_available(chan))
7321 return;
7322 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
7323 if (x < 0)
7324 return;
7325 if (!x) {
7326 if (adsi_load_vmail(chan, useadsi)) {
7327 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 7327, __PRETTY_FUNCTION__, "Unable to upload voicemail scripts\n");
7328 return;
7329 }
7330 } else
7331 *useadsi = 1;
7332}
7333
7334static void adsi_login(struct ast_channel *chan)
7335{
7336 unsigned char buf[256];
7337 int bytes = 0;
7338 unsigned char keys[8];
7339 int x;
7340 if (!ast_adsi_available(chan))
7341 return;
7342
7343 for (x = 0; x < 8; x++)
7344 keys[x] = 0;
7345 /* Set one key for next */
7346 keys[3] = ADSI_KEY_APPS16 + 3;
7347
7348 bytes += adsi_logo(buf + bytes);
7349 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 3, ADSI_JUST_CENT0x0, 0, " ", "");
7350 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 4, ADSI_JUST_CENT0x0, 0, " ", "");
7351 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE0x1, 1);
7352 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT(0), 0, "Mailbox: ******", "");
7353 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE0x1, 4, 1, 1, ADSI_JUST_LEFT0x2);
7354 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS16 + 3, "Enter", "Enter", "#", 1);
7355 bytes += ast_adsi_set_keys(buf + bytes, keys);
7356 bytes += ast_adsi_voice_mode(buf + bytes, 0);
7357 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY132);
7358}
7359
7360static void adsi_password(struct ast_channel *chan)
7361{
7362 unsigned char buf[256];
7363 int bytes = 0;
7364 unsigned char keys[8];
7365 int x;
7366 if (!ast_adsi_available(chan))
7367 return;
7368
7369 for (x = 0; x < 8; x++)
7370 keys[x] = 0;
7371 /* Set one key for next */
7372 keys[3] = ADSI_KEY_APPS16 + 3;
7373
7374 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE0x1, 1);
7375 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT(0), 0, "Password: ******", "");
7376 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE0x1, 4, 0, 1, ADSI_JUST_LEFT0x2);
7377 bytes += ast_adsi_set_keys(buf + bytes, keys);
7378 bytes += ast_adsi_voice_mode(buf + bytes, 0);
7379 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY132);
7380}
7381
7382static void adsi_folders(struct ast_channel *chan, int start, char *label)
7383{
7384 unsigned char buf[256];
7385 int bytes = 0;
7386 unsigned char keys[8];
7387 int x, y;
7388
7389 if (!ast_adsi_available(chan))
7390 return;
7391
7392 for (x = 0; x < 5; x++) {
7393 y = ADSI_KEY_APPS16 + 12 + start + x;
7394 if (y > ADSI_KEY_APPS16 + 12 + 4)
7395 y = 0;
7396 keys[x] = ADSI_KEY_SKT0x80 | y;
7397 }
7398 keys[5] = ADSI_KEY_SKT0x80 | (ADSI_KEY_APPS16 + 17);
7399 keys[6] = 0;
7400 keys[7] = 0;
7401
7402 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 1, ADSI_JUST_CENT0x0, 0, label, "");
7403 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 2, ADSI_JUST_CENT0x0, 0, " ", "");
7404 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE0x1, 1);
7405 bytes += ast_adsi_set_keys(buf + bytes, keys);
7406 bytes += ast_adsi_voice_mode(buf + bytes, 0);
7407
7408 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY132);
7409}
7410
7411static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
7412{
7413 int bytes = 0;
7414 unsigned char buf[256];
7415 char buf1[256], buf2[256];
7416 char fn2[PATH_MAX4096];
7417
7418 char cid[256] = "";
7419 char *val;
7420 char *name, *num;
7421 char datetime[21] = "";
7422 FILE *f;
7423
7424 unsigned char keys[8];
7425
7426 int x;
7427
7428 if (!ast_adsi_available(chan))
7429 return;
7430
7431 /* Retrieve important info */
7432 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
7433 f = fopen(fn2, "r");
7434 if (f) {
7435 while (!feof(f)) {
7436 if (!fgets((char *) buf, sizeof(buf), f)) {
7437 continue;
7438 }
7439 if (!feof(f)) {
7440 char *stringp = NULL((void*)0);
7441 stringp = (char *) buf;
7442 strsep(&stringp, "=");
7443 val = strsep(&stringp, "=");
7444 if (!ast_strlen_zero(val)_ast_strlen_zero(val, "app_voicemail.c", __PRETTY_FUNCTION__,
7444)
) {
7445 if (!strcmp((char *) buf, "callerid"))
7446 ast_copy_string(cid, val, sizeof(cid));
7447 if (!strcmp((char *) buf, "origdate"))
7448 ast_copy_string(datetime, val, sizeof(datetime));
7449 }
7450 }
7451 }
7452 fclose(f);
7453 }
7454 /* New meaning for keys */
7455 for (x = 0; x < 5; x++)
7456 keys[x] = ADSI_KEY_SKT0x80 | (ADSI_KEY_APPS16 + 6 + x);
7457 keys[6] = 0x0;
7458 keys[7] = 0x0;
7459
7460 if (!vms->curmsg) {
7461 /* No prev key, provide "Folder" instead */
7462 keys[0] = ADSI_KEY_SKT0x80 | (ADSI_KEY_APPS16 + 1);
7463 }
7464 if (vms->curmsg >= vms->lastmsg) {
7465 /* If last message ... */
7466 if (vms->curmsg) {
7467 /* but not only message, provide "Folder" instead */
7468 keys[3] = ADSI_KEY_SKT0x80 | (ADSI_KEY_APPS16 + 1);
7469 bytes += ast_adsi_voice_mode(buf + bytes, 0);
7470
7471 } else {
7472 /* Otherwise if only message, leave blank */
7473 keys[3] = 1;
7474 }
7475 }
7476
7477 if (!ast_strlen_zero(cid)_ast_strlen_zero(cid, "app_voicemail.c", __PRETTY_FUNCTION__,
7477)
) {
7478 ast_callerid_parse(cid, &name, &num);
7479 if (!name)
7480 name = num;
7481 } else {
7482 name = "Unknown Caller";
7483 }
7484
7485 /* If deleted, show "undeleted" */
7486#ifdef IMAP_STORAGE
7487 ast_mutex_lock(&vms->lock)__ast_pthread_mutex_lock("app_voicemail.c", 7487, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
7488#endif
7489 if (vms->deleted[vms->curmsg]) {
7490 keys[1] = ADSI_KEY_SKT0x80 | (ADSI_KEY_APPS16 + 11);
7491 }
7492#ifdef IMAP_STORAGE
7493 ast_mutex_unlock(&vms->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 7493, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
7494#endif
7495
7496 /* Except "Exit" */
7497 keys[5] = ADSI_KEY_SKT0x80 | (ADSI_KEY_APPS16 + 5);
7498 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
7499 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
7500 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
7501
7502 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 1, ADSI_JUST_LEFT0x2, 0, buf1, "");
7503 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 2, ADSI_JUST_LEFT0x2, 0, buf2, "");
7504 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 3, ADSI_JUST_LEFT0x2, 0, name, "");
7505 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 4, ADSI_JUST_LEFT0x2, 0, datetime, "");
7506 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE0x1, 1);
7507 bytes += ast_adsi_set_keys(buf + bytes, keys);
7508 bytes += ast_adsi_voice_mode(buf + bytes, 0);
7509
7510 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY132);
7511}
7512
7513static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
7514{
7515 int bytes = 0;
7516 unsigned char buf[256];
7517 unsigned char keys[8];
7518
7519 int x;
7520
7521 if (!ast_adsi_available(chan))
7522 return;
7523
7524 /* New meaning for keys */
7525 for (x = 0; x < 5; x++)
7526 keys[x] = ADSI_KEY_SKT0x80 | (ADSI_KEY_APPS16 + 6 + x);
7527
7528 keys[6] = 0x0;
7529 keys[7] = 0x0;
7530
7531 if (!vms->curmsg) {
7532 /* No prev key, provide "Folder" instead */
7533 keys[0] = ADSI_KEY_SKT0x80 | (ADSI_KEY_APPS16 + 1);
7534 }
7535 if (vms->curmsg >= vms->lastmsg) {
7536 /* If last message ... */
7537 if (vms->curmsg) {
7538 /* but not only message, provide "Folder" instead */
7539 keys[3] = ADSI_KEY_SKT0x80 | (ADSI_KEY_APPS16 + 1);
7540 } else {
7541 /* Otherwise if only message, leave blank */
7542 keys[3] = 1;
7543 }
7544 }
7545
7546 /* If deleted, show "undeleted" */
7547#ifdef IMAP_STORAGE
7548 ast_mutex_lock(&vms->lock)__ast_pthread_mutex_lock("app_voicemail.c", 7548, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
7549#endif
7550 if (vms->deleted[vms->curmsg]) {
7551 keys[1] = ADSI_KEY_SKT0x80 | (ADSI_KEY_APPS16 + 11);
7552 }
7553#ifdef IMAP_STORAGE
7554 ast_mutex_unlock(&vms->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 7554, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
7555#endif
7556
7557 /* Except "Exit" */
7558 keys[5] = ADSI_KEY_SKT0x80 | (ADSI_KEY_APPS16 + 5);
7559 bytes += ast_adsi_set_keys(buf + bytes, keys);
7560 bytes += ast_adsi_voice_mode(buf + bytes, 0);
7561
7562 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY132);
7563}
7564
7565static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
7566{
7567 unsigned char buf[256] = "";
7568 char buf1[256] = "", buf2[256] = "";
7569 int bytes = 0;
7570 unsigned char keys[8];
7571 int x;
7572
7573 char *newm = (vms->newmessages == 1) ? "message" : "messages";
7574 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
7575 if (!ast_adsi_available(chan))
7576 return;
7577 if (vms->newmessages) {
7578 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
7579 if (vms->oldmessages) {
7580 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1)__builtin_strncat (buf1, " and", sizeof(buf1) - strlen(buf1) -
1)
;
7581 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
7582 } else {
7583 snprintf(buf2, sizeof(buf2), "%s.", newm);
7584 }
7585 } else if (vms->oldmessages) {
7586 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
7587 snprintf(buf2, sizeof(buf2), "%s.", oldm);
7588 } else {
7589 strcpy(buf1, "You have no messages.");
7590 buf2[0] = ' ';
7591 buf2[1] = '\0';
7592 }
7593 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 1, ADSI_JUST_LEFT0x2, 0, buf1, "");
7594 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 2, ADSI_JUST_LEFT0x2, 0, buf2, "");
7595 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE0x1, 1);
7596
7597 for (x = 0; x < 6; x++)
7598 keys[x] = ADSI_KEY_SKT0x80 | (ADSI_KEY_APPS16 + x);
7599 keys[6] = 0;
7600 keys[7] = 0;
7601
7602 /* Don't let them listen if there are none */
7603 if (vms->lastmsg < 0)
7604 keys[0] = 1;
7605 bytes += ast_adsi_set_keys(buf + bytes, keys);
7606
7607 bytes += ast_adsi_voice_mode(buf + bytes, 0);
7608
7609 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY132);
7610}
7611
7612static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
7613{
7614 unsigned char buf[256] = "";
7615 char buf1[256] = "", buf2[256] = "";
7616 int bytes = 0;
7617 unsigned char keys[8];
7618 int x;
7619
7620 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
7621
7622 if (!ast_adsi_available(chan))
7623 return;
7624
7625 /* Original command keys */
7626 for (x = 0; x < 6; x++)
7627 keys[x] = ADSI_KEY_SKT0x80 | (ADSI_KEY_APPS16 + x);
7628
7629 keys[6] = 0;
7630 keys[7] = 0;
7631
7632 if ((vms->lastmsg + 1) < 1)
7633 keys[0] = 0;
7634
7635 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
7636 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
7637
7638 if (vms->lastmsg + 1)
7639 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
7640 else
7641 strcpy(buf2, "no messages.");
7642 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 1, ADSI_JUST_LEFT0x2, 0, buf1, "");
7643 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 2, ADSI_JUST_LEFT0x2, 0, buf2, "");
7644 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 3, ADSI_JUST_LEFT0x2, 0, "", "");
7645 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE0x1, 1);
7646 bytes += ast_adsi_set_keys(buf + bytes, keys);
7647
7648 bytes += ast_adsi_voice_mode(buf + bytes, 0);
7649
7650 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY132);
7651
7652}
7653
7654/*
7655static void adsi_clear(struct ast_channel *chan)
7656{
7657 char buf[256];
7658 int bytes=0;
7659 if (!ast_adsi_available(chan))
7660 return;
7661 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
7662 bytes += ast_adsi_voice_mode(buf + bytes, 0);
7663
7664 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
7665}
7666*/
7667
7668static void adsi_goodbye(struct ast_channel *chan)
7669{
7670 unsigned char buf[256];
7671 int bytes = 0;
7672
7673 if (!ast_adsi_available(chan))
7674 return;
7675 bytes += adsi_logo(buf + bytes);
7676 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 3, ADSI_JUST_LEFT0x2, 0, " ", "");
7677 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 4, ADSI_JUST_CENT0x0, 0, "Goodbye", "");
7678 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE0x1, 1);
7679 bytes += ast_adsi_voice_mode(buf + bytes, 0);
7680
7681 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY132);
7682}
7683
7684/*!\brief get_folder: Folder menu
7685 * Plays "press 1 for INBOX messages" etc.
7686 * Should possibly be internationalized
7687 */
7688static int get_folder(struct ast_channel *chan, int start)
7689{
7690 int x;
7691 int d;
7692 char fn[PATH_MAX4096];
7693 d = ast_play_and_wait(chan, "vm-press"); /* "Press" */
7694 if (d)
7695 return d;
7696 for (x = start; x < 5; x++) { /* For all folders */
7697 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), NULL((void*)0))))
7698 return d;
7699 d = ast_play_and_wait(chan, "vm-for"); /* "for" */
7700 if (d)
7701 return d;
7702 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL((void*)0), x)); /* Folder name */
7703
7704 /* The inbox folder can have its name changed under certain conditions
7705 * so this checks if the sound file exists for the inbox folder name and
7706 * if it doesn't, plays the default name instead. */
7707 if (x == 0) {
7708 if (ast_fileexists(fn, NULL((void*)0), NULL((void*)0))) {
7709 d = vm_play_folder_name(chan, fn);
7710 } else {
7711 ast_verb(4, "Failed to find file %s; falling back to INBOX\n", fn)do { if (((4) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 7711, __PRETTY_FUNCTION__, 4, "Failed to find file %s; falling back to INBOX\n"
, fn); } } while (0)
;
7712 d = vm_play_folder_name(chan, "vm-INBOX");
7713 }
7714 } else {
7715 ast_test_suite_event_notify("PLAYBACK", "Message: folder name %s", fn);
7716 d = vm_play_folder_name(chan, fn);
7717 }
7718
7719 if (d)
7720 return d;
7721 d = ast_waitfordigit(chan, 500);
7722 if (d)
7723 return d;
7724 }
7725
7726 d = ast_play_and_wait(chan, "vm-tocancel"); /* "or pound to cancel" */
7727 if (d)
7728 return d;
7729 d = ast_waitfordigit(chan, 4000);
7730 return d;
7731}
7732
7733/* Japanese Syntax */
7734static int get_folder_ja(struct ast_channel *chan, int start)
7735{
7736 int x;
7737 int d;
7738 char fn[256];
7739 for (x = start; x< 5; x++) { /* For all folders */
7740 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), (char *) NULL((void*)0)))) {
7741 return d;
7742 }
7743 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL((void*)0), x)); /* Folder name */
7744 d = vm_play_folder_name(chan, fn);
7745 if (d) {
7746 return d;
7747 }
7748 d = ast_waitfordigit(chan, 500);
7749 if (d) {
7750 return d;
7751 }
7752 }
7753 d = ast_play_and_wait(chan, "vm-tocancel"); /* "or pound to cancel" */
7754 if (d) {
7755 return d;
7756 }
7757 d = ast_waitfordigit(chan, 4000);
7758 return d;
7759}
7760
7761/*!
7762 * \brief plays a prompt and waits for a keypress.
7763 * \param chan
7764 * \param fn the name of the voice prompt file to be played. For example, 'vm-changeto', 'vm-savefolder'
7765 * \param start Does not appear to be used at this time.
7766 *
7767 * This is used by the main menu option to move a message to a folder or to save a message into a folder.
7768 * After playing the message identified by the fn parameter value, it calls get_folder(), which plays the
7769 * prompting for the number inputs that correspond to the available folders.
7770 *
7771 * \return zero on success, or -1 on error.
7772 */
7773static int get_folder2(struct ast_channel *chan, char *fn, int start)
7774{
7775 int res = 0;
7776 int loops = 0;
7777
7778 res = ast_play_and_wait(chan, fn); /* Folder name */
7779 while (((res < '0') || (res > '9')) &&
7780 (res != '#') && (res >= 0) &&
7781 loops < 4) {
7782 /* res = get_folder(chan, 0); */
7783 if (!strcasecmp(ast_channel_language(chan),"ja")) { /* Japanese syntax */
7784 res = get_folder_ja(chan, 0);
7785 } else { /* Default syntax */
7786 res = get_folder(chan, 0);
7787 }
7788 loops++;
7789 }
7790 if (loops == 4) { /* give up */
7791 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", '#', '#');
7792 return '#';
7793 }
7794 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
7795 return res;
7796}
7797
7798/*!
7799 * \brief presents the option to prepend to an existing message when forwarding it.
7800 * \param chan
7801 * \param vmu
7802 * \param curdir
7803 * \param curmsg
7804 * \param vm_fmts
7805 * \param context
7806 * \param record_gain
7807 * \param duration
7808 * \param vms
7809 * \param flag
7810 *
7811 * Presents a prompt for 1 to prepend the current message, 2 to forward the message without prepending, or * to return to the main menu.
7812 *
7813 * This is invoked from forward_message() when performing a forward operation (option 8 from main menu).
7814 * \return zero on success, -1 on error.
7815 */
7816static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts,
7817 char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
7818{
7819 int cmd = 0;
7820 int retries = 0, prepend_duration = 0, already_recorded = 0;
7821 char msgfile[PATH_MAX4096], backup[PATH_MAX4096], backup_textfile[PATH_MAX4096];
7822 char textfile[PATH_MAX4096];
7823 struct ast_config *msg_cfg;
7824 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
7825#ifndef IMAP_STORAGE
7826 signed char zero_gain = 0;
7827#else
7828 const char *msg_id = NULL((void*)0);
7829#endif
7830 const char *duration_str;
7831
7832 /* Must always populate duration correctly */
7833 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
7834 strcpy(textfile, msgfile);
7835 strcpy(backup, msgfile);
7836 strcpy(backup_textfile, msgfile);
7837 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1)__builtin_strncat (textfile, ".txt", sizeof(textfile) - strlen
(textfile) - 1)
;
7838 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1)__builtin_strncat (backup, "-bak", sizeof(backup) - strlen(backup
) - 1)
;
7839 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1)__builtin_strncat (backup_textfile, "-bak.txt", sizeof(backup_textfile
) - strlen(backup_textfile) - 1)
;
7840
7841 if ((msg_cfg = ast_config_load(textfile, config_flags)ast_config_load2(textfile, "app_voicemail", config_flags)) && valid_config(msg_cfg) && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
7842 *duration = atoi(duration_str);
7843 } else {
7844 *duration = 0;
7845 }
7846
7847 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
7848 if (cmd)
7849 retries = 0;
7850 switch (cmd) {
7851 case '1':
7852
7853#ifdef IMAP_STORAGE
7854 /* Record new intro file */
7855 if (msg_cfg && msg_cfg != CONFIG_STATUS_FILEINVALID(void *)-2) {
7856 msg_id = ast_variable_retrieve(msg_cfg, "message", "msg_id");
7857 }
7858 make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
7859 strncat(vms->introfn, "intro", sizeof(vms->introfn))__builtin_strncat (vms->introfn, "intro", sizeof(vms->introfn
))
;
7860 ast_play_and_wait(chan, "vm-record-prepend");
7861 ast_play_and_wait(chan, "beep");
7862 cmd = play_record_review(chan, NULL((void*)0), vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL((void*)0), NULL((void*)0), record_gain, vms, flag, msg_id, 1);
7863 if (cmd == -1) {
7864 break;
7865 }
7866 cmd = 't';
7867#else
7868
7869 /* prepend a message to the current message, update the metadata and return */
7870
7871 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
7872 strcpy(textfile, msgfile);
7873 strncat(textfile, ".txt", sizeof(textfile) - 1)__builtin_strncat (textfile, ".txt", sizeof(textfile) - 1);
7874 *duration = 0;
7875
7876 /* if we can't read the message metadata, stop now */
7877 if (!valid_config(msg_cfg)) {
7878 cmd = 0;
7879 break;
7880 }
7881
7882 /* Back up the original file, so we can retry the prepend and restore it after forward. */
7883#ifndef IMAP_STORAGE
7884 if (already_recorded) {
7885 ast_filecopy(backup, msgfile, NULL((void*)0));
7886 copy(backup_textfile, textfile);
7887 }
7888 else {
7889 ast_filecopy(msgfile, backup, NULL((void*)0));
7890 copy(textfile, backup_textfile);
7891 }
7892#endif
7893 already_recorded = 1;
7894
7895 if (record_gain)
7896 ast_channel_setoption(chan, AST_OPTION_RXGAIN6, &record_gain, sizeof(record_gain), 0);
7897
7898 cmd = ast_play_and_prepend(chan, NULL((void*)0), msgfile, 0, vm_fmts, &prepend_duration, NULL((void*)0), 1, silencethreshold, maxsilence);
7899
7900 if (cmd == 'S') { /* If we timed out, tell the user it didn't work properly and clean up the files */
7901 ast_stream_and_wait(chan, vm_pls_try_again, ""); /* this might be removed if a proper vm_prepend_timeout is ever recorded */
7902 ast_stream_and_wait(chan, vm_prepend_timeout, "");
7903 ast_filerename(backup, msgfile, NULL((void*)0));
7904 }
7905
7906 if (record_gain)
7907 ast_channel_setoption(chan, AST_OPTION_RXGAIN6, &zero_gain, sizeof(zero_gain), 0);
7908
7909
7910 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
7911 *duration = atoi(duration_str);
7912
7913 if (prepend_duration) {
7914 struct ast_category *msg_cat;
7915 /* need enough space for a maximum-length message duration */
7916 char duration_buf[12];
7917
7918 *duration += prepend_duration;
7919 msg_cat = ast_category_get(msg_cfg, "message", NULL((void*)0));
7920 snprintf(duration_buf, 11, "%ld", *duration);
7921 if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL((void*)0), 0)) {
7922 ast_config_text_file_save(textfile, msg_cfg, "app_voicemail");
7923 }
7924 }
7925
7926#endif
7927 break;
7928 case '2':
7929 /* NULL out introfile so we know there is no intro! */
7930#ifdef IMAP_STORAGE
7931 *vms->introfn = '\0';
7932#endif
7933 cmd = 't';
7934 break;
7935 case '*':
7936 cmd = '*';
7937 break;
7938 default:
7939 /* If time_out and return to menu, reset already_recorded */
7940 already_recorded = 0;
7941
7942 cmd = ast_play_and_wait(chan, "vm-forwardoptions");
7943 /* "Press 1 to prepend a message or 2 to forward the message without prepending" */
7944 if (!cmd) {
7945 cmd = ast_play_and_wait(chan, "vm-starmain");
7946 /* "press star to return to the main menu" */
7947 }
7948 if (!cmd) {
7949 cmd = ast_waitfordigit(chan, 6000);
7950 }
7951 if (!cmd) {
7952 retries++;
7953 }
7954 if (retries > 3) {
7955 cmd = '*'; /* Let's cancel this beast */
7956 }
7957 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
7958 }
7959 }
7960
7961 if (valid_config(msg_cfg))
7962 ast_config_destroy(msg_cfg);
7963 if (prepend_duration)
7964 *duration = prepend_duration;
7965
7966 if (already_recorded && cmd == -1) {
7967 /* restore original message if prepention cancelled */
7968 ast_filerename(backup, msgfile, NULL((void*)0));
7969 rename(backup_textfile, textfile);
7970 }
7971
7972 if (cmd == 't' || cmd == 'S') /* XXX entering this block with a value of 'S' is probably no longer possible. */
7973 cmd = 0;
7974 return cmd;
7975}
7976
7977static void queue_mwi_event(const char *channel_id, const char *box, int urgent, int new, int old)
7978{
7979 char *mailbox;
7980 char *context;
7981
7982 if (separate_mailbox(ast_strdupa(box)(__extension__ ({ const char *__old = (box); size_t __len = strlen
(__old) + 1; char *__new = __builtin_alloca(__len); memcpy (__new
, __old, __len); __new; }))
, &mailbox, &context)) {
7983 return;
7984 }
7985
7986 ast_publish_mwi_state_channel(mailbox, context, new + urgent, old, channel_id)ast_publish_mwi_state_full(mailbox, context, new + urgent, old
, channel_id, ((void*)0))
;
7987}
7988
7989/*!
7990 * \brief Sends email notification that a user has a new voicemail waiting for them.
7991 * \param chan
7992 * \param vmu
7993 * \param vms
7994 * \param msgnum
7995 * \param duration
7996 * \param fmt
7997 * \param cidnum The Caller ID phone number value.
7998 * \param cidname The Caller ID name value.
7999 * \param flag
8000 *
8001 * \return zero on success, -1 on error.
8002 */
8003static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msgnum, long duration, char *fmt, char *cidnum, char *cidname, const char *flag)
8004{
8005 char todir[PATH_MAX4096], fn[PATH_MAX4096], ext_context[PATH_MAX4096], *stringp;
8006 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
8007 const char *category;
8008 char *myserveremail = serveremail;
8009
8010 ast_channel_lock(chan)__ao2_lock(chan, AO2_LOCK_REQ_MUTEX, "app_voicemail.c", __PRETTY_FUNCTION__
, 8010, "chan")
;
8011 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
8012 category = ast_strdupa(category)(__extension__ ({ const char *__old = (category); size_t __len
= strlen(__old) + 1; char *__new = __builtin_alloca(__len); memcpy
(__new, __old, __len); __new; }))
;
8013 }
8014 ast_channel_unlock(chan)__ao2_unlock(chan, "app_voicemail.c", __PRETTY_FUNCTION__, 8014
, "chan")
;
8015
8016#ifndef IMAP_STORAGE
8017 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag)_ast_strlen_zero(flag, "app_voicemail.c", __PRETTY_FUNCTION__
, 8017)
&& !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
8018#else
8019 snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
8020#endif
8021 make_file(fn, sizeof(fn), todir, msgnum);
8022 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
8023
8024 if (!ast_strlen_zero(vmu->attachfmt)_ast_strlen_zero(vmu->attachfmt, "app_voicemail.c", __PRETTY_FUNCTION__
, 8024)
) {
8025 if (strstr(fmt, vmu->attachfmt))
8026 fmt = vmu->attachfmt;
8027 else
8028 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 8028, __PRETTY_FUNCTION__, "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);
8029 }
8030
8031 /* Attach only the first format */
8032 fmt = ast_strdupa(fmt)(__extension__ ({ const char *__old = (fmt); size_t __len = strlen
(__old) + 1; char *__new = __builtin_alloca(__len); memcpy (__new
, __old, __len); __new; }))
;
8033 stringp = fmt;
8034 strsep(&stringp, "|");
8035
8036 if (!ast_strlen_zero(vmu->serveremail)_ast_strlen_zero(vmu->serveremail, "app_voicemail.c", __PRETTY_FUNCTION__
, 8036)
)
8037 myserveremail = vmu->serveremail;
8038
8039 if (!ast_strlen_zero(vmu->email)_ast_strlen_zero(vmu->email, "app_voicemail.c", __PRETTY_FUNCTION__
, 8039)
) {
8040 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 11))); })
;
8041 char *msg_id = NULL((void*)0);
8042#ifdef IMAP_STORAGE
8043 struct ast_config *msg_cfg;
8044 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
8045 char filename[PATH_MAX4096];
8046
8047 snprintf(filename, sizeof(filename), "%s.txt", fn);
8048 msg_cfg = ast_config_load(filename, config_flags)ast_config_load2(filename, "app_voicemail", config_flags);
8049 if (msg_cfg && msg_cfg != CONFIG_STATUS_FILEINVALID(void *)-2) {
8050 msg_id = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "msg_id"))(__extension__ ({ const char *__old = (ast_variable_retrieve(
msg_cfg, "message", "msg_id")); size_t __len = strlen(__old) +
1; char *__new = __builtin_alloca(__len); memcpy (__new, __old
, __len); __new; }))
;
8051 ast_config_destroy(msg_cfg);
8052 }
8053#endif
8054
8055 if (attach_user_voicemail)
8056 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
8057
8058 /* XXX possible imap issue, should category be NULL XXX */
8059 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, fn, NULL((void*)0), fmt, duration, attach_user_voicemail, chan, category, flag, msg_id);
8060
8061 if (attach_user_voicemail)
8062 DISPOSE(todir, msgnum);
8063 }
8064
8065 if (!ast_strlen_zero(vmu->pager)_ast_strlen_zero(vmu->pager, "app_voicemail.c", __PRETTY_FUNCTION__
, 8065)
) {
8066 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
8067 }
8068
8069 if (ast_test_flag(vmu, VM_DELETE)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 12))); })
)
8070 DELETE(todir, msgnum, fn, vmu)(vm_delete(fn));
8071
8072 /* Leave voicemail for someone */
8073 if (ast_app_has_voicemail(ext_context, NULL((void*)0)))
8074 ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
8075
8076 queue_mwi_event(ast_channel_uniqueid(chan), ext_context, urgentmsgs, newmsgs, oldmsgs);
8077 run_externnotify(vmu->context, vmu->mailbox, flag);
8078
8079#ifdef IMAP_STORAGE
8080 vm_delete(fn); /* Delete the file, but not the IMAP message */
8081 if (ast_test_flag(vmu, VM_DELETE)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 12))); })
) { /* Delete the IMAP message if delete = yes */
8082 vm_imap_delete(NULL((void*)0), vms->curmsg, vmu);
8083 vms->newmessages--; /* Fix new message count */
8084 }
8085#endif
8086
8087 return 0;
8088}
8089
8090/*!
8091 * \brief Sends a voicemail message to a mailbox recipient.
8092 * \param chan
8093 * \param context
8094 * \param vms
8095 * \param sender
8096 * \param fmt
8097 * \param is_new_message Used to indicate the mode for which this method was invoked.
8098 * Will be 0 when called to forward an existing message (option 8)
8099 * Will be 1 when called to leave a message (option 3->5)
8100 * \param record_gain
8101 * \param urgent
8102 *
8103 * Reads the destination mailbox(es) from keypad input for CID, or if use_directory feature is enabled, the Directory.
8104 *
8105 * When in the leave message mode (is_new_message == 1):
8106 * - allow the leaving of a message for ourselves. (Will not allow us to forward a message to ourselves, when is_new_message == 0).
8107 * - attempt to determine the context and and mailbox, and then invoke leave_message() function to record and store the message.
8108 *
8109 * When in the forward message mode (is_new_message == 0):
8110 * - retrieves the current message to be forwarded
8111 * - copies the original message to a temporary file, so updates to the envelope can be done.
8112 * - determines the target mailbox and folders
8113 * - copies the message into the target mailbox, using copy_message() or by generating the message into an email attachment if using imap folders.
8114 *
8115 * \return zero on success, -1 on error.
8116 */
8117static int forward_message(struct ast_channel *chan, char *context, struct vm_state *vms, struct ast_vm_user *sender, char *fmt, int is_new_message, signed char record_gain, int urgent)
8118{
8119#ifdef IMAP_STORAGE
8120 int todircount = 0;
8121 struct vm_state *dstvms;
8122#endif
8123 char username[70]="";
8124 char fn[PATH_MAX4096]; /* for playback of name greeting */
8125 char ecodes[16] = "#";
8126 int res = 0, cmd = 0;
8127 struct ast_vm_user *receiver = NULL((void*)0), *vmtmp;
8128 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user)struct extensions { struct ast_vm_user *first; struct ast_vm_user
*last; } extensions = { .first = ((void*)0), .last = ((void*
)0), }
;
8129 char *stringp;
8130 const char *s;
8131 const char mailbox_context[256];
8132 int saved_messages = 0;
8133 int valid_extensions = 0;
8134 char *dir;
8135 int curmsg;
8136 char urgent_str[7] = "";
8137 int prompt_played = 0;
8138#ifndef IMAP_STORAGE
8139 char msgfile[PATH_MAX4096], textfile[PATH_MAX4096], backup[PATH_MAX4096], backup_textfile[PATH_MAX4096];
8140#endif
8141 if (ast_test_flag((&globalflags), VM_FWDURGAUTO)({ typeof (((&globalflags))->flags) __p = ((&globalflags
))->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); (((&globalflags))->flags &
((1 << 18))); })
) {
8142 ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
8143 }
8144
8145 if (vms == NULL((void*)0)) return -1;
8146 dir = vms->curdir;
8147 curmsg = vms->curmsg;
8148
8149 ast_test_suite_event_notify("FORWARD", "Message: entering forward message menu");
8150 while (!res && !valid_extensions) {
8151 int use_directory = 0;
8152 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)({ typeof (((&globalflags))->flags) __p = ((&globalflags
))->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); (((&globalflags))->flags &
((1 << 10))); })
) {
8153 int done = 0;
8154 int retries = 0;
8155 cmd = 0;
8156 while ((cmd >= 0) && !done ){
8157 if (cmd)
8158 retries = 0;
8159 switch (cmd) {
8160 case '1':
8161 use_directory = 0;
8162 done = 1;
8163 break;
8164 case '2':
8165 use_directory = 1;
8166 done = 1;
8167 break;
8168 case '*':
8169 cmd = 't';
8170 done = 1;
8171 break;
8172 default:
8173 /* Press 1 to enter an extension press 2 to use the directory */
8174 cmd = ast_play_and_wait(chan, "vm-forward");
8175 if (!cmd) {
8176 cmd = ast_waitfordigit(chan, 3000);
8177 }
8178 if (!cmd) {
8179 retries++;
8180 }
8181 if (retries > 3) {
8182 cmd = 't';
8183 done = 1;
8184 }
8185 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
8186 }
8187 }
8188 if (cmd < 0 || cmd == 't')
8189 break;
8190 }
8191
8192 if (use_directory) {
8193 /* use app_directory */
8194
8195 struct ast_app* directory_app;
8196
8197 directory_app = pbx_findapp("Directory");
8198 if (directory_app) {
8199 char vmcontext[256];
8200 char *old_context;
8201 char *old_exten;
8202 int old_priority;
8203 /* make backup copies */
8204 old_context = ast_strdupa(ast_channel_context(chan))(__extension__ ({ const char *__old = (ast_channel_context(chan
)); size_t __len = strlen(__old) + 1; char *__new = __builtin_alloca
(__len); memcpy (__new, __old, __len); __new; }))
;
8205 old_exten = ast_strdupa(ast_channel_exten(chan))(__extension__ ({ const char *__old = (ast_channel_exten(chan
)); size_t __len = strlen(__old) + 1; char *__new = __builtin_alloca
(__len); memcpy (__new, __old, __len); __new; }))
;
8206 old_priority = ast_channel_priority(chan);
8207
8208 /* call the the Directory, changes the channel */
8209 snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
8210 res = pbx_exec(chan, directory_app, vmcontext);
8211
8212 ast_copy_string(username, ast_channel_exten(chan), sizeof(username));
8213
8214 /* restore the old context, exten, and priority */
8215 ast_channel_context_set(chan, old_context);
8216 ast_channel_exten_set(chan, old_exten);
8217 ast_channel_priority_set(chan, old_priority);
8218 } else {
8219 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 8219, __PRETTY_FUNCTION__, "Could not find the Directory application, disabling directory_forward\n");
8220 ast_clear_flag((&globalflags), VM_DIRECFORWARD)do { typeof (((&globalflags))->flags) __p = ((&globalflags
))->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); (((&globalflags))->flags &=
~((1 << 10))); } while(0)
;
8221 }
8222 } else {
8223 /* Ask for an extension */
8224 res = ast_streamfile(chan, "vm-extension", ast_channel_language(chan)); /* "extension" */
8225 prompt_played++;
8226 if (res || prompt_played > 4)
8227 break;
8228 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#")) < 0)
8229 break;
8230 }
8231
8232 /* start all over if no username */
8233 if (ast_strlen_zero(username)_ast_strlen_zero(username, "app_voicemail.c", __PRETTY_FUNCTION__
, 8233)
)
8234 continue;
8235 stringp = username;
8236 s = strsep(&stringp, "*");
8237 /* start optimistic */
8238 valid_extensions = 1;
8239 while (s) {
8240 snprintf((char*)mailbox_context, sizeof(mailbox_context), "%s@%s", s, context ? context : "default");
8241 if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL((void*)0), context, s))) {
8242 int oldmsgs;
8243 int newmsgs;
8244 int capacity;
8245
8246 if (inboxcount(mailbox_context, &newmsgs, &oldmsgs)) {
8247 ast_log(LOG_ERROR4, "app_voicemail.c", 8247, __PRETTY_FUNCTION__, "Problem in calculating number of voicemail messages available for extension %s\n", mailbox_context);
8248 /* Shouldn't happen, but allow trying another extension if it does */
8249 res = ast_play_and_wait(chan, "pbx-invalid");
8250 valid_extensions = 0;
8251 break;
8252 }
8253#ifdef IMAP_STORAGE
8254 if (!(dstvms = get_vm_state_by_mailbox(s, context, 0))) {
8255 if (!(dstvms = create_vm_state_from_user(receiver))) {
8256 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 8256, __PRETTY_FUNCTION__, "Couldn't allocate necessary space\n");
8257 /* Shouldn't happen, but allow trying another extension if it does */
8258 res = ast_play_and_wait(chan, "pbx-invalid");
8259 valid_extensions = 0;
8260 break;
8261 }
8262 }
8263 check_quota(dstvms, imapfolder);
8264 if (dstvms->quota_limit && dstvms->quota_usage >= dstvms->quota_limit) {
8265 ast_log(LOG_NOTICE2, "app_voicemail.c", 8265, __PRETTY_FUNCTION__, "Mailbox '%s' is exceeded quota %u >= %u\n", mailbox_context, dstvms->quota_usage, dstvms->quota_limit);
8266 res = ast_play_and_wait(chan, "vm-mailboxfull");
8267 valid_extensions = 0;
8268 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list)({ typeof((&extensions)->first) __cur = (&extensions
)->first; if (__cur) { (&extensions)->first = __cur
->list.next; __cur->list.next = ((void*)0); if ((&extensions
)->last == __cur) (&extensions)->last = ((void*)0);
} __cur; })
)) {
8269 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
8270 free_user(vmtmp);
8271 }
8272 break;
8273 }
8274#endif
8275 capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
8276 if ((newmsgs + oldmsgs) >= capacity) {
8277 ast_log(LOG_NOTICE2, "app_voicemail.c", 8277, __PRETTY_FUNCTION__, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", mailbox_context, capacity);
8278 res = ast_play_and_wait(chan, "vm-mailboxfull");
8279 valid_extensions = 0;
8280 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list)({ typeof((&extensions)->first) __cur = (&extensions
)->first; if (__cur) { (&extensions)->first = __cur
->list.next; __cur->list.next = ((void*)0); if ((&extensions
)->last == __cur) (&extensions)->last = ((void*)0);
} __cur; })
)) {
8281 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
8282 free_user(vmtmp);
8283 }
8284 inprocess_count(receiver->mailbox, receiver->context, -1);
8285 break;
8286 }
8287 AST_LIST_INSERT_HEAD(&extensions, receiver, list)do { (receiver)->list.next = (&extensions)->first; (
&extensions)->first = (receiver); if (!(&extensions
)->last) (&extensions)->last = (receiver); } while (
0)
;
8288 } else {
8289 /* XXX Optimization for the future. When we encounter a single bad extension,
8290 * bailing out on all of the extensions may not be the way to go. We should
8291 * probably just bail on that single extension, then allow the user to enter
8292 * several more. XXX
8293 */
8294 while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list)({ typeof((&extensions)->first) __cur = (&extensions
)->first; if (__cur) { (&extensions)->first = __cur
->list.next; __cur->list.next = ((void*)0); if ((&extensions
)->last == __cur) (&extensions)->last = ((void*)0);
} __cur; })
)) {
8295 free_user(receiver);
8296 }
8297 ast_log(LOG_NOTICE2, "app_voicemail.c", 8297, __PRETTY_FUNCTION__, "'%s' is not a valid mailbox\n", mailbox_context);
8298 /* "I am sorry, that's not a valid extension. Please try again." */
8299 res = ast_play_and_wait(chan, "pbx-invalid");
8300 valid_extensions = 0;
8301 break;
8302 }
8303
8304 /* play name if available, else play extension number */
8305 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
8306 RETRIEVE(fn, -1, s, receiver->context);
8307 if (ast_fileexists(fn, NULL((void*)0), NULL((void*)0)) > 0) {
8308 res = ast_stream_and_wait(chan, fn, ecodes);
8309 if (res) {
8310 DISPOSE(fn, -1);
8311 return res;
8312 }
8313 } else {
8314 res = ast_say_digit_str(chan, s, ecodes, ast_channel_language(chan));
8315 }
8316 DISPOSE(fn, -1);
8317
8318 s = strsep(&stringp, "*");
8319 }
8320 /* break from the loop of reading the extensions */
8321 if (valid_extensions)
8322 break;
8323 }
8324 /* check if we're clear to proceed */
8325 if (AST_LIST_EMPTY(&extensions)(((&extensions)->first) == ((void*)0)) || !valid_extensions)
8326 return res;
8327 if (is_new_message == 1) {
8328 struct leave_vm_options leave_options;
8329 char mailbox[AST_MAX_EXTENSION80 * 2 + 2];
8330 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
8331
8332 /* Send VoiceMail */
8333 memset(&leave_options, 0, sizeof(leave_options));
8334 leave_options.record_gain = record_gain;
8335 cmd = leave_voicemail(chan, mailbox, &leave_options);
8336 } else {
8337 /* Forward VoiceMail */
8338 long duration = 0;
8339 struct vm_state vmstmp;
8340 int copy_msg_result = 0;
8341#ifdef IMAP_STORAGE
8342 char filename[PATH_MAX4096];
8343 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
8344 const char *msg_id = NULL((void*)0);
8345 struct ast_config *msg_cfg;
8346#endif
8347 memcpy(&vmstmp, vms, sizeof(vmstmp));
8348
8349 RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
8350#ifdef IMAP_STORAGE
8351 make_file(filename, sizeof(filename), dir, curmsg);
8352 strncat(filename, ".txt", sizeof(filename) - strlen(filename) - 1)__builtin_strncat (filename, ".txt", sizeof(filename) - strlen
(filename) - 1)
;
8353 msg_cfg = ast_config_load(filename, config_flags)ast_config_load2(filename, "app_voicemail", config_flags);
8354 if (msg_cfg && msg_cfg == CONFIG_STATUS_FILEINVALID(void *)-2) {
8355 msg_id = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "msg_id"))(__extension__ ({ const char *__old = (ast_variable_retrieve(
msg_cfg, "message", "msg_id")); size_t __len = strlen(__old) +
1; char *__new = __builtin_alloca(__len); memcpy (__new, __old
, __len); __new; }))
;
8356 ast_config_destroy(msg_cfg);
8357 }
8358#endif
8359
8360 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default")({typeof(&((context)[0])) __x = (context); _ast_strlen_zero
(__x, "app_voicemail.c", __PRETTY_FUNCTION__, 8360) ? ("default"
) : __x;})
, record_gain, &duration, &vmstmp, urgent_str);
8361 if (!cmd) {
8362 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list){ typeof((&extensions)) __list_head = &extensions; typeof
(__list_head->first) __list_next; typeof(__list_head->first
) __list_prev = ((void*)0); typeof(__list_head->first) __list_current
; for ((vmtmp) = __list_head->first, __list_current = (vmtmp
), __list_next = (vmtmp) ? (vmtmp)->list.next : ((void*)0)
; (vmtmp); __list_prev = __list_current, (vmtmp) = __list_next
, __list_current = (vmtmp), __list_next = (vmtmp) ? (vmtmp)->
list.next : ((void*)0), (void) __list_prev )
{
8363#ifdef IMAP_STORAGE
8364 int attach_user_voicemail;
8365 char *myserveremail = serveremail;
8366
8367 /* get destination mailbox */
8368 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
8369 if (!dstvms) {
8370 dstvms = create_vm_state_from_user(vmtmp);
8371 }
8372 if (dstvms) {
8373 init_mailstream(dstvms, 0);
8374 if (!dstvms->mailstream) {
8375 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 8375, __PRETTY_FUNCTION__, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
8376 } else {
8377 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str, msg_id);
8378 run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str);
8379 }
8380 } else {
8381 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 8381, __PRETTY_FUNCTION__, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
8382 }
8383 if (!ast_strlen_zero(vmtmp->serveremail)_ast_strlen_zero(vmtmp->serveremail, "app_voicemail.c", __PRETTY_FUNCTION__
, 8383)
)
8384 myserveremail = vmtmp->serveremail;
8385 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH)({ typeof ((vmtmp)->flags) __p = (vmtmp)->flags; typeof
(__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); ((vmtmp)->flags & ((1 << 11))); })
;
8386 /* NULL category for IMAP storage */
8387 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
8388 dstvms->curbox,
8389 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL)({typeof(&((ast_channel_caller(chan)->id.number.str)[0
])) __x = (ast_channel_caller(chan)->id.number.str); (ast_channel_caller
(chan)->id.number.valid) && !_ast_strlen_zero(__x,
"app_voicemail.c", __PRETTY_FUNCTION__, 8389) ? (__x) : (((void
*)0));})
,
8390 S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL)({typeof(&((ast_channel_caller(chan)->id.name.str)[0])
) __x = (ast_channel_caller(chan)->id.name.str); (ast_channel_caller
(chan)->id.name.valid) && !_ast_strlen_zero(__x, "app_voicemail.c"
, __PRETTY_FUNCTION__, 8390) ? (__x) : (((void*)0));})
,
8391 vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
8392 NULL((void*)0), urgent_str, msg_id);
8393#else
8394 copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str, NULL((void*)0));
8395#endif
8396 saved_messages++;
8397 AST_LIST_REMOVE_CURRENT(list)do { __list_current->list.next = ((void*)0); __list_current
= __list_prev; if (__list_prev) { __list_prev->list.next =
__list_next; } else { __list_head->first = __list_next; }
if (!__list_next) { __list_head->last = __list_prev; } } while
(0)
;
8398 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
8399 free_user(vmtmp);
8400 if (res)
8401 break;
8402 }
8403 AST_LIST_TRAVERSE_SAFE_END};
8404 if (saved_messages > 0 && !copy_msg_result) {
8405 /* give confirmation that the message was saved */
8406 /* commented out since we can't forward batches yet
8407 if (saved_messages == 1)
8408 res = ast_play_and_wait(chan, "vm-message");
8409 else
8410 res = ast_play_and_wait(chan, "vm-messages");
8411 if (!res)
8412 res = ast_play_and_wait(chan, "vm-saved"); */
8413 res = ast_play_and_wait(chan, "vm-msgforwarded");
8414 }
8415#ifndef IMAP_STORAGE
8416 else {
8417 /* with IMAP, mailbox full warning played by imap_check_limits */
8418 res = ast_play_and_wait(chan, "vm-mailboxfull");
8419 }
8420 /* Restore original message without prepended message if backup exists */
8421 make_file(msgfile, sizeof(msgfile), dir, curmsg);
8422 strcpy(textfile, msgfile);
8423 strcpy(backup, msgfile);
8424 strcpy(backup_textfile, msgfile);
8425 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1)__builtin_strncat (textfile, ".txt", sizeof(textfile) - strlen
(textfile) - 1)
;
8426 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1)__builtin_strncat (backup, "-bak", sizeof(backup) - strlen(backup
) - 1)
;
8427 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1)__builtin_strncat (backup_textfile, "-bak.txt", sizeof(backup_textfile
) - strlen(backup_textfile) - 1)
;
8428 if (ast_fileexists(backup, NULL((void*)0), NULL((void*)0)) > 0) {
8429 ast_filerename(backup, msgfile, NULL((void*)0));
8430 rename(backup_textfile, textfile);
8431 }
8432#endif
8433 }
8434 DISPOSE(dir, curmsg);
8435#ifndef IMAP_STORAGE
8436 if (cmd) { /* assuming hangup, cleanup backup file */
8437 make_file(msgfile, sizeof(msgfile), dir, curmsg);
8438 strcpy(textfile, msgfile);
8439 strcpy(backup_textfile, msgfile);
8440 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1)__builtin_strncat (textfile, ".txt", sizeof(textfile) - strlen
(textfile) - 1)
;
8441 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1)__builtin_strncat (backup_textfile, "-bak.txt", sizeof(backup_textfile
) - strlen(backup_textfile) - 1)
;
8442 rename(backup_textfile, textfile);
8443 }
8444#endif
8445 }
8446
8447 /* If anything failed above, we still have this list to free */
8448 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list)({ typeof((&extensions)->first) __cur = (&extensions
)->first; if (__cur) { (&extensions)->first = __cur
->list.next; __cur->list.next = ((void*)0); if ((&extensions
)->last == __cur) (&extensions)->last = ((void*)0);
} __cur; })
)) {
8449 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
8450 free_user(vmtmp);
8451 }
8452 return res ? res : cmd;
8453}
8454
8455static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
8456{
8457 int res;
8458 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY"0123456789#*ABCD")) < 0)
8459 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 8459, __PRETTY_FUNCTION__, "Unable to play message %s\n", file);
8460 return res;
8461}
8462
8463static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
8464{
8465 ast_test_suite_event_notify("PLAYVOICE", "Message: Playing %s", file);
8466 return ast_control_streamfile(chan, file, listen_control_forward_key, listen_control_reverse_key, listen_control_stop_key, listen_control_pause_key, listen_control_restart_key, skipms, NULL((void*)0));
8467}
8468
8469static int play_message_category(struct ast_channel *chan, const char *category)
8470{
8471 int res = 0;
8472
8473 if (!ast_strlen_zero(category)_ast_strlen_zero(category, "app_voicemail.c", __PRETTY_FUNCTION__
, 8473)
)
8474 res = ast_play_and_wait(chan, category);
8475
8476 if (res) {
8477 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 8477, __PRETTY_FUNCTION__, "No sound file for category '%s' was found.\n", category);
8478 res = 0;
8479 }
8480
8481 return res;
8482}
8483
8484static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
8485{
8486 int res = 0;
8487 struct vm_zone *the_zone = NULL((void*)0);
8488 time_t t;
8489
8490 if (ast_get_time_t(origtime, &t, 0, NULL((void*)0))) {
8491 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 8491, __PRETTY_FUNCTION__, "Couldn't find origtime in %s\n", filename);
8492 return 0;
8493 }
8494
8495 /* Does this user have a timezone specified? */
8496 if (!ast_strlen_zero(vmu->zonetag)_ast_strlen_zero(vmu->zonetag, "app_voicemail.c", __PRETTY_FUNCTION__
, 8496)
) {
8497 /* Find the zone in the list */
8498 struct vm_zone *z;
8499 AST_LIST_LOCK(&zones)__ast_pthread_mutex_lock("app_voicemail.c", 8499, __PRETTY_FUNCTION__
, "&(&zones)->lock", &(&zones)->lock)
;
8500 AST_LIST_TRAVERSE(&zones, z, list)for((z) = (&zones)->first; (z); (z) = (z)->list.next
)
{
8501 if (!strcmp(z->name, vmu->zonetag)) {
8502 the_zone = z;
8503 break;
8504 }
8505 }
8506 AST_LIST_UNLOCK(&zones)__ast_pthread_mutex_unlock("app_voicemail.c", 8506, __PRETTY_FUNCTION__
, "&(&zones)->lock", &(&zones)->lock)
;
8507 }
8508
8509/* No internal variable parsing for now, so we'll comment it out for the time being */
8510#if 0
8511 /* Set the DIFF_* variables */
8512 ast_localtime(&t, &time_now, NULL((void*)0));
8513 tv_now = ast_tvnow();
8514 ast_localtime(&tv_now, &time_then, NULL((void*)0));
8515
8516 /* Day difference */
8517 if (time_now.tm_year == time_then.tm_year)
8518 snprintf(temp, sizeof(temp), "%d", time_now.tm_yday);
8519 else
8520 snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
8521 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
8522
8523 /* Can't think of how other diffs might be helpful, but I'm sure somebody will think of something. */
8524#endif
8525 if (the_zone) {
8526 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), the_zone->msg_format, the_zone->timezone);
8527 } else if (!strncasecmp(ast_channel_language(chan), "de", 2)) { /* GERMAN syntax */
8528 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), "'vm-received' Q 'digits/at' HM", NULL((void*)0));
8529 } else if (!strncasecmp(ast_channel_language(chan), "gr", 2)) { /* GREEK syntax */
8530 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), "'vm-received' q H 'digits/kai' M ", NULL((void*)0));
8531 } else if (!strncasecmp(ast_channel_language(chan), "is", 2)) { /* ICELANDIC syntax */
8532 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), "'vm-received' Q 'digits/at' HM", NULL((void*)0));
8533 } else if (!strncasecmp(ast_channel_language(chan), "it", 2)) { /* ITALIAN syntax */
8534 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), "'vm-received' q 'digits/at' 'digits/hours' k 'digits/e' M 'digits/minutes'", NULL((void*)0));
8535 } else if (!strcasecmp(ast_channel_language(chan),"ja")) { /* Japanese syntax */
8536 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), "PHM q 'jp-ni' 'vm-received'", NULL((void*)0));
8537 } else if (!strncasecmp(ast_channel_language(chan), "nl", 2)) { /* DUTCH syntax */
8538 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), "'vm-received' q 'digits/nl-om' HM", NULL((void*)0));
8539 } else if (!strncasecmp(ast_channel_language(chan), "no", 2)) { /* NORWEGIAN syntax */
8540 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), "'vm-received' Q 'digits/at' HM", NULL((void*)0));
8541 } else if (!strncasecmp(ast_channel_language(chan), "pl", 2)) { /* POLISH syntax */
8542 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), "'vm-received' Q HM", NULL((void*)0));
8543 } else if (!strncasecmp(ast_channel_language(chan), "pt_BR", 5)) { /* Brazillian PORTUGUESE syntax */
8544 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), "'vm-received' Ad 'digits/pt-de' B 'digits/pt-de' Y 'digits/pt-as' HM ", NULL((void*)0));
8545 } else if (!strncasecmp(ast_channel_language(chan), "se", 2)) { /* SWEDISH syntax */
8546 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), "'vm-received' dB 'digits/at' k 'and' M", NULL((void*)0));
8547 } else if (!strncasecmp(ast_channel_language(chan), "zh", 2)) { /* CHINESE (Taiwan) syntax */
8548 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), "qR 'vm-received'", NULL((void*)0));
8549 } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) { /* VIETNAMESE syntax */
8550 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), "'vm-received' A 'digits/day' dB 'digits/year' Y 'digits/at' k 'hours' M 'minutes'", NULL((void*)0));
8551 } else {
8552 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), "'vm-received' q 'digits/at' IMp", NULL((void*)0));
8553 }
8554#if 0
8555 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL((void*)0));
8556#endif
8557 return res;
8558}
8559
8560
8561
8562static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback, int saycidnumber)
8563{
8564 int res = 0;
8565 int i;
8566 char *callerid, *name;
8567 char prefile[PATH_MAX4096] = "";
8568
8569 /* If voicemail cid is not enabled, or we didn't get cid or context from
8570 * the attribute file, leave now.
8571 *
8572 * TODO Still need to change this so that if this function is called by the
8573 * message envelope (and someone is explicitly requesting to hear the CID),
8574 * it does not check to see if CID is enabled in the config file.
8575 */
8576 if ((cid == NULL((void*)0))||(context == NULL((void*)0)))
8577 return res;
8578
8579 /* Strip off caller ID number from name */
8580 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 8580, __PRETTY_FUNCTION__, "VM-CID: composite caller ID received: %s, context: %s\n"
, cid, context); } } while (0)
;
8581 ast_callerid_parse(cid, &name, &callerid);
8582 if ((!ast_strlen_zero(callerid)_ast_strlen_zero(callerid, "app_voicemail.c", __PRETTY_FUNCTION__
, 8582)
) && strcmp(callerid, "Unknown")) {
8583 /* Check for internal contexts and only */
8584 /* say extension when the call didn't come from an internal context in the list */
8585 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS10 ; i++){
8586 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i])do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 8586, __PRETTY_FUNCTION__, "VM-CID: comparing internalcontext: %s\n"
, cidinternalcontexts[i]); } } while (0)
;
8587 if ((strcmp(cidinternalcontexts[i], context) == 0))
8588 break;
8589 }
8590 if (i != MAX_NUM_CID_CONTEXTS10){ /* internal context? */
8591 if (!res) {
8592 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
8593 if (!ast_strlen_zero(prefile)_ast_strlen_zero(prefile, "app_voicemail.c", __PRETTY_FUNCTION__
, 8593)
) {
8594 /* See if we can find a recorded name for this callerid
8595 * and if found, use that instead of saying number. */
8596 if (ast_fileexists(prefile, NULL((void*)0), NULL((void*)0)) > 0) {
8597 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid)do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 8597, __PRETTY_FUNCTION__, 3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n"
, callerid); } } while (0)
;
8598 if (!callback)
8599 res = wait_file2(chan, vms, "vm-from");
8600 res = ast_stream_and_wait(chan, prefile, "");
8601 } else {
8602 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid)do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 8602, __PRETTY_FUNCTION__, 3, "Playing envelope info: message from '%s'\n"
, callerid); } } while (0)
;
8603 /* Say "from extension" as one saying to sound smoother */
8604 if (!callback)
8605 res = wait_file2(chan, vms, "vm-from-extension");
8606 res = ast_say_digit_str(chan, callerid, "", ast_channel_language(chan));
8607 }
8608 }
8609 }
8610 } else if (!res) {
8611 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 8611, __PRETTY_FUNCTION__, "VM-CID: Numeric caller id: (%s)\n"
, callerid); } } while (0)
;
8612 /* If there is a recording for this numeric callerid then play that */
8613 if (!callback) {
8614 /* See if we can find a recorded name for this person instead of their extension number */
8615 snprintf(prefile, sizeof(prefile), "%s/recordings/callerids/%s", ast_config_AST_SPOOL_DIR, callerid);
8616 if (!saycidnumber && ast_fileexists(prefile, NULL((void*)0), NULL((void*)0)) > 0) {
8617 ast_verb(3, "Playing recorded name for CID number '%s' - '%s'\n", callerid,prefile)do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 8617, __PRETTY_FUNCTION__, 3, "Playing recorded name for CID number '%s' - '%s'\n"
, callerid,prefile); } } while (0)
;
8618 wait_file2(chan, vms, "vm-from");
8619 res = ast_stream_and_wait(chan, prefile, "");
8620 ast_verb(3, "Played recorded name result '%d'\n", res)do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 8620, __PRETTY_FUNCTION__, 3, "Played recorded name result '%d'\n"
, res); } } while (0)
;
8621 } else {
8622 /* Since this is all nicely figured out, why not say "from phone number" in this case" */
8623 wait_file2(chan, vms, "vm-from-phonenumber");
8624 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan));
8625 }
8626 } else {
8627 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan));
8628 }
8629 }
8630 } else {
8631 /* Number unknown */
8632 ast_debug(1, "VM-CID: From an unknown number\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 8632, __PRETTY_FUNCTION__, "VM-CID: From an unknown number\n"
); } } while (0)
;
8633 /* Say "from an unknown caller" as one phrase - it is already recorded by "the voice" anyhow */
8634 res = wait_file2(chan, vms, "vm-unknown-caller");
8635 }
8636 return res;
8637}
8638
8639static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
8640{
8641 int res = 0;
8642 int durationm;
8643 int durations;
8644 /* Verify that we have a duration for the message */
8645 if (duration == NULL((void*)0))
8646 return res;
8647
8648 /* Convert from seconds to minutes */
8649 durations = atoi(duration);
8650 durationm = (durations / 60);
8651
8652 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 8652, __PRETTY_FUNCTION__, "VM-Duration: duration is: %d seconds converted to: %d minutes\n"
, durations, durationm); } } while (0)
;
8653
8654 if ((!res) && (durationm >= minduration)) {
8655 res = wait_file2(chan, vms, "vm-duration");
8656
8657 /* POLISH syntax */
8658 if (!strncasecmp(ast_channel_language(chan), "pl", 2)) {
8659 div_t num = div(durationm, 10);
8660
8661 if (durationm == 1) {
8662 res = ast_play_and_wait(chan, "digits/1z");
8663 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
8664 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
8665 if (num.rem == 2) {
8666 if (!num.quot) {
8667 res = ast_play_and_wait(chan, "digits/2-ie");
8668 } else {
8669 res = say_and_wait(chan, durationm - 2 , ast_channel_language(chan));
8670 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
8671 }
8672 } else {
8673 res = say_and_wait(chan, durationm, ast_channel_language(chan));
8674 }
8675 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
8676 } else {
8677 res = say_and_wait(chan, durationm, ast_channel_language(chan));
8678 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
8679 }
8680 /* DEFAULT syntax */
8681 } else {
8682 res = ast_say_number(chan, durationm, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), NULL((void*)0));
8683 res = wait_file2(chan, vms, "vm-minutes");
8684 }
8685 }
8686 return res;
8687}
8688
8689static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
8690{
8691 int res = 0;
8692 char filename[256], *cid;
8693 const char *origtime, *context, *category, *duration, *flag;
8694 struct ast_config *msg_cfg;
8695 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
8696
8697 vms->starting = 0;
8698 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
8699 adsi_message(chan, vms);
8700 if (!vms->curmsg) {
8701 res = wait_file2(chan, vms, "vm-first"); /* "First" */
8702 } else if (vms->curmsg == vms->lastmsg) {
8703 res = wait_file2(chan, vms, "vm-last"); /* "last" */
8704 }
8705
8706 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
8707 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
8708 msg_cfg = ast_config_load(filename, config_flags)ast_config_load2(filename, "app_voicemail", config_flags);
8709 if (!valid_config(msg_cfg)) {
8710 ast_log(LOG_WARNING3, "app_voicemail.c", 8710, __PRETTY_FUNCTION__, "No message attribute file?!! (%s)\n", filename);
8711 return 0;
8712 }
8713 flag = ast_variable_retrieve(msg_cfg, "message", "flag");
8714
8715 /* Play the word urgent if we are listening to urgent messages */
8716 if (!ast_strlen_zero(flag)_ast_strlen_zero(flag, "app_voicemail.c", __PRETTY_FUNCTION__
, 8716)
&& !strcmp(flag, "Urgent")) {
8717 res = wait_file2(chan, vms, "vm-Urgent"); /* "urgent" */
8718 }
8719
8720 if (!res) {
8721 /* XXX Why are we playing messages above, and then playing the same language-specific stuff here? */
8722 /* POLISH syntax */
8723 if (!strncasecmp(ast_channel_language(chan), "pl", 2)) {
8724 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
8725 int ten, one;
8726 char nextmsg[256];
8727 ten = (vms->curmsg + 1) / 10;
8728 one = (vms->curmsg + 1) % 10;
8729
8730 if (vms->curmsg < 20) {
8731 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
8732 res = wait_file2(chan, vms, nextmsg);
8733 } else {
8734 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
8735 res = wait_file2(chan, vms, nextmsg);
8736 if (one > 0) {
8737 if (!res) {
8738 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
8739 res = wait_file2(chan, vms, nextmsg);
8740 }
8741 }
8742 }
8743 }
8744 if (!res)
8745 res = wait_file2(chan, vms, "vm-message");
8746 /* HEBREW syntax */
8747 } else if (!strncasecmp(ast_channel_language(chan), "he", 2)) {
8748 if (!vms->curmsg) {
8749 res = wait_file2(chan, vms, "vm-message");
8750 res = wait_file2(chan, vms, "vm-first");
8751 } else if (vms->curmsg == vms->lastmsg) {
8752 res = wait_file2(chan, vms, "vm-message");
8753 res = wait_file2(chan, vms, "vm-last");
8754 } else {
8755 res = wait_file2(chan, vms, "vm-message");
8756 res = wait_file2(chan, vms, "vm-number");
8757 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), "f");
8758 }
8759 /* ICELANDIC syntax */
8760 } else if (!strncasecmp(ast_channel_language(chan), "is", 2)) {
8761 res = wait_file2(chan, vms, "vm-message");
8762 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
8763 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), "n");
8764 }
8765 /* VIETNAMESE syntax */
8766 } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) {
8767 if (!vms->curmsg) {
8768 res = wait_file2(chan, vms, "vm-message");
8769 res = wait_file2(chan, vms, "vm-first");
8770 } else if (vms->curmsg == vms->lastmsg) {
8771 res = wait_file2(chan, vms, "vm-message");
8772 res = wait_file2(chan, vms, "vm-last");
8773 } else {
8774 res = wait_file2(chan, vms, "vm-message");
8775 res = wait_file2(chan, vms, "vm-number");
8776 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), "f");
8777 }
8778 } else {
8779 if (!strncasecmp(ast_channel_language(chan), "se", 2)) { /* SWEDISH syntax */
8780 res = wait_file2(chan, vms, "vm-meddelandet"); /* "message" */
8781 } else { /* DEFAULT syntax */
8782 res = wait_file2(chan, vms, "vm-message");
8783 }
8784 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
8785 if (!res) {
8786 ast_test_suite_event_notify("PLAYBACK", "Message: message number");
8787 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), NULL((void*)0));
8788 }
8789 }
8790 }
8791 }
8792
8793 if (!valid_config(msg_cfg)) {
8794 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 8794, __PRETTY_FUNCTION__, "No message attribute file?!! (%s)\n", filename);
8795 return 0;
8796 }
8797
8798 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
8799 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 8799, __PRETTY_FUNCTION__, "No origtime?!\n");
8800 DISPOSE(vms->curdir, vms->curmsg);
8801 ast_config_destroy(msg_cfg);
8802 return 0;
8803 }
8804
8805 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"))(__extension__ ({ const char *__old = (ast_variable_retrieve(
msg_cfg, "message", "callerid")); size_t __len = strlen(__old
) + 1; char *__new = __builtin_alloca(__len); memcpy (__new, __old
, __len); __new; }))
;
8806 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
8807 category = ast_variable_retrieve(msg_cfg, "message", "category");
8808
8809 context = ast_variable_retrieve(msg_cfg, "message", "context");
8810 if (!strncasecmp("macro", context, 5)) /* Macro names in contexts are useless for our needs */
8811 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
8812 if (!res) {
8813 res = play_message_category(chan, category);
8814 }
8815 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 4))); })
)) {
8816 res = play_message_datetime(chan, vmu, origtime, filename);
8817 }
8818 if ((!res) && (ast_test_flag(vmu, VM_SAYCID)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 2))); })
)) {
8819 res = play_message_callerid(chan, vms, cid, context, 0, 0);
8820 }
8821 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 5))); })
)) {
8822 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
8823 }
8824 /* Allow pressing '1' to skip envelope / callerid */
8825 if (res == '1') {
8826 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
8827 res = 0;
8828 }
8829 ast_config_destroy(msg_cfg);
8830
8831 if (!res) {
8832 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
8833#ifdef IMAP_STORAGE
8834 ast_mutex_lock(&vms->lock)__ast_pthread_mutex_lock("app_voicemail.c", 8834, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
8835#endif
8836 vms->heard[vms->curmsg] = 1;
8837#ifdef IMAP_STORAGE
8838 ast_mutex_unlock(&vms->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 8838, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
8839 /*IMAP storage stores any prepended message from a forward
8840 * as a separate file from the rest of the message
8841 */
8842 if (!ast_strlen_zero(vms->introfn)_ast_strlen_zero(vms->introfn, "app_voicemail.c", __PRETTY_FUNCTION__
, 8842)
&& ast_fileexists(vms->introfn, NULL((void*)0), NULL((void*)0)) > 0) {
8843 wait_file(chan, vms, vms->introfn);
8844 }
8845#endif
8846 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
8847 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 8847, __PRETTY_FUNCTION__, "Playback of message %s failed\n", vms->fn);
8848 res = 0;
8849 }
8850 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
8851 }
8852 DISPOSE(vms->curdir, vms->curmsg);
8853 return res;
8854}
8855
8856#ifdef IMAP_STORAGE
8857static int imap_remove_file(char *dir, int msgnum)
8858{
8859 char fn[PATH_MAX4096];
8860 char full_fn[PATH_MAX4096];
8861 char intro[PATH_MAX4096] = {0,};
8862
8863 if (msgnum > -1) {
8864 make_file(fn, sizeof(fn), dir, msgnum);
8865 snprintf(intro, sizeof(intro), "%sintro", fn);
8866 } else
8867 ast_copy_string(fn, dir, sizeof(fn));
8868
8869 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
8870 ast_filedelete(fn, NULL((void*)0));
8871 if (!ast_strlen_zero(intro)_ast_strlen_zero(intro, "app_voicemail.c", __PRETTY_FUNCTION__
, 8871)
) {
8872 ast_filedelete(intro, NULL((void*)0));
8873 }
8874 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
8875 unlink(full_fn);
8876 }
8877 return 0;
8878}
8879
8880
8881
8882static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
8883{
8884 char *file, *filename;
8885 char *attachment;
8886 char arg[10];
8887 int i;
8888 BODY* body;
8889 int curr_mbox;
8890
8891 file = strrchr(ast_strdupa(dir)(__extension__ ({ const char *__old = (dir); size_t __len = strlen
(__old) + 1; char *__new = __builtin_alloca(__len); memcpy (__new
, __old, __len); __new; }))
, '/');
8892 if (file) {
8893 *file++ = '\0';
8894 } else {
8895 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 8895, __PRETTY_FUNCTION__, "Failed to procure file name from directory passed. You should never see this.\n");
8896 return -1;
8897 }
8898
8899 ast_mutex_lock(&vms->lock)__ast_pthread_mutex_lock("app_voicemail.c", 8899, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
8900
8901 /* get the current mailbox so that we can point the mailstream back to it later */
8902 curr_mbox = get_folder_by_name(vms->curbox);
8903
8904 if (init_mailstream(vms, GREETINGS_FOLDER) || !vms->mailstream) {
8905 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 8905, __PRETTY_FUNCTION__, "IMAP mailstream is NULL or can't init_mailstream\n");
8906 ast_mutex_unlock(&vms->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 8906, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
8907 return -1;
8908 }
8909
8910 for (i = 0; i < vms->mailstream->nmsgs; i++) {
8911 mail_fetchstructure(vms->mailstream, i + 1, &body);
8912 /* We have the body, now we extract the file name of the first attachment. */
8913 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
8914 attachment = ast_strdupa(body->nested.part->next->body.parameter->value)(__extension__ ({ const char *__old = (body->nested.part->
next->body.parameter->value); size_t __len = strlen(__old
) + 1; char *__new = __builtin_alloca(__len); memcpy (__new, __old
, __len); __new; }))
;
8915 } else {
8916 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 8916, __PRETTY_FUNCTION__, "There is no file attached to this IMAP message.\n");
8917 ast_mutex_unlock(&vms->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 8917, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
8918 return -1;
8919 }
8920 filename = strsep(&attachment, ".");
8921 if (!strcmp(filename, file)) {
8922 sprintf(arg, "%d", i + 1);
8923 mail_setflag(vms->mailstream, arg, "\\DELETED");
8924 }
8925 }
8926 mail_expunge(vms->mailstream);
8927
8928 if (curr_mbox != -1) {
8929 /* restore previous mbox stream */
8930 if (init_mailstream(vms, curr_mbox) || !vms->mailstream) {
8931 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 8931, __PRETTY_FUNCTION__, "IMAP mailstream is NULL or can't init_mailstream\n");
8932 }
8933 }
8934
8935 ast_mutex_unlock(&vms->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 8935, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
8936 return 0;
8937}
8938
8939#elif !defined(IMAP_STORAGE)
8940static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
8941{
8942 int count_msg, last_msg;
8943
8944 ast_copy_string(vms->curbox, mbox(vmu, box), sizeof(vms->curbox));
8945
8946 /* Rename the member vmbox HERE so that we don't try to return before
8947 * we know what's going on.
8948 */
8949 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
8950
8951 /* Faster to make the directory than to check if it exists. */
8952 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
8953
8954 /* traverses directory using readdir (or select query for ODBC) */
8955 count_msg = count_messages(vmu, vms->curdir);
8956 if (count_msg < 0) {
8957 return count_msg;
8958 } else {
8959 vms->lastmsg = count_msg - 1;
8960 }
8961
8962 if (vm_allocate_dh(vms, vmu, count_msg)) {
8963 return -1;
8964 }
8965
8966 /*
8967 The following test is needed in case sequencing gets messed up.
8968 There appears to be more than one way to mess up sequence, so
8969 we will not try to find all of the root causes--just fix it when
8970 detected.
8971 */
8972
8973 if (vm_lock_path(vms->curdir)) {
8974 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 8974, __PRETTY_FUNCTION__, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
8975 return ERROR_LOCK_PATH-100;
8976 }
8977
8978 /* for local storage, checks directory for messages up to maxmsg limit */
8979 last_msg = last_message_index(vmu, vms->curdir);
8980 ast_unlock_path(vms->curdir);
8981
8982 if (last_msg < -1) {
8983 return last_msg;
8984 } else if (vms->lastmsg != last_msg) {
8985 ast_log(LOG_NOTICE2, "app_voicemail.c", 8985, __PRETTY_FUNCTION__, "Resequencing Mailbox: %s, expected %d but found %d message(s) in box with max threshold of %d.\n", vms->curdir, last_msg + 1, vms->lastmsg + 1, vmu->maxmsg);
8986 resequence_mailbox(vmu, vms->curdir, count_msg);
8987 }
8988
8989 return 0;
8990}
8991#endif
8992
8993static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
8994{
8995 int x = 0;
8996 int last_msg_idx = 0;
8997
8998#ifndef IMAP_STORAGE
8999 int res = 0, nummsg;
9000 char fn2[PATH_MAX4096];
9001#endif
9002
9003 if (vms->lastmsg <= -1) {
9004 goto done;
9005 }
9006
9007 vms->curmsg = -1;
9008#ifndef IMAP_STORAGE
9009 /* Get the deleted messages fixed */
9010 if (vm_lock_path(vms->curdir)) {
9011 return ERROR_LOCK_PATH-100;
9012 }
9013
9014 /* update count as message may have arrived while we've got mailbox open */
9015 last_msg_idx = last_message_index(vmu, vms->curdir);
9016 if (last_msg_idx != vms->lastmsg) {
9017 ast_log(AST_LOG_NOTICE2, "app_voicemail.c", 9017, __PRETTY_FUNCTION__, "%d messages received after mailbox opened.\n", last_msg_idx - vms->lastmsg);
9018 }
9019
9020 /* must check up to last detected message, just in case it is erroneously greater than maxmsg */
9021 for (x = 0; x < last_msg_idx + 1; x++) {
9022 if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 16))); })
))) {
9023 /* Save this message. It's not in INBOX or hasn't been heard */
9024 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
9025 if (!EXISTS(vms->curdir, x, vms->fn, NULL)(ast_fileexists(vms->fn,((void*)0),((void*)0)) > 0)) {
9026 break;
9027 }
9028 vms->curmsg++;
9029 make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
9030 if (strcmp(vms->fn, fn2)) {
9031 RENAME(vms->curdir, x, vmu->mailbox, vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2)(rename_file(vms->fn,fn2));;
9032 }
9033 } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 16))); })
&& !vms->deleted[x]) {
9034 /* Move to old folder before deleting */
9035 res = save_to_folder(vmu, vms, x, 1, NULL((void*)0), 0);
9036 if (res == ERROR_LOCK_PATH-100 || res == ERROR_MAX_MSGS-101) {
9037 /* If save failed do not delete the message */
9038 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 9038, __PRETTY_FUNCTION__, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH-100 ? "unable to lock path" : "destination folder full");
9039 vms->deleted[x] = 0;
9040 vms->heard[x] = 0;
9041 --x;
9042 }
9043 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
9044 /* Move to deleted folder */
9045 res = save_to_folder(vmu, vms, x, 10, NULL((void*)0), 0);
9046 if (res == ERROR_LOCK_PATH-100) {
9047 /* If save failed do not delete the message */
9048 vms->deleted[x] = 0;
9049 vms->heard[x] = 0;
9050 --x;
9051 }
9052 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
9053 /* If realtime storage enabled - we should explicitly delete this message,
9054 cause RENAME() will overwrite files, but will keep duplicate records in RT-storage */
9055 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
9056 if (EXISTS(vms->curdir, x, vms->fn, NULL)(ast_fileexists(vms->fn,((void*)0),((void*)0)) > 0)) {
9057 DELETE(vms->curdir, x, vms->fn, vmu)(vm_delete(vms->fn));
9058 }
9059 }
9060 }
9061
9062 /* Delete ALL remaining messages */
9063 nummsg = x - 1;
9064 for (x = vms->curmsg + 1; x <= nummsg; x++) {
9065 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
9066 if (EXISTS(vms->curdir, x, vms->fn, NULL)(ast_fileexists(vms->fn,((void*)0),((void*)0)) > 0)) {
9067 DELETE(vms->curdir, x, vms->fn, vmu)(vm_delete(vms->fn));
9068 }
9069 }
9070 ast_unlock_path(vms->curdir);
9071#else /* defined(IMAP_STORAGE) */
9072 ast_mutex_lock(&vms->lock)__ast_pthread_mutex_lock("app_voicemail.c", 9072, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
9073 if (vms->deleted) {
9074 /* Since we now expunge after each delete, deleting in reverse order
9075 * ensures that no reordering occurs between each step. */
9076 last_msg_idx = vms->dh_arraysize;
9077 for (x = last_msg_idx - 1; x >= 0; x--) {
9078 if (vms->deleted[x]) {
9079 ast_debug(3, "IMAP delete of %d\n", x)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 9079, __PRETTY_FUNCTION__, "IMAP delete of %d\n"
, x); } } while (0)
;
9080 DELETE(vms->curdir, x, vms->fn, vmu)(vm_delete(vms->fn));
9081 }
9082 }
9083 }
9084#endif
9085
9086done:
9087 if (vms->deleted) {
9088 ast_freefree(vms->deleted);
9089 vms->deleted = NULL((void*)0);
9090 }
9091 if (vms->heard) {
9092 ast_freefree(vms->heard);
9093 vms->heard = NULL((void*)0);
9094 }
9095 vms->dh_arraysize = 0;
9096#ifdef IMAP_STORAGE
9097 ast_mutex_unlock(&vms->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 9097, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
9098#endif
9099
9100 return 0;
9101}
9102
9103/* In Greek even though we CAN use a syntax like "friends messages"
9104 * ("filika mynhmata") it is not elegant. This also goes for "work/family messages"
9105 * ("ergasiaka/oikogeniaka mynhmata"). Therefore it is better to use a reversed
9106 * syntax for the above three categories which is more elegant.
9107 */
9108
9109static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
9110{
9111 int cmd;
9112 char *buf;
9113
9114 buf = ast_alloca(strlen(box) + 2)__builtin_alloca(strlen(box) + 2);
9115 strcpy(buf, box);
9116 strcat(buf, "s");
9117
9118 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
9119 cmd = ast_play_and_wait(chan, buf); /* "NEA / PALIA" */
9120 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages"); /* "messages" -> "MYNHMATA" */
9121 } else {
9122 cmd = ast_play_and_wait(chan, "vm-messages"); /* "messages" -> "MYNHMATA" */
9123 return cmd ? cmd : ast_play_and_wait(chan, box); /* friends/family/work... -> "FILWN"/"OIKOGENIAS"/"DOULEIAS"*/
9124 }
9125}
9126
9127static int vm_play_folder_name_ja(struct ast_channel *chan, char *box)
9128{
9129 int cmd;
9130
9131 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
9132 cmd = ast_play_and_wait(chan, box);
9133 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
9134 } else {
9135 cmd = ast_play_and_wait(chan, box);
9136 return cmd;
9137 }
9138}
9139
9140static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
9141{
9142 int cmd;
9143
9144 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
9145 if (!strcasecmp(box, "vm-INBOX"))
9146 cmd = ast_play_and_wait(chan, "vm-new-e");
9147 else
9148 cmd = ast_play_and_wait(chan, "vm-old-e");
9149 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
9150 } else {
9151 cmd = ast_play_and_wait(chan, "vm-messages");
9152 return cmd ? cmd : ast_play_and_wait(chan, box);
9153 }
9154}
9155
9156static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
9157{
9158 int cmd;
9159
9160 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
9161 cmd = ast_play_and_wait(chan, "vm-messages");
9162 return cmd ? cmd : ast_play_and_wait(chan, box);
9163 } else {
9164 cmd = ast_play_and_wait(chan, box);
9165 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
9166 }
9167}
9168
9169static int vm_play_folder_name(struct ast_channel *chan, char *box)
9170{
9171 int cmd;
9172
9173 if ( !strncasecmp(ast_channel_language(chan), "it", 2) ||
9174 !strncasecmp(ast_channel_language(chan), "es", 2) ||
9175 !strncasecmp(ast_channel_language(chan), "pt", 2)) { /* Italian, Spanish, or Portuguese syntax */
9176 cmd = ast_play_and_wait(chan, "vm-messages"); /* "messages */
9177 return cmd ? cmd : ast_play_and_wait(chan, box);
9178 } else if (!strncasecmp(ast_channel_language(chan), "gr", 2)) {
9179 return vm_play_folder_name_gr(chan, box);
9180 } else if (!strncasecmp(ast_channel_language(chan), "he", 2)) { /* Hebrew syntax */
9181 return ast_play_and_wait(chan, box);
9182 } else if (!strncasecmp(ast_channel_language(chan), "ja", 2)) { /* Japanese syntax */
9183 return vm_play_folder_name_ja(chan, box);
9184 } else if (!strncasecmp(ast_channel_language(chan), "pl", 2)) {
9185 return vm_play_folder_name_pl(chan, box);
9186 } else if (!strncasecmp(ast_channel_language(chan), "ua", 2)) { /* Ukrainian syntax */
9187 return vm_play_folder_name_ua(chan, box);
9188 } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) {
9189 return ast_play_and_wait(chan, box);
9190 } else { /* Default English */
9191 cmd = ast_play_and_wait(chan, box);
9192 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages"); /* "messages */
9193 }
9194}
9195
9196/* GREEK SYNTAX
9197 In greek the plural for old/new is
9198 different so we need the following files
9199 We also need vm-denExeteMynhmata because
9200 this syntax is different.
9201
9202 -> vm-Olds.wav : "Palia"
9203 -> vm-INBOXs.wav : "Nea"
9204 -> vm-denExeteMynhmata : "den exete mynhmata"
9205*/
9206
9207
9208static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
9209{
9210 int res = 0;
9211
9212 if (vms->newmessages) {
9213 res = ast_play_and_wait(chan, "vm-youhave");
9214 if (!res)
9215 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), NULL((void*)0));
9216 if (!res) {
9217 if (vms->newmessages == 1) {
9218 res = ast_play_and_wait(chan, "vm-INBOX");
9219 if (!res)
9220 res = ast_play_and_wait(chan, "vm-message");
9221 } else {
9222 res = ast_play_and_wait(chan, "vm-INBOXs");
9223 if (!res)
9224 res = ast_play_and_wait(chan, "vm-messages");
9225 }
9226 }
9227 } else if (vms->oldmessages){
9228 res = ast_play_and_wait(chan, "vm-youhave");
9229 if (!res)
9230 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), NULL((void*)0));
9231 if (vms->oldmessages == 1){
9232 res = ast_play_and_wait(chan, "vm-Old");
9233 if (!res)
9234 res = ast_play_and_wait(chan, "vm-message");
9235 } else {
9236 res = ast_play_and_wait(chan, "vm-Olds");
9237 if (!res)
9238 res = ast_play_and_wait(chan, "vm-messages");
9239 }
9240 } else if (!vms->oldmessages && !vms->newmessages)
9241 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
9242 return res;
9243}
9244
9245/* Version of vm_intro() designed to work for many languages.
9246 *
9247 * It is hoped that this function can prevent the proliferation of
9248 * language-specific vm_intro() functions and in time replace the language-
9249 * specific functions which already exist. An examination of the language-
9250 * specific functions revealed that they all corrected the same deficiencies
9251 * in vm_intro_en() (which was the default function). Namely:
9252 *
9253 * 1) The vm-Old and vm-INBOX sound files were overloaded. The English
9254 * wording of the voicemail greeting hides this problem. For example,
9255 * vm-INBOX contains only the word "new". This means that both of these
9256 * sequences produce valid utterances:
9257 * * vm-youhave digit/1 vm-INBOX vm-message (you have one new message)
9258 * * vm-press digit/1 vm-for vm-INBOX vm-messages (press 1 for new messages)
9259 * However, if we rerecord vm-INBOX to say "the new" (which is unavoidable
9260 * in many languages) the first utterance becomes "you have 1 the new message".
9261 * 2) The function contains hardcoded rules for pluralizing the word "message".
9262 * These rules are correct for English, but not for many other languages.
9263 * 3) No attempt is made to pluralize the adjectives ("old" and "new") as
9264 * required in many languages.
9265 * 4) The gender of the word for "message" is not specified. This is a problem
9266 * because in many languages the gender of the number in phrases such
9267 * as "you have one new message" must match the gender of the word
9268 * meaning "message".
9269 *
9270 * Fixing these problems for each new language has meant duplication of effort.
9271 * This new function solves the problems in the following general ways:
9272 * 1) Add new sound files vm-new and vm-old. These can be linked to vm-INBOX
9273 * and vm-Old respectively for those languages where it makes sense.
9274 * 2) Call ast_say_counted_noun() to put the proper gender and number prefix
9275 * on vm-message.
9276 * 3) Call ast_say_counted_adjective() to put the proper gender and number
9277 * prefix on vm-new and vm-old (none for English).
9278 * 4) Pass the gender of the language's word for "message" as an agument to
9279 * this function which is can in turn pass on to the functions which
9280 * say numbers and put endings on nounds and adjectives.
9281 *
9282 * All languages require these messages:
9283 * vm-youhave "You have..."
9284 * vm-and "and"
9285 * vm-no "no" (in the sense of "none", as in "you have no messages")
9286 *
9287 * To use it for English, you will need these additional sound files:
9288 * vm-new "new"
9289 * vm-message "message", singular
9290 * vm-messages "messages", plural
9291 *
9292 * If you use it for Russian and other slavic languages, you will need these additional sound files:
9293 *
9294 * vm-newn "novoye" (singular, neuter)
9295 * vm-newx "novikh" (counting plural form, genative plural)
9296 * vm-message "sobsheniye" (singular form)
9297 * vm-messagex1 "sobsheniya" (first counting plural form, genative singular)
9298 * vm-messagex2 "sobsheniy" (second counting plural form, genative plural)
9299 * digits/1n "odno" (neuter singular for phrases such as "one message" or "thirty one messages")
9300 * digits/2n "dva" (neuter singular)
9301 */
9302static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
9303{
9304 int res;
9305 int lastnum = 0;
9306
9307 res = ast_play_and_wait(chan, "vm-youhave");
9308
9309 if (!res && vms->newmessages) {
9310 lastnum = vms->newmessages;
9311
9312 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), message_gender))) {
9313 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
9314 }
9315
9316 if (!res && vms->oldmessages) {
9317 res = ast_play_and_wait(chan, "vm-and");
9318 }
9319 }
9320
9321 if (!res && vms->oldmessages) {
9322 lastnum = vms->oldmessages;
9323
9324 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), message_gender))) {
9325 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
9326 }
9327 }
9328
9329 if (!res) {
9330 if (lastnum == 0) {
9331 res = ast_play_and_wait(chan, "vm-no");
9332 }
9333 if (!res) {
9334 res = ast_say_counted_noun(chan, lastnum, "vm-message");
9335 }
9336 }
9337
9338 return res;
9339}
9340
9341/* Default Hebrew syntax */
9342static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
9343{
9344 int res = 0;
9345
9346 /* Introduce messages they have */
9347 if (!res) {
9348 if ((vms->newmessages) || (vms->oldmessages)) {
9349 res = ast_play_and_wait(chan, "vm-youhave");
9350 }
9351 /*
9352 * The word "shtei" refers to the number 2 in hebrew when performing a count
9353 * of elements. In Hebrew, there are 6 forms of enumerating the number 2 for
9354 * an element, this is one of them.
9355 */
9356 if (vms->newmessages) {
9357 if (!res) {
9358 if (vms->newmessages == 1) {
9359 res = ast_play_and_wait(chan, "vm-INBOX1");
9360 } else {
9361 if (vms->newmessages == 2) {
9362 res = ast_play_and_wait(chan, "vm-shtei");
9363 } else {
9364 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), "f");
9365 }
9366 res = ast_play_and_wait(chan, "vm-INBOX");
9367 }
9368 }
9369 if (vms->oldmessages && !res) {
9370 res = ast_play_and_wait(chan, "vm-and");
9371 if (vms->oldmessages == 1) {
9372 res = ast_play_and_wait(chan, "vm-Old1");
9373 } else {
9374 if (vms->oldmessages == 2) {
9375 res = ast_play_and_wait(chan, "vm-shtei");
9376 } else {
9377 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), "f");
9378 }
9379 res = ast_play_and_wait(chan, "vm-Old");
9380 }
9381 }
9382 }
9383 if (!res && vms->oldmessages && !vms->newmessages) {
9384 if (!res) {
9385 if (vms->oldmessages == 1) {
9386 res = ast_play_and_wait(chan, "vm-Old1");
9387 } else {
9388 if (vms->oldmessages == 2) {
9389 res = ast_play_and_wait(chan, "vm-shtei");
9390 } else {
9391 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), "f");
9392 }
9393 res = ast_play_and_wait(chan, "vm-Old");
9394 }
9395 }
9396 }
9397 if (!res) {
9398 if (!vms->oldmessages && !vms->newmessages) {
9399 if (!res) {
9400 res = ast_play_and_wait(chan, "vm-nomessages");
9401 }
9402 }
9403 }
9404 }
9405 return res;
9406}
9407
9408/* Japanese syntax */
9409static int vm_intro_ja(struct ast_channel *chan,struct vm_state *vms)
9410{
9411 /* Introduce messages they have */
9412 int res;
9413 if (vms->newmessages) {
9414 res = ast_play_and_wait(chan, "vm-INBOX");
9415 if (!res)
9416 res = ast_play_and_wait(chan, "vm-message");
9417 if (!res)
9418 res = ast_play_and_wait(chan, "jp-ga");
9419 if (!res)
9420 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
9421 if (vms->oldmessages && !res)
9422 res = ast_play_and_wait(chan, "silence/1");
9423
9424 }
9425 if (vms->oldmessages) {
9426 res = ast_play_and_wait(chan, "vm-Old");
9427 if (!res)
9428 res = ast_play_and_wait(chan, "vm-message");
9429 if (!res)
9430 res = ast_play_and_wait(chan, "jp-ga");
9431 if (!res)
9432 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
9433 }
9434 if (!vms->oldmessages && !vms->newmessages) {
9435 res = ast_play_and_wait(chan, "vm-messages");
9436 if (!res)
9437 res = ast_play_and_wait(chan, "jp-wa");
9438 if (!res)
9439 res = ast_play_and_wait(chan, "jp-arimasen");
9440 }
9441 else {
9442 res = ast_play_and_wait(chan, "jp-arimasu");
9443 }
9444 return res;
9445} /* Japanese */
9446
9447/* Default English syntax */
9448static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
9449{
9450 int res;
9451
9452 /* Introduce messages they have */
9453 res = ast_play_and_wait(chan, "vm-youhave");
9454 if (!res) {
9455 if (vms->urgentmessages) {
9456 res = say_and_wait(chan, vms->urgentmessages, ast_channel_language(chan));
9457 if (!res)
9458 res = ast_play_and_wait(chan, "vm-Urgent");
9459 if ((vms->oldmessages || vms->newmessages) && !res) {
9460 res = ast_play_and_wait(chan, "vm-and");
9461 } else if (!res) {
9462 if (vms->urgentmessages == 1)
9463 res = ast_play_and_wait(chan, "vm-message");
9464 else
9465 res = ast_play_and_wait(chan, "vm-messages");
9466 }
9467 }
9468 if (vms->newmessages) {
9469 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
9470 if (!res)
9471 res = ast_play_and_wait(chan, "vm-INBOX");
9472 if (vms->oldmessages && !res)
9473 res = ast_play_and_wait(chan, "vm-and");
9474 else if (!res) {
9475 if (vms->newmessages == 1)
9476 res = ast_play_and_wait(chan, "vm-message");
9477 else
9478 res = ast_play_and_wait(chan, "vm-messages");
9479 }
9480
9481 }
9482 if (!res && vms->oldmessages) {
9483 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
9484 if (!res)
9485 res = ast_play_and_wait(chan, "vm-Old");
9486 if (!res) {
9487 if (vms->oldmessages == 1)
9488 res = ast_play_and_wait(chan, "vm-message");
9489 else
9490 res = ast_play_and_wait(chan, "vm-messages");
9491 }
9492 }
9493 if (!res) {
9494 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
9495 res = ast_play_and_wait(chan, "vm-no");
9496 if (!res)
9497 res = ast_play_and_wait(chan, "vm-messages");
9498 }
9499 }
9500 }
9501 return res;
9502}
9503
9504/* ICELANDIC syntax */
9505static int vm_intro_is(struct ast_channel *chan, struct vm_state *vms)
9506{
9507 int res;
9508
9509 /* Introduce messages they have */
9510 res = ast_play_and_wait(chan, "vm-youhave");
9511 if (!res) {
9512 if (vms->urgentmessages) {
9513 /* Digits 1-4 are spoken in neutral and plural when talking about messages,
9514 however, feminine is used for 1 as it is the same as the neutral for plural,
9515 and singular neutral is the same after 1. */
9516 if (vms->urgentmessages < 5) {
9517 char recname[16];
9518 if (vms->urgentmessages == 1)
9519 snprintf(recname, sizeof(recname), "digits/1kvk");
9520 else
9521 snprintf(recname, sizeof(recname), "digits/%dhk", vms->urgentmessages);
9522 res = ast_play_and_wait(chan, recname);
9523 } else if (!res)
9524 res = ast_play_and_wait(chan, "vm-Urgent");
9525 if ((vms->oldmessages || vms->newmessages) && !res) {
9526 res = ast_play_and_wait(chan, "vm-and");
9527 } else if (!res)
9528 res = ast_play_and_wait(chan, "vm-messages");
9529 }
9530 if (vms->newmessages) {
9531 if (vms->newmessages < 5) {
9532 char recname[16];
9533 if (vms->newmessages == 1)
9534 snprintf(recname, sizeof(recname), "digits/1kvk");
9535 else
9536 snprintf(recname, sizeof(recname), "digits/%dhk", vms->newmessages);
9537 res = ast_play_and_wait(chan, recname);
9538 } else
9539 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
9540 if (!res)
9541 res = ast_play_and_wait(chan, "vm-INBOX");
9542 if (vms->oldmessages && !res)
9543 res = ast_play_and_wait(chan, "vm-and");
9544 else if (!res)
9545 res = ast_play_and_wait(chan, "vm-messages");
9546 }
9547 if (!res && vms->oldmessages) {
9548 if (vms->oldmessages < 5) {
9549 char recname[16];
9550 if (vms->oldmessages == 1)
9551 snprintf(recname, sizeof(recname), "digits/1kvk");
9552 else
9553 snprintf(recname, sizeof(recname), "digits/%dhk", vms->oldmessages);
9554 res = ast_play_and_wait(chan, recname);
9555 } else
9556 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
9557 if (!res)
9558 res = ast_play_and_wait(chan, "vm-Old");
9559 if (!res)
9560 res = ast_play_and_wait(chan, "vm-messages");
9561 }
9562 if (!res) {
9563 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
9564 res = ast_play_and_wait(chan, "vm-no");
9565 if (!res)
9566 res = ast_play_and_wait(chan, "vm-messages");
9567 }
9568 }
9569 }
9570 return res;
9571}
9572
9573/* ITALIAN syntax */
9574static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
9575{
9576 /* Introduce messages they have */
9577 int res;
9578 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
9579 res = ast_play_and_wait(chan, "vm-no") ||
9580 ast_play_and_wait(chan, "vm-message");
9581 else
9582 res = ast_play_and_wait(chan, "vm-youhave");
9583 if (!res && vms->newmessages) {
9584 res = (vms->newmessages == 1) ?
9585 ast_play_and_wait(chan, "digits/un") ||
9586 ast_play_and_wait(chan, "vm-nuovo") ||
9587 ast_play_and_wait(chan, "vm-message") :
9588 /* 2 or more new messages */
9589 say_and_wait(chan, vms->newmessages, ast_channel_language(chan)) ||
9590 ast_play_and_wait(chan, "vm-nuovi") ||
9591 ast_play_and_wait(chan, "vm-messages");
9592 if (!res && vms->oldmessages)
9593 res = ast_play_and_wait(chan, "vm-and");
9594 }
9595 if (!res && vms->oldmessages) {
9596 res = (vms->oldmessages == 1) ?
9597 ast_play_and_wait(chan, "digits/un") ||
9598 ast_play_and_wait(chan, "vm-vecchio") ||
9599 ast_play_and_wait(chan, "vm-message") :
9600 /* 2 or more old messages */
9601 say_and_wait(chan, vms->oldmessages, ast_channel_language(chan)) ||
9602 ast_play_and_wait(chan, "vm-vecchi") ||
9603 ast_play_and_wait(chan, "vm-messages");
9604 }
9605 return res;
9606}
9607
9608/* POLISH syntax */
9609static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
9610{
9611 /* Introduce messages they have */
9612 int res;
9613 div_t num;
9614
9615 if (!vms->oldmessages && !vms->newmessages) {
9616 res = ast_play_and_wait(chan, "vm-no");
9617 res = res ? res : ast_play_and_wait(chan, "vm-messages");
9618 return res;
9619 } else {
9620 res = ast_play_and_wait(chan, "vm-youhave");
9621 }
9622
9623 if (vms->newmessages) {
9624 num = div(vms->newmessages, 10);
9625 if (vms->newmessages == 1) {
9626 res = ast_play_and_wait(chan, "digits/1-a");
9627 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
9628 res = res ? res : ast_play_and_wait(chan, "vm-message");
9629 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
9630 if (num.rem == 2) {
9631 if (!num.quot) {
9632 res = ast_play_and_wait(chan, "digits/2-ie");
9633 } else {
9634 res = say_and_wait(chan, vms->newmessages - 2 , ast_channel_language(chan));
9635 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
9636 }
9637 } else {
9638 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
9639 }
9640 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
9641 res = res ? res : ast_play_and_wait(chan, "vm-messages");
9642 } else {
9643 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
9644 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
9645 res = res ? res : ast_play_and_wait(chan, "vm-messages");
9646 }
9647 if (!res && vms->oldmessages)
9648 res = ast_play_and_wait(chan, "vm-and");
9649 }
9650 if (!res && vms->oldmessages) {
9651 num = div(vms->oldmessages, 10);
9652 if (vms->oldmessages == 1) {
9653 res = ast_play_and_wait(chan, "digits/1-a");
9654 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
9655 res = res ? res : ast_play_and_wait(chan, "vm-message");
9656 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
9657 if (num.rem == 2) {
9658 if (!num.quot) {
9659 res = ast_play_and_wait(chan, "digits/2-ie");
9660 } else {
9661 res = say_and_wait(chan, vms->oldmessages - 2 , ast_channel_language(chan));
9662 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
9663 }
9664 } else {
9665 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
9666 }
9667 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
9668 res = res ? res : ast_play_and_wait(chan, "vm-messages");
9669 } else {
9670 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
9671 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
9672 res = res ? res : ast_play_and_wait(chan, "vm-messages");
9673 }
9674 }
9675
9676 return res;
9677}
9678
9679/* SWEDISH syntax */
9680static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
9681{
9682 /* Introduce messages they have */
9683 int res;
9684
9685 res = ast_play_and_wait(chan, "vm-youhave");
9686 if (res)
9687 return res;
9688
9689 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
9690 res = ast_play_and_wait(chan, "vm-no");
9691 res = res ? res : ast_play_and_wait(chan, "vm-messages");
9692 return res;
9693 }
9694
9695 if (vms->newmessages) {
9696 if (vms->newmessages == 1) {
9697 res = ast_play_and_wait(chan, "digits/ett");
9698 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
9699 res = res ? res : ast_play_and_wait(chan, "vm-message");
9700 } else {
9701 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
9702 res = res ? res : ast_play_and_wait(chan, "vm-nya");
9703 res = res ? res : ast_play_and_wait(chan, "vm-messages");
9704 }
9705 if (!res && vms->oldmessages)
9706 res = ast_play_and_wait(chan, "vm-and");
9707 }
9708 if (!res && vms->oldmessages) {
9709 if (vms->oldmessages == 1) {
9710 res = ast_play_and_wait(chan, "digits/ett");
9711 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
9712 res = res ? res : ast_play_and_wait(chan, "vm-message");
9713 } else {
9714 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
9715 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
9716 res = res ? res : ast_play_and_wait(chan, "vm-messages");
9717 }
9718 }
9719
9720 return res;
9721}
9722
9723/* NORWEGIAN syntax */
9724static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
9725{
9726 /* Introduce messages they have */
9727 int res;
9728
9729 res = ast_play_and_wait(chan, "vm-youhave");
9730 if (res)
9731 return res;
9732
9733 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
9734 res = ast_play_and_wait(chan, "vm-no");
9735 res = res ? res : ast_play_and_wait(chan, "vm-messages");
9736 return res;
9737 }
9738
9739 if (vms->newmessages) {
9740 if (vms->newmessages == 1) {
9741 res = ast_play_and_wait(chan, "digits/1");
9742 res = res ? res : ast_play_and_wait(chan, "vm-ny");
9743 res = res ? res : ast_play_and_wait(chan, "vm-message");
9744 } else {
9745 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
9746 res = res ? res : ast_play_and_wait(chan, "vm-nye");
9747 res = res ? res : ast_play_and_wait(chan, "vm-messages");
9748 }
9749 if (!res && vms->oldmessages)
9750 res = ast_play_and_wait(chan, "vm-and");
9751 }
9752 if (!res && vms->oldmessages) {
9753 if (vms->oldmessages == 1) {
9754 res = ast_play_and_wait(chan, "digits/1");
9755 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
9756 res = res ? res : ast_play_and_wait(chan, "vm-message");
9757 } else {
9758 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
9759 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
9760 res = res ? res : ast_play_and_wait(chan, "vm-messages");
9761 }
9762 }
9763
9764 return res;
9765}
9766
9767/* GERMAN syntax */
9768static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
9769{
9770 /* Introduce messages they have */
9771 int res;
9772 res = ast_play_and_wait(chan, "vm-youhave");
9773 if (!res) {
9774 if (vms->newmessages) {
9775 if (vms->newmessages == 1)
9776 res = ast_play_and_wait(chan, "digits/1F");
9777 else
9778 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
9779 if (!res)
9780 res = ast_play_and_wait(chan, "vm-INBOX");
9781 if (vms->oldmessages && !res)
9782 res = ast_play_and_wait(chan, "vm-and");
9783 else if (!res) {
9784 if (vms->newmessages == 1)
9785 res = ast_play_and_wait(chan, "vm-message");
9786 else
9787 res = ast_play_and_wait(chan, "vm-messages");
9788 }
9789
9790 }
9791 if (!res && vms->oldmessages) {
9792 if (vms->oldmessages == 1)
9793 res = ast_play_and_wait(chan, "digits/1F");
9794 else
9795 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
9796 if (!res)
9797 res = ast_play_and_wait(chan, "vm-Old");
9798 if (!res) {
9799 if (vms->oldmessages == 1)
9800 res = ast_play_and_wait(chan, "vm-message");
9801 else
9802 res = ast_play_and_wait(chan, "vm-messages");
9803 }
9804 }
9805 if (!res) {
9806 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
9807 res = ast_play_and_wait(chan, "vm-no");
9808 if (!res)
9809 res = ast_play_and_wait(chan, "vm-messages");
9810 }
9811 }
9812 }
9813 return res;
9814}
9815
9816/* SPANISH syntax */
9817static int vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
9818{
9819 /* Introduce messages they have */
9820 int res;
9821 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
9822 res = ast_play_and_wait(chan, "vm-youhaveno");
9823 if (!res)
9824 res = ast_play_and_wait(chan, "vm-messages");
9825 } else {
9826 res = ast_play_and_wait(chan, "vm-youhave");
9827 }
9828 if (!res) {
9829 if (vms->newmessages) {
9830 if (!res) {
9831 if (vms->newmessages == 1) {
9832 res = ast_play_and_wait(chan, "digits/1M");
9833 if (!res)
9834 res = ast_play_and_wait(chan, "vm-message");
9835 if (!res)
9836 res = ast_play_and_wait(chan, "vm-INBOXs");
9837 } else {
9838 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
9839 if (!res)
9840 res = ast_play_and_wait(chan, "vm-messages");
9841 if (!res)
9842 res = ast_play_and_wait(chan, "vm-INBOX");
9843 }
9844 }
9845 if (vms->oldmessages && !res)
9846 res = ast_play_and_wait(chan, "vm-and");
9847 }
9848 if (vms->oldmessages) {
9849 if (!res) {
9850 if (vms->oldmessages == 1) {
9851 res = ast_play_and_wait(chan, "digits/1M");
9852 if (!res)
9853 res = ast_play_and_wait(chan, "vm-message");
9854 if (!res)
9855 res = ast_play_and_wait(chan, "vm-Olds");
9856 } else {
9857 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
9858 if (!res)
9859 res = ast_play_and_wait(chan, "vm-messages");
9860 if (!res)
9861 res = ast_play_and_wait(chan, "vm-Old");
9862 }
9863 }
9864 }
9865 }
9866return res;
9867}
9868
9869/* BRAZILIAN PORTUGUESE syntax */
9870static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms) {
9871 /* Introduce messages they have */
9872 int res;
9873 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
9874 res = ast_play_and_wait(chan, "vm-nomessages");
9875 return res;
9876 } else {
9877 res = ast_play_and_wait(chan, "vm-youhave");
9878 }
9879 if (vms->newmessages) {
9880 if (!res)
9881 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), "f");
9882 if (vms->newmessages == 1) {
9883 if (!res)
9884 res = ast_play_and_wait(chan, "vm-message");
9885 if (!res)
9886 res = ast_play_and_wait(chan, "vm-INBOXs");
9887 } else {
9888 if (!res)
9889 res = ast_play_and_wait(chan, "vm-messages");
9890 if (!res)
9891 res = ast_play_and_wait(chan, "vm-INBOX");
9892 }
9893 if (vms->oldmessages && !res)
9894 res = ast_play_and_wait(chan, "vm-and");
9895 }
9896 if (vms->oldmessages) {
9897 if (!res)
9898 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), "f");
9899 if (vms->oldmessages == 1) {
9900 if (!res)
9901 res = ast_play_and_wait(chan, "vm-message");
9902 if (!res)
9903 res = ast_play_and_wait(chan, "vm-Olds");
9904 } else {
9905 if (!res)
9906 res = ast_play_and_wait(chan, "vm-messages");
9907 if (!res)
9908 res = ast_play_and_wait(chan, "vm-Old");
9909 }
9910 }
9911 return res;
9912}
9913
9914/* FRENCH syntax */
9915static int vm_intro_fr(struct ast_channel *chan, struct vm_state *vms)
9916{
9917 /* Introduce messages they have */
9918 int res;
9919 res = ast_play_and_wait(chan, "vm-youhave");
9920 if (!res) {
9921 if (vms->newmessages) {
9922 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
9923 if (!res)
9924 res = ast_play_and_wait(chan, "vm-INBOX");
9925 if (vms->oldmessages && !res)
9926 res = ast_play_and_wait(chan, "vm-and");
9927 else if (!res) {
9928 if (vms->newmessages == 1)
9929 res = ast_play_and_wait(chan, "vm-message");
9930 else
9931 res = ast_play_and_wait(chan, "vm-messages");
9932 }
9933
9934 }
9935 if (!res && vms->oldmessages) {
9936 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
9937 if (!res)
9938 res = ast_play_and_wait(chan, "vm-Old");
9939 if (!res) {
9940 if (vms->oldmessages == 1)
9941 res = ast_play_and_wait(chan, "vm-message");
9942 else
9943 res = ast_play_and_wait(chan, "vm-messages");
9944 }
9945 }
9946 if (!res) {
9947 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
9948 res = ast_play_and_wait(chan, "vm-no");
9949 if (!res)
9950 res = ast_play_and_wait(chan, "vm-messages");
9951 }
9952 }
9953 }
9954 return res;
9955}
9956
9957/* DUTCH syntax */
9958static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
9959{
9960 /* Introduce messages they have */
9961 int res;
9962 res = ast_play_and_wait(chan, "vm-youhave");
9963 if (!res) {
9964 if (vms->newmessages) {
9965 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
9966 if (!res) {
9967 if (vms->newmessages == 1)
9968 res = ast_play_and_wait(chan, "vm-INBOXs");
9969 else
9970 res = ast_play_and_wait(chan, "vm-INBOX");
9971 }
9972 if (vms->oldmessages && !res)
9973 res = ast_play_and_wait(chan, "vm-and");
9974 else if (!res) {
9975 if (vms->newmessages == 1)
9976 res = ast_play_and_wait(chan, "vm-message");
9977 else
9978 res = ast_play_and_wait(chan, "vm-messages");
9979 }
9980
9981 }
9982 if (!res && vms->oldmessages) {
9983 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
9984 if (!res) {
9985 if (vms->oldmessages == 1)
9986 res = ast_play_and_wait(chan, "vm-Olds");
9987 else
9988 res = ast_play_and_wait(chan, "vm-Old");
9989 }
9990 if (!res) {
9991 if (vms->oldmessages == 1)
9992 res = ast_play_and_wait(chan, "vm-message");
9993 else
9994 res = ast_play_and_wait(chan, "vm-messages");
9995 }
9996 }
9997 if (!res) {
9998 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
9999 res = ast_play_and_wait(chan, "vm-no");
10000 if (!res)
10001 res = ast_play_and_wait(chan, "vm-messages");
10002 }
10003 }
10004 }
10005 return res;
10006}
10007
10008/* PORTUGUESE syntax */
10009static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
10010{
10011 /* Introduce messages they have */
10012 int res;
10013 res = ast_play_and_wait(chan, "vm-youhave");
10014 if (!res) {
10015 if (vms->newmessages) {
10016 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), "f");
10017 if (!res) {
10018 if (vms->newmessages == 1) {
10019 res = ast_play_and_wait(chan, "vm-message");
10020 if (!res)
10021 res = ast_play_and_wait(chan, "vm-INBOXs");
10022 } else {
10023 res = ast_play_and_wait(chan, "vm-messages");
10024 if (!res)
10025 res = ast_play_and_wait(chan, "vm-INBOX");
10026 }
10027 }
10028 if (vms->oldmessages && !res)
10029 res = ast_play_and_wait(chan, "vm-and");
10030 }
10031 if (!res && vms->oldmessages) {
10032 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), "f");
10033 if (!res) {
10034 if (vms->oldmessages == 1) {
10035 res = ast_play_and_wait(chan, "vm-message");
10036 if (!res)
10037 res = ast_play_and_wait(chan, "vm-Olds");
10038 } else {
10039 res = ast_play_and_wait(chan, "vm-messages");
10040 if (!res)
10041 res = ast_play_and_wait(chan, "vm-Old");
10042 }
10043 }
10044 }
10045 if (!res) {
10046 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10047 res = ast_play_and_wait(chan, "vm-no");
10048 if (!res)
10049 res = ast_play_and_wait(chan, "vm-messages");
10050 }
10051 }
10052 }
10053 return res;
10054}
10055
10056
10057/* CZECH syntax */
10058/* in czech there must be declension of word new and message
10059 * czech : english : czech : english
10060 * --------------------------------------------------------
10061 * vm-youhave : you have
10062 * vm-novou : one new : vm-zpravu : message
10063 * vm-nove : 2-4 new : vm-zpravy : messages
10064 * vm-novych : 5-infinite new : vm-zprav : messages
10065 * vm-starou : one old
10066 * vm-stare : 2-4 old
10067 * vm-starych : 5-infinite old
10068 * jednu : one - falling 4.
10069 * vm-no : no ( no messages )
10070 */
10071
10072static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
10073{
10074 int res;
10075 res = ast_play_and_wait(chan, "vm-youhave");
10076 if (!res) {
10077 if (vms->newmessages) {
10078 if (vms->newmessages == 1) {
10079 res = ast_play_and_wait(chan, "digits/jednu");
10080 } else {
10081 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10082 }
10083 if (!res) {
10084 if (vms->newmessages == 1)
10085 res = ast_play_and_wait(chan, "vm-novou");
10086 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
10087 res = ast_play_and_wait(chan, "vm-nove");
10088 if (vms->newmessages > 4)
10089 res = ast_play_and_wait(chan, "vm-novych");
10090 }
10091 if (vms->oldmessages && !res)
10092 res = ast_play_and_wait(chan, "vm-and");
10093 else if (!res) {
10094 if (vms->newmessages == 1)
10095 res = ast_play_and_wait(chan, "vm-zpravu");
10096 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
10097 res = ast_play_and_wait(chan, "vm-zpravy");
10098 if (vms->newmessages > 4)
10099 res = ast_play_and_wait(chan, "vm-zprav");
10100 }
10101 }
10102 if (!res && vms->oldmessages) {
10103 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10104 if (!res) {
10105 if (vms->oldmessages == 1)
10106 res = ast_play_and_wait(chan, "vm-starou");
10107 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
10108 res = ast_play_and_wait(chan, "vm-stare");
10109 if (vms->oldmessages > 4)
10110 res = ast_play_and_wait(chan, "vm-starych");
10111 }
10112 if (!res) {
10113 if (vms->oldmessages == 1)
10114 res = ast_play_and_wait(chan, "vm-zpravu");
10115 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
10116 res = ast_play_and_wait(chan, "vm-zpravy");
10117 if (vms->oldmessages > 4)
10118 res = ast_play_and_wait(chan, "vm-zprav");
10119 }
10120 }
10121 if (!res) {
10122 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10123 res = ast_play_and_wait(chan, "vm-no");
10124 if (!res)
10125 res = ast_play_and_wait(chan, "vm-zpravy");
10126 }
10127 }
10128 }
10129 return res;
10130}
10131
10132/* CHINESE (Taiwan) syntax */
10133static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
10134{
10135 int res;
10136 /* Introduce messages they have */
10137 res = ast_play_and_wait(chan, "vm-you");
10138
10139 if (!res && vms->newmessages) {
10140 res = ast_play_and_wait(chan, "vm-have");
10141 if (!res)
10142 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10143 if (!res)
10144 res = ast_play_and_wait(chan, "vm-tong");
10145 if (!res)
10146 res = ast_play_and_wait(chan, "vm-INBOX");
10147 if (vms->oldmessages && !res)
10148 res = ast_play_and_wait(chan, "vm-and");
10149 else if (!res)
10150 res = ast_play_and_wait(chan, "vm-messages");
10151 }
10152 if (!res && vms->oldmessages) {
10153 res = ast_play_and_wait(chan, "vm-have");
10154 if (!res)
10155 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10156 if (!res)
10157 res = ast_play_and_wait(chan, "vm-tong");
10158 if (!res)
10159 res = ast_play_and_wait(chan, "vm-Old");
10160 if (!res)
10161 res = ast_play_and_wait(chan, "vm-messages");
10162 }
10163 if (!res && !vms->oldmessages && !vms->newmessages) {
10164 res = ast_play_and_wait(chan, "vm-haveno");
10165 if (!res)
10166 res = ast_play_and_wait(chan, "vm-messages");
10167 }
10168 return res;
10169}
10170
10171/* Vietnamese syntax */
10172static int vm_intro_vi(struct ast_channel *chan, struct vm_state *vms)
10173{
10174 int res;
10175
10176 /* Introduce messages they have */
10177 res = ast_play_and_wait(chan, "vm-youhave");
10178 if (!res) {
10179 if (vms->newmessages) {
10180 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10181 if (!res)
10182 res = ast_play_and_wait(chan, "vm-INBOX");
10183 if (vms->oldmessages && !res)
10184 res = ast_play_and_wait(chan, "vm-and");
10185 }
10186 if (!res && vms->oldmessages) {
10187 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10188 if (!res)
10189 res = ast_play_and_wait(chan, "vm-Old");
10190 }
10191 if (!res) {
10192 if (!vms->oldmessages && !vms->newmessages) {
10193 res = ast_play_and_wait(chan, "vm-no");
10194 if (!res)
10195 res = ast_play_and_wait(chan, "vm-message");
10196 }
10197 }
10198 }
10199 return res;
10200}
10201
10202static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
10203{
10204 char prefile[256];
10205
10206 /* Notify the user that the temp greeting is set and give them the option to remove it */
10207 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
10208 if (ast_test_flag(vmu, VM_TEMPGREETWARN)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 15))); })
) {
10209 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
10210 if (ast_fileexists(prefile, NULL((void*)0), NULL((void*)0)) > 0) {
10211 ast_play_and_wait(chan, "vm-tempgreetactive");
10212 }
10213 DISPOSE(prefile, -1);
10214 }
10215
10216 /* Play voicemail intro - syntax is different for different languages */
10217 if (0) {
10218 return 0;
10219 } else if (!strncasecmp(ast_channel_language(chan), "cs", 2)) { /* CZECH syntax */
10220 return vm_intro_cs(chan, vms);
10221 } else if (!strncasecmp(ast_channel_language(chan), "cz", 2)) { /* deprecated CZECH syntax */
10222 static int deprecation_warning = 0;
10223 if (deprecation_warning++ % 10 == 0) {
10224 ast_log(LOG_WARNING3, "app_voicemail.c", 10224, __PRETTY_FUNCTION__, "cz is not a standard language code. Please switch to using cs instead.\n");
10225 }
10226 return vm_intro_cs(chan, vms);
10227 } else if (!strncasecmp(ast_channel_language(chan), "de", 2)) { /* GERMAN syntax */
10228 return vm_intro_de(chan, vms);
10229 } else if (!strncasecmp(ast_channel_language(chan), "es", 2)) { /* SPANISH syntax */
10230 return vm_intro_es(chan, vms);
10231 } else if (!strncasecmp(ast_channel_language(chan), "fr", 2)) { /* FRENCH syntax */
10232 return vm_intro_fr(chan, vms);
10233 } else if (!strncasecmp(ast_channel_language(chan), "gr", 2)) { /* GREEK syntax */
10234 return vm_intro_gr(chan, vms);
10235 } else if (!strncasecmp(ast_channel_language(chan), "he", 2)) { /* HEBREW syntax */
10236 return vm_intro_he(chan, vms);
10237 } else if (!strncasecmp(ast_channel_language(chan), "is", 2)) { /* ICELANDIC syntax */
10238 return vm_intro_is(chan, vms);
10239 } else if (!strncasecmp(ast_channel_language(chan), "it", 2)) { /* ITALIAN syntax */
10240 return vm_intro_it(chan, vms);
10241 } else if (!strncasecmp(ast_channel_language(chan), "ja", 2)) { /* JAPANESE syntax */
10242 return vm_intro_ja(chan, vms);
10243 } else if (!strncasecmp(ast_channel_language(chan), "nl", 2)) { /* DUTCH syntax */
10244 return vm_intro_nl(chan, vms);
10245 } else if (!strncasecmp(ast_channel_language(chan), "no", 2)) { /* NORWEGIAN syntax */
10246 return vm_intro_no(chan, vms);
10247 } else if (!strncasecmp(ast_channel_language(chan), "pl", 2)) { /* POLISH syntax */
10248 return vm_intro_pl(chan, vms);
10249 } else if (!strncasecmp(ast_channel_language(chan), "pt_BR", 5)) { /* BRAZILIAN PORTUGUESE syntax */
10250 return vm_intro_pt_BR(chan, vms);
10251 } else if (!strncasecmp(ast_channel_language(chan), "pt", 2)) { /* PORTUGUESE syntax */
10252 return vm_intro_pt(chan, vms);
10253 } else if (!strncasecmp(ast_channel_language(chan), "ru", 2)) { /* RUSSIAN syntax */
10254 return vm_intro_multilang(chan, vms, "n");
10255 } else if (!strncasecmp(ast_channel_language(chan), "se", 2)) { /* SWEDISH syntax */
10256 return vm_intro_se(chan, vms);
10257 } else if (!strncasecmp(ast_channel_language(chan), "ua", 2)) { /* UKRAINIAN syntax */
10258 return vm_intro_multilang(chan, vms, "n");
10259 } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) { /* VIETNAMESE syntax */
10260 return vm_intro_vi(chan, vms);
10261 } else if (!strncasecmp(ast_channel_language(chan), "zh", 2)) { /* CHINESE (Taiwan) syntax */
10262 return vm_intro_zh(chan, vms);
10263 } else { /* Default to ENGLISH */
10264 return vm_intro_en(chan, vms);
10265 }
10266}
10267
10268static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
10269{
10270 int res = 0;
10271 /* Play instructions and wait for new command */
10272 while (!res) {
10273 if (vms->starting) {
10274 if (vms->lastmsg > -1) {
10275 if (skipadvanced)
10276 res = ast_play_and_wait(chan, "vm-onefor-full");
10277 else
10278 res = ast_play_and_wait(chan, "vm-onefor");
10279 if (!res)
10280 res = vm_play_folder_name(chan, vms->vmbox);
10281 }
10282 if (!res) {
10283 if (skipadvanced)
10284 res = ast_play_and_wait(chan, "vm-opts-full");
10285 else
10286 res = ast_play_and_wait(chan, "vm-opts");
10287 }
10288 } else {
10289 /* Added for additional help */
10290 if (skipadvanced) {
10291 res = ast_play_and_wait(chan, "vm-onefor-full");
10292 if (!res)
10293 res = vm_play_folder_name(chan, vms->vmbox);
10294 res = ast_play_and_wait(chan, "vm-opts-full");
10295 }
10296 /* Logic:
10297 * If the current message is not the first OR
10298 * if we're listening to the first new message and there are
10299 * also urgent messages, then prompt for navigation to the
10300 * previous message
10301 */
10302 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 17))); })
&& vms->lastmsg > 0)) {
10303 res = ast_play_and_wait(chan, "vm-prev");
10304 }
10305 if (!res && !skipadvanced)
10306 res = ast_play_and_wait(chan, "vm-advopts");
10307 if (!res)
10308 res = ast_play_and_wait(chan, "vm-repeat");
10309 /* Logic:
10310 * If we're not listening to the last message OR
10311 * we're listening to the last urgent message and there are
10312 * also new non-urgent messages, then prompt for navigation
10313 * to the next message
10314 */
10315 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
10316 (ast_test_flag(vmu, VM_MESSAGEWRAP)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 17))); })
&& vms->lastmsg > 0) )) {
10317 res = ast_play_and_wait(chan, "vm-next");
10318 }
10319 if (!res) {
10320 int curmsg_deleted;
10321#ifdef IMAP_STORAGE
10322 ast_mutex_lock(&vms->lock)__ast_pthread_mutex_lock("app_voicemail.c", 10322, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
10323#endif
10324 curmsg_deleted = vms->deleted[vms->curmsg];
10325#ifdef IMAP_STORAGE
10326 ast_mutex_unlock(&vms->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 10326, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
10327#endif
10328 if (!curmsg_deleted) {
10329 res = ast_play_and_wait(chan, "vm-delete");
10330 } else {
10331 res = ast_play_and_wait(chan, "vm-undelete");
10332 }
10333 if (!res) {
10334 res = ast_play_and_wait(chan, "vm-toforward");
10335 }
10336 if (!res) {
10337 res = ast_play_and_wait(chan, "vm-savemessage");
10338 }
10339 }
10340 }
10341 if (!res) {
10342 res = ast_play_and_wait(chan, "vm-helpexit");
10343 }
10344 if (!res)
10345 res = ast_waitfordigit(chan, 6000);
10346 if (!res) {
10347 vms->repeats++;
10348 if (vms->repeats > 2) {
10349 res = 't';
10350 }
10351 }
10352 }
10353 return res;
10354}
10355
10356static int vm_instructions_ja(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
10357{
10358 int res = 0;
10359 /* Play instructions and wait for new command */
10360 while (!res) {
10361 if (vms->starting) {
10362 if (vms->lastmsg > -1) {
10363 res = vm_play_folder_name(chan, vms->vmbox);
10364 if (!res)
10365 res = ast_play_and_wait(chan, "jp-wa");
10366 if (!res)
10367 res = ast_play_and_wait(chan, "digits/1");
10368 if (!res)
10369 res = ast_play_and_wait(chan, "jp-wo");
10370 if (!res)
10371 res = ast_play_and_wait(chan, "silence/1");
10372 }
10373 if (!res)
10374 res = ast_play_and_wait(chan, "vm-opts");
10375 } else {
10376 /* Added for additional help */
10377 if (skipadvanced) {
10378 res = vm_play_folder_name(chan, vms->vmbox);
10379 if (!res)
10380 res = ast_play_and_wait(chan, "jp-wa");
10381 if (!res)
10382 res = ast_play_and_wait(chan, "digits/1");
10383 if (!res)
10384 res = ast_play_and_wait(chan, "jp-wo");
10385 if (!res)
10386 res = ast_play_and_wait(chan, "silence/1");
10387 res = ast_play_and_wait(chan, "vm-opts-full");
10388 }
10389 /* Logic:
10390 * If the current message is not the first OR
10391 * if we're listening to the first new message and there are
10392 * also urgent messages, then prompt for navigation to the
10393 * previous message
10394 */
10395 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 17))); })
&& vms->lastmsg > 0)) {
10396 res = ast_play_and_wait(chan, "vm-prev");
10397 }
10398 if (!res && !skipadvanced)
10399 res = ast_play_and_wait(chan, "vm-advopts");
10400 if (!res)
10401 res = ast_play_and_wait(chan, "vm-repeat");
10402 /* Logic:
10403 * If we're not listening to the last message OR
10404 * we're listening to the last urgent message and there are
10405 * also new non-urgent messages, then prompt for navigation
10406 * to the next message
10407 */
10408 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
10409 (ast_test_flag(vmu, VM_MESSAGEWRAP)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 17))); })
&& vms->lastmsg > 0) )) {
10410 res = ast_play_and_wait(chan, "vm-next");
10411 }
10412 if (!res) {
10413 int curmsg_deleted;
10414#ifdef IMAP_STORAGE
10415 ast_mutex_lock(&vms->lock)__ast_pthread_mutex_lock("app_voicemail.c", 10415, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
10416#endif
10417 curmsg_deleted = vms->deleted[vms->curmsg];
10418#ifdef IMAP_STORAGE
10419 ast_mutex_unlock(&vms->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 10419, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
10420#endif
10421 if (!curmsg_deleted) {
10422 res = ast_play_and_wait(chan, "vm-delete");
10423 } else {
10424 res = ast_play_and_wait(chan, "vm-undelete");
10425 }
10426 if (!res) {
10427 res = ast_play_and_wait(chan, "vm-toforward");
10428 }
10429 if (!res) {
10430 res = ast_play_and_wait(chan, "vm-savemessage");
10431 }
10432 }
10433 }
10434
10435 if (!res) {
10436 res = ast_play_and_wait(chan, "vm-helpexit");
10437 }
10438 if (!res)
10439 res = ast_waitfordigit(chan, 6000);
10440 if (!res) {
10441 vms->repeats++;
10442 if (vms->repeats > 2) {
10443 res = 't';
10444 }
10445 }
10446
10447 }
10448
10449 return res;
10450}
10451
10452static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
10453{
10454 int res = 0;
10455 /* Play instructions and wait for new command */
10456 while (!res) {
10457 if (vms->lastmsg > -1) {
10458 res = ast_play_and_wait(chan, "vm-listen");
10459 if (!res)
10460 res = vm_play_folder_name(chan, vms->vmbox);
10461 if (!res)
10462 res = ast_play_and_wait(chan, "press");
10463 if (!res)
10464 res = ast_play_and_wait(chan, "digits/1");
10465 }
10466 if (!res)
10467 res = ast_play_and_wait(chan, "vm-opts");
10468 if (!res) {
10469 vms->starting = 0;
10470 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
10471 }
10472 }
10473 return res;
10474}
10475
10476static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
10477{
10478 if (!strncasecmp(ast_channel_language(chan), "ja", 2)) { /* Japanese syntax */
10479 return vm_instructions_ja(chan, vmu, vms, skipadvanced, in_urgent);
10480 } else if (vms->starting && !strncasecmp(ast_channel_language(chan), "zh", 2)) { /* CHINESE (Taiwan) syntax */
10481 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
10482 } else { /* Default to ENGLISH */
10483 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
10484 }
10485}
10486
10487
10488static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
10489{
10490 int cmd = 0;
10491 int duration = 0;
10492 int tries = 0;
10493 char newpassword[80] = "";
10494 char newpassword2[80] = "";
10495 char prefile[PATH_MAX4096] = "";
10496 unsigned char buf[256];
10497 int bytes = 0;
10498
10499 ast_test_suite_event_notify("NEWUSER", "Message: entering new user state");
10500 if (ast_adsi_available(chan)) {
10501 bytes += adsi_logo(buf + bytes);
10502 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 3, ADSI_JUST_CENT0x0, 0, "New User Setup", "");
10503 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 4, ADSI_JUST_CENT0x0, 0, "Not Done", "");
10504 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE0x1, 1);
10505 bytes += ast_adsi_voice_mode(buf + bytes, 0);
10506 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY132);
10507 }
10508
10509 /* If forcename is set, have the user record their name */
10510 if (ast_test_flag(vmu, VM_FORCENAME)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 7))); })
) {
10511 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
10512 if (ast_fileexists(prefile, NULL((void*)0), NULL((void*)0)) < 1) {
10513 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL((void*)0), NULL((void*)0), record_gain, vms, NULL((void*)0), NULL((void*)0), 0);
10514 if (cmd < 0 || cmd == 't' || cmd == '#')
10515 return cmd;
10516 }
10517 }
10518
10519 /* If forcegreetings is set, have the user record their greetings */
10520 if (ast_test_flag(vmu, VM_FORCEGREET)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 8))); })
) {
10521 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
10522 if (ast_fileexists(prefile, NULL((void*)0), NULL((void*)0)) < 1) {
10523 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL((void*)0), NULL((void*)0), record_gain, vms, NULL((void*)0), NULL((void*)0), 0);
10524 if (cmd < 0 || cmd == 't' || cmd == '#')
10525 return cmd;
10526 }
10527
10528 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
10529 if (ast_fileexists(prefile, NULL((void*)0), NULL((void*)0)) < 1) {
10530 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL((void*)0), NULL((void*)0), record_gain, vms, NULL((void*)0), NULL((void*)0), 0);
10531 if (cmd < 0 || cmd == 't' || cmd == '#')
10532 return cmd;
10533 }
10534 }
10535
10536 /*
10537 * Change the password last since new users will be able to skip over any steps this one comes before
10538 * by hanging up and calling back to voicemail main since the password is used to verify new user status.
10539 */
10540 for (;;) {
10541 newpassword[1] = '\0';
10542 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
10543 if (cmd == '#')
10544 newpassword[0] = '\0';
10545 if (cmd < 0 || cmd == 't' || cmd == '#')
10546 return cmd;
10547 cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
10548 if (cmd < 0 || cmd == 't' || cmd == '#')
10549 return cmd;
10550 cmd = check_password(vmu, newpassword); /* perform password validation */
10551 if (cmd != 0) {
10552 ast_log(AST_LOG_NOTICE2, "app_voicemail.c", 10552, __PRETTY_FUNCTION__, "Invalid password for user %s (%s)\n", vms->username, newpassword);
10553 cmd = ast_play_and_wait(chan, vm_invalid_password);
10554 } else {
10555 newpassword2[1] = '\0';
10556 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
10557 if (cmd == '#')
10558 newpassword2[0] = '\0';
10559 if (cmd < 0 || cmd == 't' || cmd == '#')
10560 return cmd;
10561 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
10562 if (cmd < 0 || cmd == 't' || cmd == '#')
10563 return cmd;
10564 if (!strcmp(newpassword, newpassword2))
10565 break;
10566 ast_log(AST_LOG_NOTICE2, "app_voicemail.c", 10566, __PRETTY_FUNCTION__, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
10567 cmd = ast_play_and_wait(chan, vm_mismatch);
10568 }
10569 if (++tries == 3)
10570 return -1;
10571 if (cmd != 0) {
10572 cmd = ast_play_and_wait(chan, vm_pls_try_again);
10573 }
10574 }
10575 if (pwdchange & PWDCHANGE_INTERNAL(1 << 1))
10576 vm_change_password(vmu, newpassword);
10577 if ((pwdchange & PWDCHANGE_EXTERNAL(1 << 2)) && !ast_strlen_zero(ext_pass_cmd)_ast_strlen_zero(ext_pass_cmd, "app_voicemail.c", __PRETTY_FUNCTION__
, 10577)
)
10578 vm_change_password_shell(vmu, newpassword);
10579
10580 ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int) strlen(newpassword))do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 10580, __PRETTY_FUNCTION__, "User %s set password to %s of length %d\n"
, vms->username, newpassword, (int) strlen(newpassword)); }
} while (0)
;
10581 cmd = ast_play_and_wait(chan, vm_passchanged);
10582
10583 return cmd;
10584}
10585
10586static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
10587{
10588 int cmd = 0;
10589 int retries = 0;
10590 int duration = 0;
10591 char newpassword[80] = "";
10592 char newpassword2[80] = "";
10593 char prefile[PATH_MAX4096] = "";
10594 unsigned char buf[256];
10595 int bytes = 0;
10596
10597 ast_test_suite_event_notify("VMOPTIONS", "Message: entering mailbox options");
10598 if (ast_adsi_available(chan)) {
10599 bytes += adsi_logo(buf + bytes);
10600 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 3, ADSI_JUST_CENT0x0, 0, "Options Menu", "");
10601 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 4, ADSI_JUST_CENT0x0, 0, "Not Done", "");
10602 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE0x1, 1);
10603 bytes += ast_adsi_voice_mode(buf + bytes, 0);
10604 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY132);
10605 }
10606 while ((cmd >= 0) && (cmd != 't')) {
10607 if (cmd)
10608 retries = 0;
10609 switch (cmd) {
10610 case '1': /* Record your unavailable message */
10611 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
10612 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL((void*)0), NULL((void*)0), record_gain, vms, NULL((void*)0), NULL((void*)0), 0);
10613 break;
10614 case '2': /* Record your busy message */
10615 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
10616 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL((void*)0), NULL((void*)0), record_gain, vms, NULL((void*)0), NULL((void*)0), 0);
10617 break;
10618 case '3': /* Record greeting */
10619 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
10620 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL((void*)0), NULL((void*)0), record_gain, vms, NULL((void*)0), NULL((void*)0), 0);
10621 break;
10622 case '4': /* manage the temporary greeting */
10623 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
10624 break;
10625 case '5': /* change password */
10626 if (vmu->password[0] == '-') {
10627 cmd = ast_play_and_wait(chan, "vm-no");
10628 break;
10629 }
10630 newpassword[1] = '\0';
10631 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
10632 if (cmd == '#')
10633 newpassword[0] = '\0';
10634 else {
10635 if (cmd < 0)
10636 break;
10637 if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
10638 break;
10639 }
10640 }
10641 cmd = check_password(vmu, newpassword); /* perform password validation */
10642 if (cmd != 0) {
10643 ast_log(AST_LOG_NOTICE2, "app_voicemail.c", 10643, __PRETTY_FUNCTION__, "Invalid password for user %s (%s)\n", vms->username, newpassword);
10644 cmd = ast_play_and_wait(chan, vm_invalid_password);
10645 if (!cmd) {
10646 cmd = ast_play_and_wait(chan, vm_pls_try_again);
10647 }
10648 break;
10649 }
10650 newpassword2[1] = '\0';
10651 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
10652 if (cmd == '#')
10653 newpassword2[0] = '\0';
10654 else {
10655 if (cmd < 0)
10656 break;
10657
10658 if ((cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#")) < 0) {
10659 break;
10660 }
10661 }
10662 if (strcmp(newpassword, newpassword2)) {
10663 ast_log(AST_LOG_NOTICE2, "app_voicemail.c", 10663, __PRETTY_FUNCTION__, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
10664 cmd = ast_play_and_wait(chan, vm_mismatch);
10665 if (!cmd) {
10666 cmd = ast_play_and_wait(chan, vm_pls_try_again);
10667 }
10668 break;
10669 }
10670
10671 if (pwdchange & PWDCHANGE_INTERNAL(1 << 1)) {
10672 vm_change_password(vmu, newpassword);
10673 }
10674 if ((pwdchange & PWDCHANGE_EXTERNAL(1 << 2)) && !ast_strlen_zero(ext_pass_cmd)_ast_strlen_zero(ext_pass_cmd, "app_voicemail.c", __PRETTY_FUNCTION__
, 10674)
) {
10675 vm_change_password_shell(vmu, newpassword);
10676 }
10677
10678 ast_debug(1, "User %s set password to %s of length %d\n",do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 10679, __PRETTY_FUNCTION__, "User %s set password to %s of length %d\n"
, vms->username, newpassword, (int) strlen(newpassword)); }
} while (0)
10679 vms->username, newpassword, (int) strlen(newpassword))do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 10679, __PRETTY_FUNCTION__, "User %s set password to %s of length %d\n"
, vms->username, newpassword, (int) strlen(newpassword)); }
} while (0)
;
10680 cmd = ast_play_and_wait(chan, vm_passchanged);
10681 break;
10682 case '*':
10683 cmd = 't';
10684 break;
10685 default:
10686 cmd = 0;
10687 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
10688 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
10689 if (ast_fileexists(prefile, NULL((void*)0), NULL((void*)0))) {
10690 cmd = ast_play_and_wait(chan, "vm-tmpexists");
10691 }
10692 DISPOSE(prefile, -1);
10693 if (!cmd) {
10694 cmd = ast_play_and_wait(chan, "vm-options");
10695 }
10696 if (!cmd) {
10697 cmd = ast_waitfordigit(chan, 6000);
10698 }
10699 if (!cmd) {
10700 retries++;
10701 }
10702 if (retries > 3) {
10703 cmd = 't';
10704 }
10705 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10706 }
10707 }
10708 if (cmd == 't')
10709 cmd = 0;
10710 return cmd;
10711}
10712
10713/*!
10714 * \brief The handler for 'record a temporary greeting'.
10715 * \param chan
10716 * \param vmu
10717 * \param vms
10718 * \param fmtc
10719 * \param record_gain
10720 *
10721 * This is option 4 from the mailbox options menu.
10722 * This function manages the following promptings:
10723 * 1: play / record / review the temporary greeting. : invokes play_record_review().
10724 * 2: remove (delete) the temporary greeting.
10725 * *: return to the main menu.
10726 *
10727 * \return zero on success, -1 on error.
10728 */
10729static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
10730{
10731 int cmd = 0;
10732 int retries = 0;
10733 int duration = 0;
10734 char prefile[PATH_MAX4096] = "";
10735 unsigned char buf[256];
10736 int bytes = 0;
10737
10738 if (ast_adsi_available(chan)) {
10739 bytes += adsi_logo(buf + bytes);
10740 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 3, ADSI_JUST_CENT0x0, 0, "Temp Greeting Menu", "");
10741 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE0x1, 4, ADSI_JUST_CENT0x0, 0, "Not Done", "");
10742 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE0x1, 1);
10743 bytes += ast_adsi_voice_mode(buf + bytes, 0);
10744 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY132);
10745 }
10746
10747 ast_test_suite_event_notify("TEMPGREETING", "Message: entering temp greeting options");
10748 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
10749 while ((cmd >= 0) && (cmd != 't')) {
10750 if (cmd)
10751 retries = 0;
10752 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
10753 if (ast_fileexists(prefile, NULL((void*)0), NULL((void*)0)) <= 0) {
10754 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL((void*)0), NULL((void*)0), record_gain, vms, NULL((void*)0), NULL((void*)0), 0);
10755 if (cmd == -1) {
10756 break;
10757 }
10758 cmd = 't';
10759 } else {
10760 switch (cmd) {
10761 case '1':
10762 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL((void*)0), NULL((void*)0), record_gain, vms, NULL((void*)0), NULL((void*)0), 0);
10763 break;
10764 case '2':
10765 DELETE(prefile, -1, prefile, vmu)(vm_delete(prefile));
10766 ast_play_and_wait(chan, "vm-tempremoved");
10767 cmd = 't';
10768 break;
10769 case '*':
10770 cmd = 't';
10771 break;
10772 default:
10773 cmd = ast_play_and_wait(chan,
10774 ast_fileexists(prefile, NULL((void*)0), NULL((void*)0)) > 0 ? /* XXX always true ? */
10775 "vm-tempgreeting2" : "vm-tempgreeting");
10776 if (!cmd) {
10777 cmd = ast_waitfordigit(chan, 6000);
10778 }
10779 if (!cmd) {
10780 retries++;
10781 }
10782 if (retries > 3) {
10783 cmd = 't';
10784 }
10785 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10786 }
10787 }
10788 DISPOSE(prefile, -1);
10789 }
10790 if (cmd == 't')
10791 cmd = 0;
10792 return cmd;
10793}
10794
10795/*!
10796 * \brief Greek syntax for 'You have N messages' greeting.
10797 * \param chan
10798 * \param vms
10799 * \param vmu
10800 *
10801 * \return zero on success, -1 on error.
10802 */
10803static int vm_browse_messages_gr(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
10804{
10805 int cmd = 0;
10806
10807 if (vms->lastmsg > -1) {
10808 cmd = play_message(chan, vmu, vms);
10809 } else {
10810 cmd = ast_play_and_wait(chan, "vm-youhaveno");
10811 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
10812 if (!cmd) {
10813 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
10814 cmd = ast_play_and_wait(chan, vms->fn);
10815 }
10816 if (!cmd)
10817 cmd = ast_play_and_wait(chan, "vm-messages");
10818 } else {
10819 if (!cmd)
10820 cmd = ast_play_and_wait(chan, "vm-messages");
10821 if (!cmd) {
10822 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
10823 cmd = ast_play_and_wait(chan, vms->fn);
10824 }
10825 }
10826 }
10827 return cmd;
10828}
10829
10830/* Hebrew Syntax */
10831static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
10832{
10833 int cmd = 0;
10834
10835 if (vms->lastmsg > -1) {
10836 cmd = play_message(chan, vmu, vms);
10837 } else {
10838 if (!strcasecmp(vms->fn, "INBOX")) {
10839 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
10840 } else {
10841 cmd = ast_play_and_wait(chan, "vm-nomessages");
10842 }
10843 }
10844 return cmd;
10845}
10846
10847/*!
10848 * \brief Default English syntax for 'You have N messages' greeting.
10849 * \param chan
10850 * \param vms
10851 * \param vmu
10852 *
10853 * \return zero on success, -1 on error.
10854 */
10855static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
10856{
10857 int cmd = 0;
10858
10859 if (vms->lastmsg > -1) {
10860 cmd = play_message(chan, vmu, vms);
10861 } else {
10862 cmd = ast_play_and_wait(chan, "vm-youhave");
10863 if (!cmd)
10864 cmd = ast_play_and_wait(chan, "vm-no");
10865 if (!cmd) {
10866 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
10867 cmd = ast_play_and_wait(chan, vms->fn);
10868 }
10869 if (!cmd)
10870 cmd = ast_play_and_wait(chan, "vm-messages");
10871 }
10872 return cmd;
10873}
10874
10875/*!
10876 *\brief Italian syntax for 'You have N messages' greeting.
10877 * \param chan
10878 * \param vms
10879 * \param vmu
10880 *
10881 * \return zero on success, -1 on error.
10882 */
10883static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
10884{
10885 int cmd;
10886
10887 if (vms->lastmsg > -1) {
10888 cmd = play_message(chan, vmu, vms);
10889 } else {
10890 cmd = ast_play_and_wait(chan, "vm-no");
10891 if (!cmd)
10892 cmd = ast_play_and_wait(chan, "vm-message");
10893 if (!cmd) {
10894 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
10895 cmd = ast_play_and_wait(chan, vms->fn);
10896 }
10897 }
10898 return cmd;
10899}
10900
10901/*!
10902 * \brief Japanese syntax for 'You have N messages' greeting.
10903 * \param chan
10904 * \param vms
10905 * \param vmu
10906 *
10907 * \return zero on success, -1 on error.
10908 */
10909static int vm_browse_messages_ja(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
10910{
10911 int cmd = 0;
10912
10913 if (vms->lastmsg > -1) {
10914 cmd = play_message(chan, vmu, vms);
10915 } else {
10916 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
10917 cmd = ast_play_and_wait(chan, vms->fn);
10918 if (!cmd)
10919 cmd = ast_play_and_wait(chan, "vm-messages");
10920 if (!cmd)
10921 cmd = ast_play_and_wait(chan, "jp-wa");
10922 if (!cmd)
10923 cmd = ast_play_and_wait(chan, "jp-arimasen");
10924 }
10925 return cmd;
10926}
10927
10928/*!
10929 * \brief Spanish syntax for 'You have N messages' greeting.
10930 * \param chan
10931 * \param vms
10932 * \param vmu
10933 *
10934 * \return zero on success, -1 on error.
10935 */
10936static int vm_browse_messages_es(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
10937{
10938 int cmd;
10939
10940 if (vms->lastmsg > -1) {
10941 cmd = play_message(chan, vmu, vms);
10942 } else {
10943 cmd = ast_play_and_wait(chan, "vm-youhaveno");
10944 if (!cmd)
10945 cmd = ast_play_and_wait(chan, "vm-messages");
10946 if (!cmd) {
10947 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
10948 cmd = ast_play_and_wait(chan, vms->fn);
10949 }
10950 }
10951 return cmd;
10952}
10953
10954/*!
10955 * \brief Portuguese syntax for 'You have N messages' greeting.
10956 * \param chan
10957 * \param vms
10958 * \param vmu
10959 *
10960 * \return zero on success, -1 on error.
10961 */
10962static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
10963{
10964 int cmd;
10965
10966 if (vms->lastmsg > -1) {
10967 cmd = play_message(chan, vmu, vms);
10968 } else {
10969 cmd = ast_play_and_wait(chan, "vm-no");
10970 if (!cmd) {
10971 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
10972 cmd = ast_play_and_wait(chan, vms->fn);
10973 }
10974 if (!cmd)
10975 cmd = ast_play_and_wait(chan, "vm-messages");
10976 }
10977 return cmd;
10978}
10979
10980/*!
10981 * \brief Chinese (Taiwan)syntax for 'You have N messages' greeting.
10982 * \param chan
10983 * \param vms
10984 * \param vmu
10985 *
10986 * \return zero on success, -1 on error.
10987 */
10988static int vm_browse_messages_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
10989{
10990 int cmd;
10991
10992 if (vms->lastmsg > -1) {
10993 cmd = play_message(chan, vmu, vms);
10994 } else {
10995 cmd = ast_play_and_wait(chan, "vm-you");
10996 if (!cmd)
10997 cmd = ast_play_and_wait(chan, "vm-haveno");
10998 if (!cmd)
10999 cmd = ast_play_and_wait(chan, "vm-messages");
11000 if (!cmd) {
11001 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
11002 cmd = ast_play_and_wait(chan, vms->fn);
11003 }
11004 }
11005 return cmd;
11006}
11007
11008/*!
11009 * \brief Vietnamese syntax for 'You have N messages' greeting.
11010 * \param chan
11011 * \param vms
11012 * \param vmu
11013 *
11014 * \return zero on success, -1 on error.
11015 */
11016static int vm_browse_messages_vi(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
11017{
11018 int cmd = 0;
11019
11020 if (vms->lastmsg > -1) {
11021 cmd = play_message(chan, vmu, vms);
11022 } else {
11023 cmd = ast_play_and_wait(chan, "vm-no");
11024 if (!cmd) {
11025 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
11026 cmd = ast_play_and_wait(chan, vms->fn);
11027 }
11028 }
11029 return cmd;
11030}
11031
11032/*!
11033 * \brief Top level method to invoke the language variant vm_browse_messages_XX function.
11034 * \param chan The channel for the current user. We read the language property from this.
11035 * \param vms passed into the language-specific vm_browse_messages function.
11036 * \param vmu passed into the language-specific vm_browse_messages function.
11037 *
11038 * The method to be invoked is determined by the value of language code property in the user's channel.
11039 * The default (when unable to match) is to use english.
11040 *
11041 * \return zero on success, -1 on error.
11042 */
11043static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
11044{
11045 if (!strncasecmp(ast_channel_language(chan), "es", 2)) { /* SPANISH */
11046 return vm_browse_messages_es(chan, vms, vmu);
11047 } else if (!strncasecmp(ast_channel_language(chan), "gr", 2)) { /* GREEK */
11048 return vm_browse_messages_gr(chan, vms, vmu);
11049 } else if (!strncasecmp(ast_channel_language(chan), "he", 2)) { /* HEBREW */
11050 return vm_browse_messages_he(chan, vms, vmu);
11051 } else if (!strncasecmp(ast_channel_language(chan), "it", 2)) { /* ITALIAN */
11052 return vm_browse_messages_it(chan, vms, vmu);
11053 } else if (!strncasecmp(ast_channel_language(chan), "ja", 2)) { /* JAPANESE */
11054 return vm_browse_messages_ja(chan, vms, vmu);
11055 } else if (!strncasecmp(ast_channel_language(chan), "pt", 2)) { /* PORTUGUESE */
11056 return vm_browse_messages_pt(chan, vms, vmu);
11057 } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) { /* VIETNAMESE */
11058 return vm_browse_messages_vi(chan, vms, vmu);
11059 } else if (!strncasecmp(ast_channel_language(chan), "zh", 2)) { /* CHINESE (Taiwan) */
11060 return vm_browse_messages_zh(chan, vms, vmu);
11061 } else { /* Default to English syntax */
11062 return vm_browse_messages_en(chan, vms, vmu);
11063 }
11064}
11065
11066static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
11067 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
11068 int skipuser, int max_logins, int silent)
11069{
11070 int useadsi = 0, valid = 0, logretries = 0;
11071 char password[AST_MAX_EXTENSION80]="", *passptr;
11072 struct ast_vm_user vmus, *vmu = NULL((void*)0);
11073
11074 /* If ADSI is supported, setup login screen */
11075 adsi_begin(chan, &useadsi);
11076 if (!skipuser && useadsi)
11077 adsi_login(chan);
11078 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", ast_channel_language(chan))) {
11079 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 11079, __PRETTY_FUNCTION__, "Couldn't stream login file\n");
11080 return -1;
11081 }
11082
11083 /* Authenticate them and get their mailbox/password */
11084
11085 while (!valid && (logretries < max_logins)) {
11086 /* Prompt for, and read in the username */
11087 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
11088 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 11088, __PRETTY_FUNCTION__, "Couldn't read username\n");
11089 return -1;
11090 }
11091 if (ast_strlen_zero(mailbox)_ast_strlen_zero(mailbox, "app_voicemail.c", __PRETTY_FUNCTION__
, 11091)
) {
11092 if (ast_channel_caller(chan)->id.number.valid && ast_channel_caller(chan)->id.number.str) {
11093 ast_copy_string(mailbox, ast_channel_caller(chan)->id.number.str, mailbox_size);
11094 } else {
11095 ast_verb(3, "Username not entered\n")do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 11095, __PRETTY_FUNCTION__, 3, "Username not entered\n"); }
} while (0)
;
11096 return -1;
11097 }
11098 } else if (mailbox[0] == '*') {
11099 /* user entered '*' */
11100 ast_verb(4, "Mailbox begins with '*', attempting jump to extension 'a'\n")do { if (((4) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 11100, __PRETTY_FUNCTION__, 4, "Mailbox begins with '*', attempting jump to extension 'a'\n"
); } } while (0)
;
11101 if (ast_exists_extension(chan, ast_channel_context(chan), "a", 1,
11102 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL)({typeof(&((ast_channel_caller(chan)->id.number.str)[0
])) __x = (ast_channel_caller(chan)->id.number.str); (ast_channel_caller
(chan)->id.number.valid) && !_ast_strlen_zero(__x,
"app_voicemail.c", __PRETTY_FUNCTION__, 11102) ? (__x) : (((
void*)0));})
)) {
11103 return -1;
11104 }
11105 ast_verb(4, "Jump to extension 'a' failed; setting mailbox to NULL\n")do { if (((4) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 11105, __PRETTY_FUNCTION__, 4, "Jump to extension 'a' failed; setting mailbox to NULL\n"
); } } while (0)
;
11106 mailbox[0] = '\0';
11107 }
11108
11109 if (useadsi)
11110 adsi_password(chan);
11111
11112 if (!ast_strlen_zero(prefix)_ast_strlen_zero(prefix, "app_voicemail.c", __PRETTY_FUNCTION__
, 11112)
) {
11113 char fullusername[80] = "";
11114 ast_copy_string(fullusername, prefix, sizeof(fullusername));
11115 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername))__builtin_strncat (fullusername, mailbox, sizeof(fullusername
) - 1 - strlen(fullusername))
;
11116 ast_copy_string(mailbox, fullusername, mailbox_size);
11117 }
11118
11119 ast_debug(1, "Before find user for mailbox %s\n", mailbox)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 11119, __PRETTY_FUNCTION__, "Before find user for mailbox %s\n"
, mailbox); } } while (0)
;
11120 memset(&vmus, 0, sizeof(vmus));
11121 vmu = find_user(&vmus, context, mailbox);
11122 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
11123 /* saved password is blank, so don't bother asking */
11124 password[0] = '\0';
11125 } else {
11126 if (ast_streamfile(chan, vm_password, ast_channel_language(chan))) {
11127 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 11127, __PRETTY_FUNCTION__, "Unable to stream password file\n");
11128 free_user(vmu);
11129 return -1;
11130 }
11131 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
11132 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 11132, __PRETTY_FUNCTION__, "Unable to read password\n");
11133 free_user(vmu);
11134 return -1;
11135 } else if (password[0] == '*') {
11136 /* user entered '*' */
11137 ast_verb(4, "Password begins with '*', attempting jump to extension 'a'\n")do { if (((4) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 11137, __PRETTY_FUNCTION__, 4, "Password begins with '*', attempting jump to extension 'a'\n"
); } } while (0)
;
11138 if (ast_exists_extension(chan, ast_channel_context(chan), "a", 1,
11139 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL)({typeof(&((ast_channel_caller(chan)->id.number.str)[0
])) __x = (ast_channel_caller(chan)->id.number.str); (ast_channel_caller
(chan)->id.number.valid) && !_ast_strlen_zero(__x,
"app_voicemail.c", __PRETTY_FUNCTION__, 11139) ? (__x) : (((
void*)0));})
)) {
11140 mailbox[0] = '*';
11141 free_user(vmu);
11142 return -1;
11143 }
11144 ast_verb(4, "Jump to extension 'a' failed; setting mailbox and user to NULL\n")do { if (((4) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 11144, __PRETTY_FUNCTION__, 4, "Jump to extension 'a' failed; setting mailbox and user to NULL\n"
); } } while (0)
;
11145 mailbox[0] = '\0';
11146 /* if the password entered was '*', do not let a user mailbox be created if the extension 'a' is not defined */
11147 free_user(vmu);
11148 vmu = NULL((void*)0);
11149 }
11150 }
11151
11152 if (vmu) {
11153 passptr = vmu->password;
11154 if (passptr[0] == '-') passptr++;
11155 }
11156 if (vmu && !strcmp(passptr, password))
11157 valid++;
11158 else {
11159 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default")do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 11159, __PRETTY_FUNCTION__, 3, "Incorrect password '%s' for user '%s' (context = %s)\n"
, password, mailbox, context ? context : "default"); } } while
(0)
;
11160 if (!ast_strlen_zero(prefix)_ast_strlen_zero(prefix, "app_voicemail.c", __PRETTY_FUNCTION__
, 11160)
)
11161 mailbox[0] = '\0';
11162 }
11163 logretries++;
11164 if (!valid) {
11165 if (skipuser || logretries >= max_logins) {
11166 if (ast_streamfile(chan, "vm-incorrect", ast_channel_language(chan))) {
11167 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 11167, __PRETTY_FUNCTION__, "Unable to stream incorrect message\n");
11168 free_user(vmu);
11169 return -1;
11170 }
11171 } else {
11172 if (useadsi)
11173 adsi_login(chan);
11174 if (ast_streamfile(chan, "vm-incorrect-mailbox", ast_channel_language(chan))) {
11175 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 11175, __PRETTY_FUNCTION__, "Unable to stream incorrect mailbox message\n");
11176 free_user(vmu);
11177 return -1;
11178 }
11179 }
11180 if (ast_waitstream(chan, "")) { /* Channel is hung up */
11181 free_user(vmu);
11182 return -1;
11183 }
11184 }
11185 }
11186 if (!valid && (logretries >= max_logins)) {
11187 ast_stopstream(chan);
11188 ast_play_and_wait(chan, "vm-goodbye");
11189 free_user(vmu);
11190 return -1;
11191 }
11192 if (vmu && !skipuser) {
11193 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
11194 }
11195 return 0;
11196}
11197
11198static int play_message_by_id_helper(struct ast_channel *chan,
11199 struct ast_vm_user *vmu,
11200 struct vm_state *vms,
11201 const char *msg_id)
11202{
11203 if (message_range_and_existence_check(vms, &msg_id, 1, &vms->curmsg, vmu)) {
11204 return -1;
11205 }
11206 /* Found the msg, so play it back */
11207
11208 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
11209 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
11210
11211#ifdef IMAP_STORAGE
11212 /*IMAP storage stores any prepended message from a forward
11213 * as a separate file from the rest of the message
11214 */
11215 if (!ast_strlen_zero(vms->introfn)_ast_strlen_zero(vms->introfn, "app_voicemail.c", __PRETTY_FUNCTION__
, 11215)
&& ast_fileexists(vms->introfn, NULL((void*)0), NULL((void*)0)) > 0) {
11216 wait_file(chan, vms, vms->introfn);
11217 }
11218#endif
11219 if ((wait_file(chan, vms, vms->fn)) < 0) {
11220 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 11220, __PRETTY_FUNCTION__, "Playback of message %s failed\n", vms->fn);
11221 } else {
11222#ifdef IMAP_STORAGE
11223 ast_mutex_lock(&vms->lock)__ast_pthread_mutex_lock("app_voicemail.c", 11223, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
11224#endif
11225 vms->heard[vms->curmsg] = 1;
11226#ifdef IMAP_STORAGE
11227 ast_mutex_unlock(&vms->lock)__ast_pthread_mutex_unlock("app_voicemail.c", 11227, __PRETTY_FUNCTION__
, "&vms->lock", &vms->lock)
;
11228#endif
11229 }
11230
11231 return 0;
11232}
11233
11234/*!
11235 * \brief Finds a message in a specific mailbox by msg_id and plays it to the channel
11236 *
11237 * \retval 0 Success
11238 * \retval -1 Failure
11239 */
11240static int play_message_by_id(struct ast_channel *chan, const char *mailbox, const char *context, const char *msg_id)
11241{
11242 struct vm_state vms;
11243 struct ast_vm_user *vmu = NULL((void*)0), vmus;
11244 int res = 0;
11245 int open = 0;
11246 int played = 0;
11247 int i;
11248
11249 memset(&vmus, 0, sizeof(vmus));
11250 memset(&vms, 0, sizeof(vms));
11251
11252 if (!(vmu = find_user(&vmus, context, mailbox))) {
11253 goto play_msg_cleanup;
11254 }
11255
11256 /* Iterate through every folder, find the msg, and play it */
11257 for (i = 0; i < ARRAY_LEN(mailbox_folders)(size_t) (sizeof(mailbox_folders) / sizeof(0[mailbox_folders]
))
&& !played; i++) {
11258 ast_copy_string(vms.username, mailbox, sizeof(vms.username));
11259 vms.lastmsg = -1;
11260
11261 /* open the mailbox state */
11262 if ((res = open_mailbox(&vms, vmu, i)) < 0) {
11263 ast_log(LOG_WARNING3, "app_voicemail.c", 11263, __PRETTY_FUNCTION__, "Could not open mailbox %s\n", mailbox);
11264 res = -1;
11265 goto play_msg_cleanup;
11266 }
11267 open = 1;
11268
11269 /* play msg if it exists in this mailbox */
11270 if ((vms.lastmsg != -1) && !(play_message_by_id_helper(chan, vmu, &vms, msg_id))) {
11271 played = 1;
11272 }
11273
11274 /* close mailbox */
11275 if ((res = close_mailbox(&vms, vmu) == ERROR_LOCK_PATH-100)) {
11276 res = -1;
11277 goto play_msg_cleanup;
11278 }
11279 open = 0;
11280 }
11281
11282play_msg_cleanup:
11283 if (!played) {
11284 res = -1;
11285 }
11286
11287 if (vmu && open) {
11288 close_mailbox(&vms, vmu);
11289 }
11290
11291#ifdef IMAP_STORAGE
11292 if (vmu) {
11293 vmstate_delete(&vms);
11294 }
11295#endif
11296
11297 free_user(vmu);
11298
11299 return res;
11300}
11301
11302static int vm_playmsgexec(struct ast_channel *chan, const char *data)
11303{
11304 char *parse;
11305 char *mailbox = NULL((void*)0);
11306 char *context = NULL((void*)0);
11307 int res;
11308
11309 AST_DECLARE_APP_ARGS(args,struct { unsigned int argc; char *argv[0]; char *mailbox; char
*msg_id; } args = { 0, }
11310 AST_APP_ARG(mailbox);struct { unsigned int argc; char *argv[0]; char *mailbox; char
*msg_id; } args = { 0, }
11311 AST_APP_ARG(msg_id);struct { unsigned int argc; char *argv[0]; char *mailbox; char
*msg_id; } args = { 0, }
11312 )struct { unsigned int argc; char *argv[0]; char *mailbox; char
*msg_id; } args = { 0, }
;
11313
11314 if (ast_channel_state(chan) != AST_STATE_UP) {
11315 ast_debug(1, "Before ast_answer\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 11315, __PRETTY_FUNCTION__, "Before ast_answer\n"
); } } while (0)
;
11316 ast_answer(chan);
11317 }
11318
11319 if (ast_strlen_zero(data)_ast_strlen_zero(data, "app_voicemail.c", __PRETTY_FUNCTION__
, 11319)
) {
11320 return -1;
11321 }
11322
11323 parse = ast_strdupa(data)(__extension__ ({ const char *__old = (data); size_t __len = strlen
(__old) + 1; char *__new = __builtin_alloca(__len); memcpy (__new
, __old, __len); __new; }))
;
11324 AST_STANDARD_APP_ARGS(args, parse)args.argc = __ast_app_separate_args(parse, ',', 1, args.argv,
((sizeof(args) - __builtin_offsetof(typeof(args), argv)) / sizeof
(args.argv[0])))
;
11325
11326 if (ast_strlen_zero(args.mailbox)_ast_strlen_zero(args.mailbox, "app_voicemail.c", __PRETTY_FUNCTION__
, 11326)
|| ast_strlen_zero(args.msg_id)_ast_strlen_zero(args.msg_id, "app_voicemail.c", __PRETTY_FUNCTION__
, 11326)
) {
11327 return -1;
11328 }
11329
11330 if ((context = strchr(args.mailbox, '@')(__extension__ (__builtin_constant_p ('@') && !__builtin_constant_p
(args.mailbox) && ('@') == '\0' ? (char *) __rawmemchr
(args.mailbox, '@') : __builtin_strchr (args.mailbox, '@')))
)) {
11331 *context++ = '\0';
11332 }
11333 mailbox = args.mailbox;
11334
11335 res = play_message_by_id(chan, mailbox, context, args.msg_id);
11336 pbx_builtin_setvar_helper(chan, "VOICEMAIL_PLAYBACKSTATUS", res ? "FAILED" : "SUCCESS");
11337
11338 return 0;
11339}
11340
11341static int vm_execmain(struct ast_channel *chan, const char *data)
11342{
11343 /* XXX This is, admittedly, some pretty horrendous code. For some
11344 reason it just seemed a lot easier to do with GOTO's. I feel
11345 like I'm back in my GWBASIC days. XXX */
11346 int res = -1;
11347 int cmd = 0;
11348 int valid = 0;
11349 char prefixstr[80] ="";
11350 char ext_context[256]="";
11351 int box;
11352 int useadsi = 0;
11353 int skipuser = 0;
11354 struct vm_state vms;
11355 struct ast_vm_user *vmu = NULL((void*)0), vmus;
11356 char *context = NULL((void*)0);
11357 int silentexit = 0;
11358 struct ast_flags flags = { 0 };
11359 signed char record_gain = 0;
11360 int play_auto = 0;
11361 int play_folder = 0;
11362 int in_urgent = 0;
11363#ifdef IMAP_STORAGE
11364 int deleted = 0;
11365#endif
11366
11367 /* Add the vm_state to the active list and keep it active */
11368 memset(&vms, 0, sizeof(vms));
11369
11370 vms.lastmsg = -1;
11371
11372 memset(&vmus, 0, sizeof(vmus));
11373
11374 ast_test_suite_event_notify("START", "Message: vm_execmain started");
11375 if (ast_channel_state(chan) != AST_STATE_UP) {
11376 ast_debug(1, "Before ast_answer\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 11376, __PRETTY_FUNCTION__, "Before ast_answer\n"
); } } while (0)
;
11377 ast_answer(chan);
11378 }
11379
11380 if (!ast_strlen_zero(data)_ast_strlen_zero(data, "app_voicemail.c", __PRETTY_FUNCTION__
, 11380)
) {
11381 char *opts[OPT_ARG_ARRAY_SIZE];
11382 char *parse;
11383 AST_DECLARE_APP_ARGS(args,struct { unsigned int argc; char *argv[0]; char *argv0; char *
argv1; } args = { 0, }
11384 AST_APP_ARG(argv0);struct { unsigned int argc; char *argv[0]; char *argv0; char *
argv1; } args = { 0, }
11385 AST_APP_ARG(argv1);struct { unsigned int argc; char *argv[0]; char *argv0; char *
argv1; } args = { 0, }
11386 )struct { unsigned int argc; char *argv[0]; char *argv0; char *
argv1; } args = { 0, }
;
11387
11388 parse = ast_strdupa(data)(__extension__ ({ const char *__old = (data); size_t __len = strlen
(__old) + 1; char *__new = __builtin_alloca(__len); memcpy (__new
, __old, __len); __new; }))
;
11389
11390 AST_STANDARD_APP_ARGS(args, parse)args.argc = __ast_app_separate_args(parse, ',', 1, args.argv,
((sizeof(args) - __builtin_offsetof(typeof(args), argv)) / sizeof
(args.argv[0])))
;
11391
11392 if (args.argc == 2) {
11393 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
11394 return -1;
11395 if (ast_test_flag(&flags, OPT_RECORDGAIN)({ typeof ((&flags)->flags) __p = (&flags)->flags
; typeof (__unsigned_int_flags_dummy) __x = 0; (void) (&__p
== &__x); ((&flags)->flags & (OPT_RECORDGAIN)
); })
) {
11396 int gain;
11397 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])_ast_strlen_zero(opts[OPT_ARG_RECORDGAIN], "app_voicemail.c",
__PRETTY_FUNCTION__, 11397)
) {
11398 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
11399 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 11399, __PRETTY_FUNCTION__, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
11400 return -1;
11401 } else {
11402 record_gain = (signed char) gain;
11403 }
11404 } else {
11405 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 11405, __PRETTY_FUNCTION__, "Invalid Gain level set with option g\n");
11406 }
11407 }
11408 if (ast_test_flag(&flags, OPT_AUTOPLAY)({ typeof ((&flags)->flags) __p = (&flags)->flags
; typeof (__unsigned_int_flags_dummy) __x = 0; (void) (&__p
== &__x); ((&flags)->flags & (OPT_AUTOPLAY));
})
) {
11409 play_auto = 1;
11410 if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])_ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER], "app_voicemail.c",
__PRETTY_FUNCTION__, 11410)
) {
11411 /* See if it is a folder name first */
11412 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])((*__ctype_b_loc ())[(int) ((opts[OPT_ARG_PLAYFOLDER][0]))] &
(unsigned short int) _ISdigit)
) {
11413 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
11414 play_folder = -1;
11415 }
11416 } else {
11417 play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
11418 }
11419 } else {
11420 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 11420, __PRETTY_FUNCTION__, "Invalid folder set with option a\n");
11421 }
11422 if (play_folder > 9 || play_folder < 0) {
11423 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 11423, __PRETTY_FUNCTION__,
11424 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
11425 opts[OPT_ARG_PLAYFOLDER]);
11426 play_folder = 0;
11427 }
11428 }
11429 } else {
11430 /* old style options parsing */
11431 while (*(args.argv0)) {
11432 if (*(args.argv0) == 's')
11433 ast_set_flag(&flags, OPT_SILENT)do { typeof ((&flags)->flags) __p = (&flags)->flags
; typeof (__unsigned_int_flags_dummy) __x = 0; (void) (&__p
== &__x); ((&flags)->flags |= (OPT_SILENT)); } while
(0)
;
11434 else if (*(args.argv0) == 'p')
11435 ast_set_flag(&flags, OPT_PREPEND_MAILBOX)do { typeof ((&flags)->flags) __p = (&flags)->flags
; typeof (__unsigned_int_flags_dummy) __x = 0; (void) (&__p
== &__x); ((&flags)->flags |= (OPT_PREPEND_MAILBOX
)); } while(0)
;
11436 else
11437 break;
11438 (args.argv0)++;
11439 }
11440
11441 }
11442
11443 valid = ast_test_flag(&flags, OPT_SILENT)({ typeof ((&flags)->flags) __p = (&flags)->flags
; typeof (__unsigned_int_flags_dummy) __x = 0; (void) (&__p
== &__x); ((&flags)->flags & (OPT_SILENT)); }
)
;
11444
11445 if ((context = strchr(args.argv0, '@')(__extension__ (__builtin_constant_p ('@') && !__builtin_constant_p
(args.argv0) && ('@') == '\0' ? (char *) __rawmemchr
(args.argv0, '@') : __builtin_strchr (args.argv0, '@')))
))
11446 *context++ = '\0';
11447
11448 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX)({ typeof ((&flags)->flags) __p = (&flags)->flags
; typeof (__unsigned_int_flags_dummy) __x = 0; (void) (&__p
== &__x); ((&flags)->flags & (OPT_PREPEND_MAILBOX
)); })
)
11449 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
11450 else
11451 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
11452
11453 if (!ast_strlen_zero(vms.username)_ast_strlen_zero(vms.username, "app_voicemail.c", __PRETTY_FUNCTION__
, 11453)
&& (vmu = find_user(&vmus, context ,vms.username)))
11454 skipuser++;
11455 else
11456 valid = 0;
11457 }
11458
11459 if (!valid)
11460 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
11461
11462 ast_debug(1, "After vm_authenticate\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 11462, __PRETTY_FUNCTION__, "After vm_authenticate\n"
); } } while (0)
;
11463
11464 if (vms.username[0] == '*') {
11465 ast_debug(1, "user pressed * in context '%s'\n", ast_channel_context(chan))do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 11465, __PRETTY_FUNCTION__, "user pressed * in context '%s'\n"
, ast_channel_context(chan)); } } while (0)
;
11466
11467 /* user entered '*' */
11468 if (!ast_goto_if_exists(chan, ast_channel_context(chan), "a", 1)) {
11469 ast_test_suite_event_notify("REDIRECT", "Message: redirecting user to 'a' extension");
11470 res = 0; /* prevent hangup */
11471 goto out;
11472 }
11473 }
11474
11475 if (!res) {
11476 valid = 1;
11477 if (!skipuser)
11478 vmu = &vmus;
11479 } else {
11480 res = 0;
11481 }
11482
11483 /* If ADSI is supported, setup login screen */
11484 adsi_begin(chan, &useadsi);
11485
11486 if (!valid) {
11487 goto out;
11488 }
11489 ast_test_suite_event_notify("AUTHENTICATED", "Message: vm_user authenticated");
11490
11491#ifdef IMAP_STORAGE
11492 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
11493 pthread_setspecific(ts_vmstate.key, &vms);
11494
11495 vms.interactive = 1;
11496 vms.updated = 1;
11497 if (vmu)
11498 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
11499 vmstate_insert(&vms);
11500 init_vm_state(&vms);
11501#endif
11502
11503 /* Set language from config to override channel language */
11504 if (!ast_strlen_zero(vmu->language)_ast_strlen_zero(vmu->language, "app_voicemail.c", __PRETTY_FUNCTION__
, 11504)
) {
11505 ast_channel_lock(chan)__ao2_lock(chan, AO2_LOCK_REQ_MUTEX, "app_voicemail.c", __PRETTY_FUNCTION__
, 11505, "chan")
;
11506 ast_channel_language_set(chan, vmu->language);
11507 ast_channel_unlock(chan)__ao2_unlock(chan, "app_voicemail.c", __PRETTY_FUNCTION__, 11507
, "chan")
;
11508 }
11509
11510 /* Retrieve urgent, old and new message counts */
11511 ast_debug(1, "Before open_mailbox\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 11511, __PRETTY_FUNCTION__, "Before open_mailbox\n"
); } } while (0)
;
11512 res = open_mailbox(&vms, vmu, OLD_FOLDER); /* Count all messages, even Urgent */
11513 if (res < 0)
11514 goto out;
11515 vms.oldmessages = vms.lastmsg + 1;
11516 ast_debug(1, "Number of old messages: %d\n", vms.oldmessages)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 11516, __PRETTY_FUNCTION__, "Number of old messages: %d\n"
, vms.oldmessages); } } while (0)
;
11517 /* check INBOX */
11518 res = open_mailbox(&vms, vmu, NEW_FOLDER);
11519 if (res < 0)
11520 goto out;
11521 vms.newmessages = vms.lastmsg + 1;
11522 ast_debug(1, "Number of new messages: %d\n", vms.newmessages)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 11522, __PRETTY_FUNCTION__, "Number of new messages: %d\n"
, vms.newmessages); } } while (0)
;
11523 /* Start in Urgent */
11524 in_urgent = 1;
11525 res = open_mailbox(&vms, vmu, 11); /*11 is the Urgent folder */
11526 if (res < 0)
11527 goto out;
11528 vms.urgentmessages = vms.lastmsg + 1;
11529 ast_debug(1, "Number of urgent messages: %d\n", vms.urgentmessages)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 11529, __PRETTY_FUNCTION__, "Number of urgent messages: %d\n"
, vms.urgentmessages); } } while (0)
;
11530
11531 /* Select proper mailbox FIRST!! */
11532 if (play_auto) {
11533 ast_test_suite_event_notify("AUTOPLAY", "Message: auto-playing messages");
11534 if (vms.urgentmessages) {
11535 in_urgent = 1;
11536 res = open_mailbox(&vms, vmu, 11);
11537 } else {
11538 in_urgent = 0;
11539 res = open_mailbox(&vms, vmu, play_folder);
11540 }
11541 if (res < 0)
11542 goto out;
11543
11544 /* If there are no new messages, inform the user and hangup */
11545 if (vms.lastmsg == -1) {
11546 in_urgent = 0;
11547 cmd = vm_browse_messages(chan, &vms, vmu);
11548 res = 0;
11549 goto out;
11550 }
11551 } else {
11552 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
11553 /* If we only have old messages start here */
11554 res = open_mailbox(&vms, vmu, OLD_FOLDER); /* Count all messages, even Urgent */
11555 in_urgent = 0;
11556 play_folder = 1;
11557 if (res < 0)
11558 goto out;
11559 } else if (!vms.urgentmessages && vms.newmessages) {
11560 /* If we have new messages but none are urgent */
11561 in_urgent = 0;
11562 res = open_mailbox(&vms, vmu, NEW_FOLDER);
11563 if (res < 0)
11564 goto out;
11565 }
11566 }
11567
11568 if (useadsi)
11569 adsi_status(chan, &vms);
11570 res = 0;
11571
11572 /* Check to see if this is a new user */
11573 if (!strcasecmp(vmu->mailbox, vmu->password) &&
11574 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 7) | (1 << 8))); })
)) {
11575 if (ast_play_and_wait(chan, "vm-newuser") == -1)
11576 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 11576, __PRETTY_FUNCTION__, "Couldn't stream new user file\n");
11577 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
11578 if ((cmd == 't') || (cmd == '#')) {
11579 /* Timeout */
11580 ast_test_suite_event_notify("TIMEOUT", "Message: response from user timed out");
11581 res = 0;
11582 goto out;
11583 } else if (cmd < 0) {
11584 /* Hangup */
11585 ast_test_suite_event_notify("HANGUP", "Message: hangup detected");
11586 res = -1;
11587 goto out;
11588 }
11589 }
11590#ifdef IMAP_STORAGE
11591 ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 11591, __PRETTY_FUNCTION__, "Checking quotas: comparing %u to %u\n"
, vms.quota_usage, vms.quota_limit); } } while (0)
;
11592 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
11593 ast_debug(1, "*** QUOTA EXCEEDED!!\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 11593, __PRETTY_FUNCTION__, "*** QUOTA EXCEEDED!!\n"
); } } while (0)
;
11594 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
11595 }
11596 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 11596, __PRETTY_FUNCTION__, "Checking quotas: User has %d messages and limit is %d.\n"
, (vms.newmessages + vms.oldmessages), vmu->maxmsg); } } while
(0)
;
11597 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
11598 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 11598, __PRETTY_FUNCTION__, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
11599 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
11600 }
11601#endif
11602
11603 ast_test_suite_event_notify("INTRO", "Message: playing intro menu");
11604 if (play_auto) {
11605 cmd = '1';
11606 } else {
11607 cmd = vm_intro(chan, vmu, &vms);
11608 }
11609 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
11610
11611 vms.repeats = 0;
11612 vms.starting = 1;
11613 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
11614 /* Run main menu */
11615 switch (cmd) {
11616 case '1': /* First message */
11617 vms.curmsg = 0;
11618 /* Fall through */
11619 case '5': /* Play current message */
11620 ast_test_suite_event_notify("BROWSE", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
11621 cmd = vm_browse_messages(chan, &vms, vmu);
11622 break;
11623 case '2': /* Change folders */
11624 ast_test_suite_event_notify("CHANGEFOLDER", "Message: browsing to a different folder");
11625 if (useadsi)
11626 adsi_folders(chan, 0, "Change to folder...");
11627
11628 cmd = get_folder2(chan, "vm-changeto", 0);
11629 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
11630 if (cmd == '#') {
11631 cmd = 0;
11632 } else if (cmd > 0) {
11633 cmd = cmd - '0';
11634 res = close_mailbox(&vms, vmu);
11635 if (res == ERROR_LOCK_PATH-100)
11636 goto out;
11637 /* If folder is not urgent, set in_urgent to zero! */
11638 if (cmd != 11) in_urgent = 0;
11639 res = open_mailbox(&vms, vmu, cmd);
11640 if (res < 0)
11641 goto out;
11642 play_folder = cmd;
11643 cmd = 0;
11644 }
11645 if (useadsi)
11646 adsi_status2(chan, &vms);
11647
11648 if (!cmd) {
11649 cmd = vm_play_folder_name(chan, vms.vmbox);
11650 }
11651
11652 vms.starting = 1;
11653 vms.curmsg = 0;
11654 break;
11655 case '3': /* Advanced options */
11656 ast_test_suite_event_notify("ADVOPTIONS", "Message: entering advanced options menu");
11657 cmd = 0;
11658 vms.repeats = 0;
11659 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
11660 switch (cmd) {
11661 case '1': /* Reply */
11662 if (vms.lastmsg > -1 && !vms.starting) {
11663 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
11664 if (cmd == ERROR_LOCK_PATH-100 || cmd == OPERATOR_EXIT300) {
11665 res = cmd;
11666 goto out;
11667 }
11668 } else {
11669 cmd = ast_play_and_wait(chan, "vm-sorry");
11670 }
11671 cmd = 't';
11672 break;
11673 case '2': /* Callback */
11674 if (!vms.starting)
11675 ast_verb(3, "Callback Requested\n")do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 11675, __PRETTY_FUNCTION__, 3, "Callback Requested\n"); } }
while (0)
;
11676 if (!ast_strlen_zero(vmu->callback)_ast_strlen_zero(vmu->callback, "app_voicemail.c", __PRETTY_FUNCTION__
, 11676)
&& vms.lastmsg > -1 && !vms.starting) {
11677 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
11678 if (cmd == 9) {
11679 silentexit = 1;
11680 goto out;
11681 } else if (cmd == ERROR_LOCK_PATH-100) {
11682 res = cmd;
11683 goto out;
11684 }
11685 } else {
11686 cmd = ast_play_and_wait(chan, "vm-sorry");
11687 }
11688 cmd = 't';
11689 break;
11690 case '3': /* Envelope */
11691 if (vms.lastmsg > -1 && !vms.starting) {
11692 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
11693 if (cmd == ERROR_LOCK_PATH-100) {
11694 res = cmd;
11695 goto out;
11696 }
11697 } else {
11698 cmd = ast_play_and_wait(chan, "vm-sorry");
11699 }
11700 cmd = 't';
11701 break;
11702 case '4': /* Dialout */
11703 if (!ast_strlen_zero(vmu->dialout)_ast_strlen_zero(vmu->dialout, "app_voicemail.c", __PRETTY_FUNCTION__
, 11703)
) {
11704 cmd = dialout(chan, vmu, NULL((void*)0), vmu->dialout);
11705 if (cmd == 9) {
11706 silentexit = 1;
11707 goto out;
11708 }
11709 } else {
11710 cmd = ast_play_and_wait(chan, "vm-sorry");
11711 }
11712 cmd = 't';
11713 break;
11714
11715 case '5': /* Leave VoiceMail */
11716 if (ast_test_flag(vmu, VM_SVMAIL)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 3))); })
) {
11717 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
11718 if (cmd == ERROR_LOCK_PATH-100 || cmd == OPERATOR_EXIT300) {
11719 res = cmd;
11720 goto out;
11721 }
11722 } else {
11723 cmd = ast_play_and_wait(chan, "vm-sorry");
11724 }
11725 cmd = 't';
11726 break;
11727
11728 case '*': /* Return to main menu */
11729 cmd = 't';
11730 break;
11731
11732 default:
11733 cmd = 0;
11734 if (!vms.starting) {
11735 cmd = ast_play_and_wait(chan, "vm-toreply");
11736 }
11737 if (!ast_strlen_zero(vmu->callback)_ast_strlen_zero(vmu->callback, "app_voicemail.c", __PRETTY_FUNCTION__
, 11737)
&& !vms.starting && !cmd) {
11738 cmd = ast_play_and_wait(chan, "vm-tocallback");
11739 }
11740 if (!cmd && !vms.starting) {
11741 cmd = ast_play_and_wait(chan, "vm-tohearenv");
11742 }
11743 if (!ast_strlen_zero(vmu->dialout)_ast_strlen_zero(vmu->dialout, "app_voicemail.c", __PRETTY_FUNCTION__
, 11743)
&& !cmd) {
11744 cmd = ast_play_and_wait(chan, "vm-tomakecall");
11745 }
11746 if (ast_test_flag(vmu, VM_SVMAIL)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 3))); })
&& !cmd) {
11747 cmd = ast_play_and_wait(chan, "vm-leavemsg");
11748 }
11749 if (!cmd) {
11750 cmd = ast_play_and_wait(chan, "vm-starmain");
11751 }
11752 if (!cmd) {
11753 cmd = ast_waitfordigit(chan, 6000);
11754 }
11755 if (!cmd) {
11756 vms.repeats++;
11757 }
11758 if (vms.repeats > 3) {
11759 cmd = 't';
11760 }
11761 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
11762 }
11763 }
11764 if (cmd == 't') {
11765 cmd = 0;
11766 vms.repeats = 0;
11767 }
11768 break;
11769 case '4': /* Go to the previous message */
11770 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg - 1, vms.curmsg - 1);
11771 if (vms.curmsg > 0) {
11772 vms.curmsg--;
11773 cmd = play_message(chan, vmu, &vms);
11774 } else {
11775 /* Check if we were listening to new
11776 messages. If so, go to Urgent messages
11777 instead of saying "no more messages"
11778 */
11779 if (in_urgent == 0 && vms.urgentmessages > 0) {
11780 /* Check for Urgent messages */
11781 in_urgent = 1;
11782 res = close_mailbox(&vms, vmu);
11783 if (res == ERROR_LOCK_PATH-100)
11784 goto out;
11785 res = open_mailbox(&vms, vmu, 11); /* Open Urgent folder */
11786 if (res < 0)
11787 goto out;
11788 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 11788, __PRETTY_FUNCTION__, "No more new messages, opened INBOX and got %d Urgent messages\n"
, vms.lastmsg + 1); } } while (0)
;
11789 vms.curmsg = vms.lastmsg;
11790 if (vms.lastmsg < 0) {
11791 cmd = ast_play_and_wait(chan, "vm-nomore");
11792 }
11793 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 17))); })
&& vms.lastmsg > 0) {
11794 vms.curmsg = vms.lastmsg;
11795 cmd = play_message(chan, vmu, &vms);
11796 } else {
11797 cmd = ast_play_and_wait(chan, "vm-nomore");
11798 }
11799 }
11800 break;
11801 case '6': /* Go to the next message */
11802 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg + 1, vms.curmsg + 1);
11803 if (vms.curmsg < vms.lastmsg) {
11804 vms.curmsg++;
11805 cmd = play_message(chan, vmu, &vms);
11806 } else {
11807 if (in_urgent && vms.newmessages > 0) {
11808 /* Check if we were listening to urgent
11809 * messages. If so, go to regular new messages
11810 * instead of saying "no more messages"
11811 */
11812 in_urgent = 0;
11813 res = close_mailbox(&vms, vmu);
11814 if (res == ERROR_LOCK_PATH-100)
11815 goto out;
11816 res = open_mailbox(&vms, vmu, NEW_FOLDER);
11817 if (res < 0)
11818 goto out;
11819 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 11819, __PRETTY_FUNCTION__, "No more urgent messages, opened INBOX and got %d new messages\n"
, vms.lastmsg + 1); } } while (0)
;
11820 vms.curmsg = -1;
11821 if (vms.lastmsg < 0) {
11822 cmd = ast_play_and_wait(chan, "vm-nomore");
11823 }
11824 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 17))); })
&& vms.lastmsg > 0) {
11825 vms.curmsg = 0;
11826 cmd = play_message(chan, vmu, &vms);
11827 } else {
11828 cmd = ast_play_and_wait(chan, "vm-nomore");
11829 }
11830 }
11831 break;
11832 case '7': /* Delete the current message */
11833 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
11834 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
11835 if (useadsi)
11836 adsi_delete(chan, &vms);
11837 if (vms.deleted[vms.curmsg]) {
11838 if (play_folder == 0) {
11839 if (in_urgent) {
11840 vms.urgentmessages--;
11841 } else {
11842 vms.newmessages--;
11843 }
11844 }
11845 else if (play_folder == 1)
11846 vms.oldmessages--;
11847 cmd = ast_play_and_wait(chan, "vm-deleted");
11848 } else {
11849 if (play_folder == 0) {
11850 if (in_urgent) {
11851 vms.urgentmessages++;
11852 } else {
11853 vms.newmessages++;
11854 }
11855 }
11856 else if (play_folder == 1)
11857 vms.oldmessages++;
11858 cmd = ast_play_and_wait(chan, "vm-undeleted");
11859 }
11860 if (ast_test_flag(vmu, VM_SKIPAFTERCMD)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 6))); })
) {
11861 if (vms.curmsg < vms.lastmsg) {
11862 vms.curmsg++;
11863 cmd = play_message(chan, vmu, &vms);
11864 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 17))); })
&& vms.lastmsg > 0) {
11865 vms.curmsg = 0;
11866 cmd = play_message(chan, vmu, &vms);
11867 } else {
11868 /* Check if we were listening to urgent
11869 messages. If so, go to regular new messages
11870 instead of saying "no more messages"
11871 */
11872 if (in_urgent == 1) {
11873 /* Check for new messages */
11874 in_urgent = 0;
11875 res = close_mailbox(&vms, vmu);
11876 if (res == ERROR_LOCK_PATH-100)
11877 goto out;
11878 res = open_mailbox(&vms, vmu, NEW_FOLDER);
11879 if (res < 0)
11880 goto out;
11881 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 11881, __PRETTY_FUNCTION__, "No more urgent messages, opened INBOX and got %d new messages\n"
, vms.lastmsg + 1); } } while (0)
;
11882 vms.curmsg = -1;
11883 if (vms.lastmsg < 0) {
11884 cmd = ast_play_and_wait(chan, "vm-nomore");
11885 }
11886 } else {
11887 cmd = ast_play_and_wait(chan, "vm-nomore");
11888 }
11889 }
11890 }
11891 } else /* Delete not valid if we haven't selected a message */
11892 cmd = 0;
11893#ifdef IMAP_STORAGE
11894 deleted = 1;
11895#endif
11896 break;
11897
11898 case '8': /* Forward the current message */
11899 if (vms.lastmsg > -1) {
11900 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
11901 if (cmd == ERROR_LOCK_PATH-100) {
11902 res = cmd;
11903 goto out;
11904 }
11905 } else {
11906 /* Check if we were listening to urgent
11907 messages. If so, go to regular new messages
11908 instead of saying "no more messages"
11909 */
11910 if (in_urgent == 1 && vms.newmessages > 0) {
11911 /* Check for new messages */
11912 in_urgent = 0;
11913 res = close_mailbox(&vms, vmu);
11914 if (res == ERROR_LOCK_PATH-100)
11915 goto out;
11916 res = open_mailbox(&vms, vmu, NEW_FOLDER);
11917 if (res < 0)
11918 goto out;
11919 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 11919, __PRETTY_FUNCTION__, "No more urgent messages, opened INBOX and got %d new messages\n"
, vms.lastmsg + 1); } } while (0)
;
11920 vms.curmsg = -1;
11921 if (vms.lastmsg < 0) {
11922 cmd = ast_play_and_wait(chan, "vm-nomore");
11923 }
11924 } else {
11925 cmd = ast_play_and_wait(chan, "vm-nomore");
11926 }
11927 }
11928 break;
11929 case '9': /* Save message to folder */
11930 ast_test_suite_event_notify("SAVEMSG", "Message: saving message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
11931 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
11932 /* No message selected */
11933 cmd = 0;
11934 break;
11935 }
11936 if (useadsi)
11937 adsi_folders(chan, 1, "Save to folder...");
11938 cmd = get_folder2(chan, "vm-savefolder", 1);
11939 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
11940 box = 0; /* Shut up compiler */
11941 if (cmd == '#') {
11942 cmd = 0;
11943 break;
11944 } else if (cmd > 0) {
11945 box = cmd = cmd - '0';
11946 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd, NULL((void*)0), 0);
11947 if (cmd == ERROR_LOCK_PATH-100) {
11948 res = cmd;
11949 goto out;
11950#ifndef IMAP_STORAGE
11951 } else if (!cmd) {
11952 vms.deleted[vms.curmsg] = 1;
11953#endif
11954 } else {
11955 vms.deleted[vms.curmsg] = 0;
11956 vms.heard[vms.curmsg] = 0;
11957 }
11958 }
11959 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
11960 if (useadsi)
11961 adsi_message(chan, &vms);
11962 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(vmu, box));
11963 if (!cmd) {
11964 cmd = ast_play_and_wait(chan, "vm-message");
11965 if (!cmd)
11966 cmd = say_and_wait(chan, vms.curmsg + 1, ast_channel_language(chan));
11967 if (!cmd)
11968 cmd = ast_play_and_wait(chan, "vm-savedto");
11969 if (!cmd)
11970 cmd = vm_play_folder_name(chan, vms.fn);
11971 } else {
11972 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
11973 }
11974 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)({ typeof (((&globalflags))->flags) __p = ((&globalflags
))->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); (((&globalflags))->flags &
((1 << 6))); })
) {
11975 if (vms.curmsg < vms.lastmsg) {
11976 vms.curmsg++;
11977 cmd = play_message(chan, vmu, &vms);
11978 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 17))); })
&& vms.lastmsg > 0) {
11979 vms.curmsg = 0;
11980 cmd = play_message(chan, vmu, &vms);
11981 } else {
11982 /* Check if we were listening to urgent
11983 messages. If so, go to regular new messages
11984 instead of saying "no more messages"
11985 */
11986 if (in_urgent == 1 && vms.newmessages > 0) {
11987 /* Check for new messages */
11988 in_urgent = 0;
11989 res = close_mailbox(&vms, vmu);
11990 if (res == ERROR_LOCK_PATH-100)
11991 goto out;
11992 res = open_mailbox(&vms, vmu, NEW_FOLDER);
11993 if (res < 0)
11994 goto out;
11995 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 11995, __PRETTY_FUNCTION__, "No more urgent messages, opened INBOX and got %d new messages\n"
, vms.lastmsg + 1); } } while (0)
;
11996 vms.curmsg = -1;
11997 if (vms.lastmsg < 0) {
11998 cmd = ast_play_and_wait(chan, "vm-nomore");
11999 }
12000 } else {
12001 cmd = ast_play_and_wait(chan, "vm-nomore");
12002 }
12003 }
12004 }
12005 break;
12006 case '*': /* Help */
12007 if (!vms.starting) {
12008 if (!strncasecmp(ast_channel_language(chan), "ja", 2)) {
12009 cmd = vm_play_folder_name(chan, vms.vmbox);
12010 if (!cmd)
12011 cmd = ast_play_and_wait(chan, "jp-wa");
12012 if (!cmd)
12013 cmd = ast_play_and_wait(chan, "digits/1");
12014 if (!cmd)
12015 cmd = ast_play_and_wait(chan, "jp-wo");
12016 if (!cmd)
12017 cmd = ast_play_and_wait(chan, "silence/1");
12018 if (!cmd)
12019 cmd = ast_play_and_wait(chan, "vm-opts");
12020 if (!cmd)
12021 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
12022 break;
12023 }
12024 cmd = ast_play_and_wait(chan, "vm-onefor");
12025 if (!strncasecmp(ast_channel_language(chan), "he", 2)) {
12026 cmd = ast_play_and_wait(chan, "vm-for");
12027 }
12028 if (!cmd)
12029 cmd = vm_play_folder_name(chan, vms.vmbox);
12030 if (!cmd)
12031 cmd = ast_play_and_wait(chan, "vm-opts");
12032 if (!cmd)
12033 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
12034 } else
12035 cmd = 0;
12036 break;
12037 case '0': /* Mailbox options */
12038 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
12039 if (useadsi)
12040 adsi_status(chan, &vms);
12041 /* Reopen play_folder */
12042 res = open_mailbox(&vms, vmu, play_folder);
12043 if (res < 0) {
12044 goto out;
12045 }
12046 vms.starting = 1;
12047 break;
12048 default: /* Nothing */
12049 ast_test_suite_event_notify("PLAYBACK", "Message: instructions");
12050 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
12051 break;
12052 }
12053 }
12054 if ((cmd == 't') || (cmd == '#')) {
12055 /* Timeout */
12056 res = 0;
12057 } else {
12058 /* Hangup */
12059 res = -1;
12060 }
12061
12062out:
12063 if (res > -1) {
12064 ast_stopstream(chan);
12065 adsi_goodbye(chan);
12066 if (valid && res != OPERATOR_EXIT300) {
12067 if (silentexit)
12068 res = ast_play_and_wait(chan, "vm-dialout");
12069 else
12070 res = ast_play_and_wait(chan, "vm-goodbye");
12071 }
12072 if ((valid && res > 0) || res == OPERATOR_EXIT300) {
12073 res = 0;
12074 }
12075 if (useadsi)
12076 ast_adsi_unload_session(chan);
12077 }
12078 if (vmu)
12079 close_mailbox(&vms, vmu);
12080 if (valid) {
12081 int new = 0, old = 0, urgent = 0;
12082 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
12083 /* Urgent flag not passwd to externnotify here */
12084 run_externnotify(vmu->context, vmu->mailbox, NULL((void*)0));
12085 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
12086 queue_mwi_event(ast_channel_uniqueid(chan), ext_context, urgent, new, old);
12087 }
12088#ifdef IMAP_STORAGE
12089 /* expunge message - use UID Expunge if supported on IMAP server*/
12090 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 12090, __PRETTY_FUNCTION__, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n"
, deleted, expungeonhangup); } } while (0)
;
12091 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL((void*)0)) {
12092 ast_mutex_lock(&vms.lock)__ast_pthread_mutex_lock("app_voicemail.c", 12092, __PRETTY_FUNCTION__
, "&vms.lock", &vms.lock)
;
12093#ifdef HAVE_IMAP_TK2006
12094 if (LEVELUIDPLUS (vms.mailstream)) {
12095 mail_expunge_full(vms.mailstream, NIL, EX_UID);
12096 } else
12097#endif
12098 mail_expunge(vms.mailstream);
12099 ast_mutex_unlock(&vms.lock)__ast_pthread_mutex_unlock("app_voicemail.c", 12099, __PRETTY_FUNCTION__
, "&vms.lock", &vms.lock)
;
12100 }
12101 /* before we delete the state, we should copy pertinent info
12102 * back to the persistent model */
12103 if (vmu) {
12104 vmstate_delete(&vms);
12105 }
12106#endif
12107 if (vmu)
12108 free_user(vmu);
12109
12110#ifdef IMAP_STORAGE
12111 pthread_setspecific(ts_vmstate.key, NULL((void*)0));
12112#endif
12113 return res;
12114}
12115
12116static int vm_exec(struct ast_channel *chan, const char *data)
12117{
12118 int res = 0;
12119 char *tmp;
12120 struct leave_vm_options leave_options;
12121 struct ast_flags flags = { 0 };
12122 char *opts[OPT_ARG_ARRAY_SIZE];
12123 AST_DECLARE_APP_ARGS(args,struct { unsigned int argc; char *argv[0]; char *argv0; char *
argv1; } args = { 0, }
12124 AST_APP_ARG(argv0);struct { unsigned int argc; char *argv[0]; char *argv0; char *
argv1; } args = { 0, }
12125 AST_APP_ARG(argv1);struct { unsigned int argc; char *argv[0]; char *argv0; char *
argv1; } args = { 0, }
12126 )struct { unsigned int argc; char *argv[0]; char *argv0; char *
argv1; } args = { 0, }
;
12127
12128 memset(&leave_options, 0, sizeof(leave_options));
12129
12130 if (ast_channel_state(chan) != AST_STATE_UP)
12131 ast_answer(chan);
12132
12133 if (!ast_strlen_zero(data)_ast_strlen_zero(data, "app_voicemail.c", __PRETTY_FUNCTION__
, 12133)
) {
12134 tmp = ast_strdupa(data)(__extension__ ({ const char *__old = (data); size_t __len = strlen
(__old) + 1; char *__new = __builtin_alloca(__len); memcpy (__new
, __old, __len); __new; }))
;
12135 AST_STANDARD_APP_ARGS(args, tmp)args.argc = __ast_app_separate_args(tmp, ',', 1, args.argv, (
(sizeof(args) - __builtin_offsetof(typeof(args), argv)) / sizeof
(args.argv[0])))
;
12136 if (args.argc == 2) {
12137 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
12138 return -1;
12139 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT)do { typeof ((&leave_options)->flags) __d = (&leave_options
)->flags; typeof ((&flags)->flags) __s = (&flags
)->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__d == &__x); (void) (&__s == &__x); (&
leave_options)->flags &= ~(OPT_SILENT | OPT_BUSY_GREETING
| OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY
| OPT_DTMFEXIT); (&leave_options)->flags |= ((&flags
)->flags & (OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING
| OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT))
; } while (0)
;
12140 if (ast_test_flag(&flags, OPT_RECORDGAIN)({ typeof ((&flags)->flags) __p = (&flags)->flags
; typeof (__unsigned_int_flags_dummy) __x = 0; (void) (&__p
== &__x); ((&flags)->flags & (OPT_RECORDGAIN)
); })
) {
12141 int gain;
12142
12143 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
12144 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 12144, __PRETTY_FUNCTION__, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
12145 return -1;
12146 } else {
12147 leave_options.record_gain = (signed char) gain;
12148 }
12149 }
12150 if (ast_test_flag(&flags, OPT_DTMFEXIT)({ typeof ((&flags)->flags) __p = (&flags)->flags
; typeof (__unsigned_int_flags_dummy) __x = 0; (void) (&__p
== &__x); ((&flags)->flags & (OPT_DTMFEXIT));
})
) {
12151 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT])_ast_strlen_zero(opts[OPT_ARG_DTMFEXIT], "app_voicemail.c", __PRETTY_FUNCTION__
, 12151)
)
12152 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
12153 }
12154 }
12155 } else {
12156 char temp[256];
12157 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
12158 if (res < 0)
12159 return res;
12160 if (ast_strlen_zero(temp)_ast_strlen_zero(temp, "app_voicemail.c", __PRETTY_FUNCTION__
, 12160)
)
12161 return 0;
12162 args.argv0 = ast_strdupa(temp)(__extension__ ({ const char *__old = (temp); size_t __len = strlen
(__old) + 1; char *__new = __builtin_alloca(__len); memcpy (__new
, __old, __len); __new; }))
;
12163 }
12164
12165 res = leave_voicemail(chan, args.argv0, &leave_options);
12166 if (res == 't') {
12167 ast_play_and_wait(chan, "vm-goodbye");
12168 res = 0;
12169 }
12170
12171 if (res == OPERATOR_EXIT300) {
12172 res = 0;
12173 }
12174
12175 if (res == ERROR_LOCK_PATH-100) {
12176 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 12176, __PRETTY_FUNCTION__, "Could not leave voicemail. The path is already locked.\n");
12177 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
12178 res = 0;
12179 }
12180
12181 return res;
12182}
12183
12184static int add_message_id(struct ast_config *msg_cfg, char *dir, int msg, char *filename, char *id, size_t id_size, struct ast_vm_user *vmu, int folder)
12185{
12186 struct ast_variable *var;
12187 struct ast_category *cat;
12188 generate_msg_id(id);
12189
12190 var = ast_variable_new("msg_id", id, "");
12191 if (!var) {
12192 return -1;
12193 }
12194
12195 cat = ast_category_get(msg_cfg, "message", NULL((void*)0));
12196 if (!cat) {
12197 ast_log(LOG_ERROR4, "app_voicemail.c", 12197, __PRETTY_FUNCTION__, "Voicemail data file %s/%d.txt has no [message] category?\n", dir, msg);
12198 ast_variables_destroy(var);
12199 return -1;
12200 }
12201
12202 ast_variable_append(cat, var);
12203
12204 if (ast_config_text_file_save(filename, msg_cfg, "app_voicemail")) {
12205 ast_log(LOG_WARNING3, "app_voicemail.c", 12205, __PRETTY_FUNCTION__, "Unable to update %s to have a message ID\n", filename);
12206 return -1;
12207 }
12208
12209 UPDATE_MSG_ID(dir, msg, id, vmu, msg_cfg, folder);
12210 return 0;
12211}
12212
12213static struct ast_vm_user *find_or_create(const char *context, const char *box)
12214{
12215 struct ast_vm_user *vmu;
12216
12217 if (!ast_strlen_zero(box)_ast_strlen_zero(box, "app_voicemail.c", __PRETTY_FUNCTION__,
12217)
&& box[0] == '*') {
12218 ast_log(LOG_WARNING3, "app_voicemail.c", 12218, __PRETTY_FUNCTION__, "Mailbox %s in context %s begins with '*' character. The '*' character,"
12219 "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
12220 "\n\tpredefined extension 'a'. A mailbox or password beginning with '*' is not valid"
12221 "\n\tand will be ignored.\n", box, context);
12222 return NULL((void*)0);
12223 }
12224
12225 AST_LIST_TRAVERSE(&users, vmu, list)for((vmu) = (&users)->first; (vmu); (vmu) = (vmu)->
list.next)
{
12226 if (ast_test_flag((&globalflags), VM_SEARCH)({ typeof (((&globalflags))->flags) __p = ((&globalflags
))->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); (((&globalflags))->flags &
((1 << 14))); })
&& !strcasecmp(box, vmu->mailbox)) {
12227 if (strcasecmp(vmu->context, context)) {
12228 ast_log(LOG_WARNING3, "app_voicemail.c", 12228, __PRETTY_FUNCTION__, "\nIt has been detected that you have defined mailbox '%s' in separate\
12229 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
12230 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
12231 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
12232 }
12233 ast_log(LOG_WARNING3, "app_voicemail.c", 12233, __PRETTY_FUNCTION__, "Ignoring duplicated mailbox %s\n", box);
12234 return NULL((void*)0);
12235 }
12236 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
12237 ast_log(LOG_WARNING3, "app_voicemail.c", 12237, __PRETTY_FUNCTION__, "Ignoring duplicated mailbox %s in context %s\n", box, context);
12238 return NULL((void*)0);
12239 }
12240 }
12241
12242 if (!(vmu = ast_calloc(1, sizeof(*vmu))_ast_calloc((1), (sizeof(*vmu)), "app_voicemail.c", 12242, __PRETTY_FUNCTION__
)
))
12243 return NULL((void*)0);
12244
12245 ast_copy_string(vmu->context, context, sizeof(vmu->context));
12246 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
12247
12248 AST_LIST_INSERT_TAIL(&users, vmu, list)do { if (!(&users)->first) { (&users)->first = (
vmu); (&users)->last = (vmu); } else { (&users)->
last->list.next = (vmu); (&users)->last = (vmu); } }
while (0)
;
12249
12250 return vmu;
12251}
12252
12253static int append_mailbox(const char *context, const char *box, const char *data)
12254{
12255 /* Assumes lock is already held */
12256 char *tmp;
12257 char *stringp;
12258 char *s;
12259 struct ast_vm_user *vmu;
12260 char *mailbox_full;
12261 int new = 0, old = 0, urgent = 0;
12262 char secretfn[PATH_MAX4096] = "";
12263
12264 tmp = ast_strdupa(data)(__extension__ ({ const char *__old = (data); size_t __len = strlen
(__old) + 1; char *__new = __builtin_alloca(__len); memcpy (__new
, __old, __len); __new; }))
;
12265
12266 if (!(vmu = find_or_create(context, box)))
12267 return -1;
12268
12269 populate_defaults(vmu);
12270
12271 stringp = tmp;
12272 if ((s = strsep(&stringp, ","))) {
12273 if (!ast_strlen_zero(s)_ast_strlen_zero(s, "app_voicemail.c", __PRETTY_FUNCTION__, 12273
)
&& s[0] == '*') {
12274 ast_log(LOG_WARNING3, "app_voicemail.c", 12274, __PRETTY_FUNCTION__, "Invalid password detected for mailbox %s. The password"
12275 "\n\tmust be reset in voicemail.conf.\n", box);
12276 }
12277 /* assign password regardless of validity to prevent NULL password from being assigned */
12278 ast_copy_string(vmu->password, s, sizeof(vmu->password));
12279 }
12280 if (stringp && (s = strsep(&stringp, ","))) {
12281 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
12282 }
12283 if (stringp && (s = strsep(&stringp, ","))) {
12284 vmu->email = ast_strdup(s)_ast_strdup((s), "app_voicemail.c", 12284, __PRETTY_FUNCTION__
)
;
12285 }
12286 if (stringp && (s = strsep(&stringp, ","))) {
12287 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
12288 }
12289 if (stringp && (s = strsep(&stringp, ","))) {
12290 apply_options(vmu, s);
12291 }
12292
12293 switch (vmu->passwordlocation) {
12294 case OPT_PWLOC_SPOOLDIR:
12295 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
12296 read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
12297 }
12298
12299 mailbox_full = ast_alloca(strlen(box) + strlen(context) + 1)__builtin_alloca(strlen(box) + strlen(context) + 1);
12300 strcpy(mailbox_full, box);
12301 strcat(mailbox_full, "@");
12302 strcat(mailbox_full, context);
12303
12304 inboxcount2(mailbox_full, &urgent, &new, &old);
12305 queue_mwi_event(NULL((void*)0), mailbox_full, urgent, new, old);
12306
12307 return 0;
12308}
12309
12310AST_TEST_DEFINE(test_voicemail_vmuser)static enum ast_test_result_state __attribute__((unused)) test_voicemail_vmuser
(struct ast_test_info *info, enum ast_test_command cmd, struct
ast_test *test)
12311{
12312 int res = 0;
12313 struct ast_vm_user *vmu;
12314 /* language parameter seems to only be used for display in manager action */
12315 static const char options_string[] = "attach=yes|attachfmt=wav49|"
12316 "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|"
12317 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|"
12318 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
12319 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
12320 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
12321 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir|emailbody="
12322 "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message|emailsubject="
12323 "[PBX]: New message \\\\${VM_MSGNUM}\\\\ in mailbox ${VM_MAILBOX}";
12324#ifdef IMAP_STORAGE
12325 static const char option_string2[] = "imapuser=imapuser|imappassword=imappasswd|"
12326 "imapfolder=INBOX|imapvmshareid=6000|imapserver=imapserver|imapport=1234|imapflags=flagged";
12327#endif
12328
12329 switch (cmd) {
12330 case TEST_INIT:
12331 info->name = "vmuser";
12332 info->category = "/apps/app_voicemail/";
12333 info->summary = "Vmuser unit test";
12334 info->description =
12335 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
12336 return AST_TEST_NOT_RUN;
12337 case TEST_EXECUTE:
12338 break;
12339 }
12340
12341 if (!(vmu = ast_calloc(1, sizeof(*vmu))_ast_calloc((1), (sizeof(*vmu)), "app_voicemail.c", 12341, __PRETTY_FUNCTION__
)
)) {
12342 return AST_TEST_NOT_RUN;
12343 }
12344 populate_defaults(vmu);
12345 ast_set_flag(vmu, VM_ALLOCED)do { typeof ((vmu)->flags) __p = (vmu)->flags; typeof (
__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); ((vmu)->flags |= ((1 << 13))); } while(0)
;
12346
12347 apply_options(vmu, options_string);
12348
12349 if (!ast_test_flag(vmu, VM_ATTACH)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 11))); })
) {
12350 ast_test_status_update(test, "Parse failure for attach option\n");
12351 res = 1;
12352 }
12353 if (strcasecmp(vmu->attachfmt, "wav49")) {
12354 ast_test_status_update(test, "Parse failure for attachftm option\n");
12355 res = 1;
12356 }
12357 if (strcasecmp(vmu->serveremail, "someguy@digium.com")) {
12358 ast_test_status_update(test, "Parse failure for serveremail option\n");
12359 res = 1;
12360 }
12361 if (!vmu->emailsubject || strcasecmp(vmu->emailsubject, "[PBX]: New message \\${VM_MSGNUM}\\ in mailbox ${VM_MAILBOX}")) {
12362 ast_test_status_update(test, "Parse failure for emailsubject option\n");
12363 res = 1;
12364 }
12365 if (!vmu->emailbody || strcasecmp(vmu->emailbody, "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message")) {
12366 ast_test_status_update(test, "Parse failure for emailbody option\n");
12367 res = 1;
12368 }
12369 if (strcasecmp(vmu->zonetag, "central")) {
12370 ast_test_status_update(test, "Parse failure for tz option\n");
12371 res = 1;
12372 }
12373 if (!ast_test_flag(vmu, VM_DELETE)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 12))); })
) {
12374 ast_test_status_update(test, "Parse failure for delete option\n");
12375 res = 1;
12376 }
12377 if (!ast_test_flag(vmu, VM_SAYCID)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 2))); })
) {
12378 ast_test_status_update(test, "Parse failure for saycid option\n");
12379 res = 1;
12380 }
12381 if (!ast_test_flag(vmu, VM_SVMAIL)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 3))); })
) {
12382 ast_test_status_update(test, "Parse failure for sendvoicemail option\n");
12383 res = 1;
12384 }
12385 if (!ast_test_flag(vmu, VM_REVIEW)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 0))); })
) {
12386 ast_test_status_update(test, "Parse failure for review option\n");
12387 res = 1;
12388 }
12389 if (!ast_test_flag(vmu, VM_TEMPGREETWARN)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 15))); })
) {
12390 ast_test_status_update(test, "Parse failure for tempgreetwarm option\n");
12391 res = 1;
12392 }
12393 if (!ast_test_flag(vmu, VM_MESSAGEWRAP)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 17))); })
) {
12394 ast_test_status_update(test, "Parse failure for messagewrap option\n");
12395 res = 1;
12396 }
12397 if (!ast_test_flag(vmu, VM_OPERATOR)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 1))); })
) {
12398 ast_test_status_update(test, "Parse failure for operator option\n");
12399 res = 1;
12400 }
12401 if (!ast_test_flag(vmu, VM_ENVELOPE)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 4))); })
) {
12402 ast_test_status_update(test, "Parse failure for envelope option\n");
12403 res = 1;
12404 }
12405 if (!ast_test_flag(vmu, VM_MOVEHEARD)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 16))); })
) {
12406 ast_test_status_update(test, "Parse failure for moveheard option\n");
12407 res = 1;
12408 }
12409 if (!ast_test_flag(vmu, VM_SAYDURATION)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 5))); })
) {
12410 ast_test_status_update(test, "Parse failure for sayduration option\n");
12411 res = 1;
12412 }
12413 if (vmu->saydurationm != 5) {
12414 ast_test_status_update(test, "Parse failure for saydurationm option\n");
12415 res = 1;
12416 }
12417 if (!ast_test_flag(vmu, VM_FORCENAME)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 7))); })
) {
12418 ast_test_status_update(test, "Parse failure for forcename option\n");
12419 res = 1;
12420 }
12421 if (!ast_test_flag(vmu, VM_FORCEGREET)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 8))); })
) {
12422 ast_test_status_update(test, "Parse failure for forcegreetings option\n");
12423 res = 1;
12424 }
12425 if (strcasecmp(vmu->callback, "somecontext")) {
12426 ast_test_status_update(test, "Parse failure for callbacks option\n");
12427 res = 1;
12428 }
12429 if (strcasecmp(vmu->dialout, "somecontext2")) {
12430 ast_test_status_update(test, "Parse failure for dialout option\n");
12431 res = 1;
12432 }
12433 if (strcasecmp(vmu->exit, "somecontext3")) {
12434 ast_test_status_update(test, "Parse failure for exitcontext option\n");
12435 res = 1;
12436 }
12437 if (vmu->minsecs != 10) {
12438 ast_test_status_update(test, "Parse failure for minsecs option\n");
12439 res = 1;
12440 }
12441 if (vmu->maxsecs != 100) {
12442 ast_test_status_update(test, "Parse failure for maxsecs option\n");
12443 res = 1;
12444 }
12445 if (!ast_test_flag(vmu, VM_SKIPAFTERCMD)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 6))); })
) {
12446 ast_test_status_update(test, "Parse failure for nextaftercmd option\n");
12447 res = 1;
12448 }
12449 if (vmu->maxdeletedmsg != 50) {
12450 ast_test_status_update(test, "Parse failure for backupdeleted option\n");
12451 res = 1;
12452 }
12453 if (vmu->volgain != 1.3) {
12454 ast_test_status_update(test, "Parse failure for volgain option\n");
12455 res = 1;
12456 }
12457 if (vmu->passwordlocation != OPT_PWLOC_SPOOLDIR) {
12458 ast_test_status_update(test, "Parse failure for passwordlocation option\n");
12459 res = 1;
12460 }
12461#ifdef IMAP_STORAGE
12462 apply_options(vmu, option_string2);
12463
12464 if (strcasecmp(vmu->imapuser, "imapuser")) {
12465 ast_test_status_update(test, "Parse failure for imapuser option\n");
12466 res = 1;
12467 }
12468 if (strcasecmp(vmu->imappassword, "imappasswd")) {
12469 ast_test_status_update(test, "Parse failure for imappasswd option\n");
12470 res = 1;
12471 }
12472 if (strcasecmp(vmu->imapfolder, "INBOX")) {
12473 ast_test_status_update(test, "Parse failure for imapfolder option\n");
12474 res = 1;
12475 }
12476 if (strcasecmp(vmu->imapvmshareid, "6000")) {
12477 ast_test_status_update(test, "Parse failure for imapvmshareid option\n");
12478 res = 1;
12479 }
12480 if (strcasecmp(vmu->imapserver, "imapserver")) {
12481 ast_test_status_update(test, "Parse failure for imapserver option\n");
12482 res = 1;
12483 }
12484 if (strcasecmp(vmu->imapport, "1234")) {
12485 ast_test_status_update(test, "Parse failure for imapport option\n");
12486 res = 1;
12487 }
12488 if (strcasecmp(vmu->imapflags, "flagged")) {
12489 ast_test_status_update(test, "Parse failure for imapflags option\n");
12490 res = 1;
12491 }
12492#endif
12493
12494 free_user(vmu);
12495 return res ? AST_TEST_FAIL : AST_TEST_PASS;
12496}
12497
12498static int vm_box_exists(struct ast_channel *chan, const char *data)
12499{
12500 struct ast_vm_user svm, *vmu;
12501 char *context, *box;
12502 AST_DECLARE_APP_ARGS(args,struct { unsigned int argc; char *argv[0]; char *mbox; char *
options; } args = { 0, }
12503 AST_APP_ARG(mbox);struct { unsigned int argc; char *argv[0]; char *mbox; char *
options; } args = { 0, }
12504 AST_APP_ARG(options);struct { unsigned int argc; char *argv[0]; char *mbox; char *
options; } args = { 0, }
12505 )struct { unsigned int argc; char *argv[0]; char *mbox; char *
options; } args = { 0, }
;
12506 static int dep_warning = 0;
12507
12508 if (ast_strlen_zero(data)_ast_strlen_zero(data, "app_voicemail.c", __PRETTY_FUNCTION__
, 12508)
) {
12509 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 12509, __PRETTY_FUNCTION__, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
12510 return -1;
12511 }
12512
12513 if (!dep_warning) {
12514 dep_warning = 1;
12515 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 12515, __PRETTY_FUNCTION__, "MailboxExists is deprecated. Please use ${VM_INFO(%s,exists)} instead.\n", data);
12516 }
12517
12518 box = ast_strdupa(data)(__extension__ ({ const char *__old = (data); size_t __len = strlen
(__old) + 1; char *__new = __builtin_alloca(__len); memcpy (__new
, __old, __len); __new; }))
;
12519
12520 AST_STANDARD_APP_ARGS(args, box)args.argc = __ast_app_separate_args(box, ',', 1, args.argv, (
(sizeof(args) - __builtin_offsetof(typeof(args), argv)) / sizeof
(args.argv[0])))
;
12521
12522 if (args.options) {
12523 }
12524
12525 if ((context = strchr(args.mbox, '@')(__extension__ (__builtin_constant_p ('@') && !__builtin_constant_p
(args.mbox) && ('@') == '\0' ? (char *) __rawmemchr (
args.mbox, '@') : __builtin_strchr (args.mbox, '@')))
)) {
12526 *context = '\0';
12527 context++;
12528 }
12529
12530 vmu = find_user(&svm, context, args.mbox);
12531 if (vmu) {
12532 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
12533 free_user(vmu);
12534 } else
12535 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
12536
12537 return 0;
12538}
12539
12540static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
12541{
12542 struct ast_vm_user svm, *vmu;
12543 AST_DECLARE_APP_ARGS(arg,struct { unsigned int argc; char *argv[0]; char *mbox; char *
context; } arg = { 0, }
12544 AST_APP_ARG(mbox);struct { unsigned int argc; char *argv[0]; char *mbox; char *
context; } arg = { 0, }
12545 AST_APP_ARG(context);struct { unsigned int argc; char *argv[0]; char *mbox; char *
context; } arg = { 0, }
12546 )struct { unsigned int argc; char *argv[0]; char *mbox; char *
context; } arg = { 0, }
;
12547 static int dep_warning = 0;
12548
12549 AST_NONSTANDARD_APP_ARGS(arg, args, '@')arg.argc = __ast_app_separate_args(args, '@', 1, arg.argv, ((
sizeof(arg) - __builtin_offsetof(typeof(arg), argv)) / sizeof
(arg.argv[0])))
;
12550
12551 if (ast_strlen_zero(arg.mbox)_ast_strlen_zero(arg.mbox, "app_voicemail.c", __PRETTY_FUNCTION__
, 12551)
) {
12552 ast_log(LOG_ERROR4, "app_voicemail.c", 12552, __PRETTY_FUNCTION__, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
12553 return -1;
12554 }
12555
12556 if (!dep_warning) {
12557 dep_warning = 1;
12558 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 12558, __PRETTY_FUNCTION__, "MAILBOX_EXISTS is deprecated. Please use ${VM_INFO(%s,exists)} instead.\n", args);
12559 }
12560
12561 vmu = find_user(&svm, ast_strlen_zero(arg.context)_ast_strlen_zero(arg.context, "app_voicemail.c", __PRETTY_FUNCTION__
, 12561)
? "default" : arg.context, arg.mbox);
12562 ast_copy_string(buf, vmu ? "1" : "0", len);
12563 free_user(vmu);
12564
12565 return 0;
12566}
12567
12568static int acf_vm_info(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
12569{
12570 struct ast_vm_user svm;
12571 struct ast_vm_user *vmu = NULL((void*)0);
12572 char *parse;
12573 char *mailbox;
12574 char *context;
12575 int res = 0;
12576
12577 AST_DECLARE_APP_ARGS(arg,struct { unsigned int argc; char *argv[0]; char *mailbox_context
; char *attribute; char *folder; } arg = { 0, }
12578 AST_APP_ARG(mailbox_context);struct { unsigned int argc; char *argv[0]; char *mailbox_context
; char *attribute; char *folder; } arg = { 0, }
12579 AST_APP_ARG(attribute);struct { unsigned int argc; char *argv[0]; char *mailbox_context
; char *attribute; char *folder; } arg = { 0, }
12580 AST_APP_ARG(folder);struct { unsigned int argc; char *argv[0]; char *mailbox_context
; char *attribute; char *folder; } arg = { 0, }
12581 )struct { unsigned int argc; char *argv[0]; char *mailbox_context
; char *attribute; char *folder; } arg = { 0, }
;
12582
12583 buf[0] = '\0';
12584
12585 if (ast_strlen_zero(args)_ast_strlen_zero(args, "app_voicemail.c", __PRETTY_FUNCTION__
, 12585)
) {
12586 ast_log(LOG_ERROR4, "app_voicemail.c", 12586, __PRETTY_FUNCTION__, "VM_INFO requires an argument (<mailbox>[@<context>],attribute[,folder])\n");
12587 return -1;
12588 }
12589
12590 parse = ast_strdupa(args)(__extension__ ({ const char *__old = (args); size_t __len = strlen
(__old) + 1; char *__new = __builtin_alloca(__len); memcpy (__new
, __old, __len); __new; }))
;
12591 AST_STANDARD_APP_ARGS(arg, parse)arg.argc = __ast_app_separate_args(parse, ',', 1, arg.argv, (
(sizeof(arg) - __builtin_offsetof(typeof(arg), argv)) / sizeof
(arg.argv[0])))
;
12592
12593 if (ast_strlen_zero(arg.mailbox_context)_ast_strlen_zero(arg.mailbox_context, "app_voicemail.c", __PRETTY_FUNCTION__
, 12593)
12594 || ast_strlen_zero(arg.attribute)_ast_strlen_zero(arg.attribute, "app_voicemail.c", __PRETTY_FUNCTION__
, 12594)
12595 || separate_mailbox(ast_strdupa(arg.mailbox_context)(__extension__ ({ const char *__old = (arg.mailbox_context); size_t
__len = strlen(__old) + 1; char *__new = __builtin_alloca(__len
); memcpy (__new, __old, __len); __new; }))
, &mailbox, &context)) {
12596 ast_log(LOG_ERROR4, "app_voicemail.c", 12596, __PRETTY_FUNCTION__, "VM_INFO requires an argument (<mailbox>[@<context>],attribute[,folder])\n");
12597 return -1;
12598 }
12599
12600 memset(&svm, 0, sizeof(svm));
12601 vmu = find_user(&svm, context, mailbox);
12602
12603 if (!strncasecmp(arg.attribute, "exists", 5)) {
12604 ast_copy_string(buf, vmu ? "1" : "0", len);
12605 free_user(vmu);
12606 return 0;
12607 }
12608
12609 if (vmu) {
12610 if (!strncasecmp(arg.attribute, "password", 8)) {
12611 ast_copy_string(buf, vmu->password, len);
12612 } else if (!strncasecmp(arg.attribute, "fullname", 8)) {
12613 ast_copy_string(buf, vmu->fullname, len);
12614 } else if (!strncasecmp(arg.attribute, "email", 5)) {
12615 ast_copy_string(buf, vmu->email, len);
12616 } else if (!strncasecmp(arg.attribute, "pager", 5)) {
12617 ast_copy_string(buf, vmu->pager, len);
12618 } else if (!strncasecmp(arg.attribute, "language", 8)) {
12619 ast_copy_string(buf, S_OR(vmu->language, ast_channel_language(chan))({typeof(&((vmu->language)[0])) __x = (vmu->language
); _ast_strlen_zero(__x, "app_voicemail.c", __PRETTY_FUNCTION__
, 12619) ? (ast_channel_language(chan)) : __x;})
, len);
12620 } else if (!strncasecmp(arg.attribute, "locale", 6)) {
12621 ast_copy_string(buf, vmu->locale, len);
12622 } else if (!strncasecmp(arg.attribute, "tz", 2)) {
12623 ast_copy_string(buf, vmu->zonetag, len);
12624 } else if (!strncasecmp(arg.attribute, "count", 5)) {
12625 char *mailbox_id;
12626
12627 mailbox_id = ast_alloca(strlen(mailbox) + strlen(context) + 2)__builtin_alloca(strlen(mailbox) + strlen(context) + 2);
12628 sprintf(mailbox_id, "%s@%s", mailbox, context);/* Safe */
12629
12630 /* If mbxfolder is empty messagecount will default to INBOX */
12631 res = messagecount(mailbox_id, arg.folder);
12632 if (res < 0) {
12633 ast_log(LOG_ERROR4, "app_voicemail.c", 12633, __PRETTY_FUNCTION__, "Unable to retrieve message count for mailbox %s\n", arg.mailbox_context);
12634 free_user(vmu);
12635 return -1;
12636 }
12637 snprintf(buf, len, "%d", res);
12638 } else {
12639 ast_log(LOG_ERROR4, "app_voicemail.c", 12639, __PRETTY_FUNCTION__, "Unknown attribute '%s' for VM_INFO\n", arg.attribute);
12640 free_user(vmu);
12641 return -1;
12642 }
12643 free_user(vmu);
12644 }
12645
12646 return 0;
12647}
12648
12649static struct ast_custom_function mailbox_exists_acf = {
12650 .name = "MAILBOX_EXISTS",
12651 .read = acf_mailbox_exists,
12652};
12653
12654static struct ast_custom_function vm_info_acf = {
12655 .name = "VM_INFO",
12656 .read = acf_vm_info,
12657};
12658
12659static int vmauthenticate(struct ast_channel *chan, const char *data)
12660{
12661 char *s, *user = NULL((void*)0), *context = NULL((void*)0), mailbox[AST_MAX_EXTENSION80] = "";
12662 struct ast_vm_user vmus;
12663 char *options = NULL((void*)0);
12664 int silent = 0, skipuser = 0;
12665 int res = -1;
12666
12667 if (data) {
12668 s = ast_strdupa(data)(__extension__ ({ const char *__old = (data); size_t __len = strlen
(__old) + 1; char *__new = __builtin_alloca(__len); memcpy (__new
, __old, __len); __new; }))
;
12669 user = strsep(&s, ",");
12670 options = strsep(&s, ",");
12671 if (user) {
12672 s = user;
12673 user = strsep(&s, "@");
12674 context = strsep(&s, "");
12675 if (!ast_strlen_zero(user)_ast_strlen_zero(user, "app_voicemail.c", __PRETTY_FUNCTION__
, 12675)
)
12676 skipuser++;
12677 ast_copy_string(mailbox, user, sizeof(mailbox));
12678 }
12679 }
12680
12681 if (options) {
12682 silent = (strchr(options, 's')(__extension__ (__builtin_constant_p ('s') && !__builtin_constant_p
(options) && ('s') == '\0' ? (char *) __rawmemchr (options
, 's') : __builtin_strchr (options, 's')))
) != NULL((void*)0);
12683 }
12684
12685 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL((void*)0), skipuser, 3, silent)) {
12686 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
12687 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
12688 ast_play_and_wait(chan, "auth-thankyou");
12689 res = 0;
12690 } else if (mailbox[0] == '*') {
12691 /* user entered '*' */
12692 if (!ast_goto_if_exists(chan, ast_channel_context(chan), "a", 1)) {
12693 res = 0; /* prevent hangup */
12694 }
12695 }
12696
12697 return res;
12698}
12699
12700static char *show_users_realtime(int fd, const char *context)
12701{
12702 struct ast_config *cfg;
12703 const char *cat = NULL((void*)0);
12704
12705 if (!(cfg = ast_load_realtime_multientry("voicemail",
12706 "context", context, SENTINEL((char *)((void*)0))))) {
12707 return CLI_FAILURE(char *)2;
12708 }
12709
12710 ast_cli(fd,
12711 "\n"
12712 "=============================================================\n"
12713 "=== Configured Voicemail Users ==============================\n"
12714 "=============================================================\n"
12715 "===\n");
12716
12717 while ((cat = ast_category_browse(cfg, cat))) {
12718 struct ast_variable *var = NULL((void*)0);
12719 ast_cli(fd,
12720 "=== Mailbox ...\n"
12721 "===\n");
12722 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
12723 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
12724 ast_cli(fd,
12725 "===\n"
12726 "=== ---------------------------------------------------------\n"
12727 "===\n");
12728 }
12729
12730 ast_cli(fd,
12731 "=============================================================\n"
12732 "\n");
12733
12734 ast_config_destroy(cfg);
12735
12736 return CLI_SUCCESS(char *)0;
12737}
12738
12739static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
12740{
12741 int which = 0;
12742 int wordlen;
12743 struct ast_vm_user *vmu;
12744 const char *context = "";
12745
12746 /* 0 - show; 1 - voicemail; 2 - users; 3 - for; 4 - <context> */
12747 if (pos > 4)
12748 return NULL((void*)0);
12749 if (pos == 3)
12750 return (state == 0) ? ast_strdup("for")_ast_strdup(("for"), "app_voicemail.c", 12750, __PRETTY_FUNCTION__
)
: NULL((void*)0);
12751 wordlen = strlen(word);
12752 AST_LIST_TRAVERSE(&users, vmu, list)for((vmu) = (&users)->first; (vmu); (vmu) = (vmu)->
list.next)
{
12753 if (!strncasecmp(word, vmu->context, wordlen)) {
12754 if (context && strcmp(context, vmu->context) && ++which > state)
12755 return ast_strdup(vmu->context)_ast_strdup((vmu->context), "app_voicemail.c", 12755, __PRETTY_FUNCTION__
)
;
12756 /* ignore repeated contexts ? */
12757 context = vmu->context;
12758 }
12759 }
12760 return NULL((void*)0);
12761}
12762
12763/*! \brief Show a list of voicemail users in the CLI */
12764static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12765{
12766 struct ast_vm_user *vmu;
12767#define HVSU_OUTPUT_FORMAT"%-10s %-5s %-25s %-10s %6s\n" "%-10s %-5s %-25s %-10s %6s\n"
12768 const char *context = NULL((void*)0);
12769 int users_counter = 0;
12770
12771 switch (cmd) {
12772 case CLI_INIT:
12773 e->command = "voicemail show users";
12774 e->usage =
12775 "Usage: voicemail show users [for <context>]\n"
12776 " Lists all mailboxes currently set up\n";
12777 return NULL((void*)0);
12778 case CLI_GENERATE:
12779 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
12780 }
12781
12782 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
12783 return CLI_SHOWUSAGE(char *)1;
12784 if (a->argc == 5) {
12785 if (strcmp(a->argv[3],"for"))
12786 return CLI_SHOWUSAGE(char *)1;
12787 context = a->argv[4];
12788 }
12789
12790 if (ast_check_realtime("voicemail")) {
12791 if (!context) {
12792 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
12793 return CLI_SHOWUSAGE(char *)1;
12794 }
12795 return show_users_realtime(a->fd, context);
12796 }
12797
12798 AST_LIST_LOCK(&users)__ast_pthread_mutex_lock("app_voicemail.c", 12798, __PRETTY_FUNCTION__
, "&(&users)->lock", &(&users)->lock)
;
12799 if (AST_LIST_EMPTY(&users)(((&users)->first) == ((void*)0))) {
12800 ast_cli(a->fd, "There are no voicemail users currently defined\n");
12801 AST_LIST_UNLOCK(&users)__ast_pthread_mutex_unlock("app_voicemail.c", 12801, __PRETTY_FUNCTION__
, "&(&users)->lock", &(&users)->lock)
;
12802 return CLI_FAILURE(char *)2;
12803 }
12804 if (!context) {
12805 ast_cli(a->fd, HVSU_OUTPUT_FORMAT"%-10s %-5s %-25s %-10s %6s\n", "Context", "Mbox", "User", "Zone", "NewMsg");
12806 } else {
12807 int count = 0;
12808 AST_LIST_TRAVERSE(&users, vmu, list)for((vmu) = (&users)->first; (vmu); (vmu) = (vmu)->
list.next)
{
12809 if (!strcmp(context, vmu->context)) {
12810 count++;
12811 break;
12812 }
12813 }
12814 if (count) {
12815 ast_cli(a->fd, HVSU_OUTPUT_FORMAT"%-10s %-5s %-25s %-10s %6s\n", "Context", "Mbox", "User", "Zone", "NewMsg");
12816 } else {
12817 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
12818 AST_LIST_UNLOCK(&users)__ast_pthread_mutex_unlock("app_voicemail.c", 12818, __PRETTY_FUNCTION__
, "&(&users)->lock", &(&users)->lock)
;
12819 return CLI_FAILURE(char *)2;
12820 }
12821 }
12822 AST_LIST_TRAVERSE(&users, vmu, list)for((vmu) = (&users)->first; (vmu); (vmu) = (vmu)->
list.next)
{
12823 int newmsgs = 0, oldmsgs = 0;
12824 char count[12], tmp[256] = "";
12825
12826 if (!context || !strcmp(context, vmu->context)) {
12827 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context)_ast_strlen_zero(vmu->context, "app_voicemail.c", __PRETTY_FUNCTION__
, 12827)
? "default" : vmu->context);
12828 inboxcount(tmp, &newmsgs, &oldmsgs);
12829 snprintf(count, sizeof(count), "%d", newmsgs);
12830 ast_cli(a->fd, HVSU_OUTPUT_FORMAT"%-10s %-5s %-25s %-10s %6s\n", vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
12831 users_counter++;
12832 }
12833 }
12834 AST_LIST_UNLOCK(&users)__ast_pthread_mutex_unlock("app_voicemail.c", 12834, __PRETTY_FUNCTION__
, "&(&users)->lock", &(&users)->lock)
;
12835 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
12836 return CLI_SUCCESS(char *)0;
12837}
12838
12839/*! \brief Show a list of voicemail zones in the CLI */
12840static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12841{
12842 struct vm_zone *zone;
12843#define HVSZ_OUTPUT_FORMAT"%-15s %-20s %-45s\n" "%-15s %-20s %-45s\n"
12844 char *res = CLI_SUCCESS(char *)0;
12845
12846 switch (cmd) {
12847 case CLI_INIT:
12848 e->command = "voicemail show zones";
12849 e->usage =
12850 "Usage: voicemail show zones\n"
12851 " Lists zone message formats\n";
12852 return NULL((void*)0);
12853 case CLI_GENERATE:
12854 return NULL((void*)0);
12855 }
12856
12857 if (a->argc != 3)
12858 return CLI_SHOWUSAGE(char *)1;
12859
12860 AST_LIST_LOCK(&zones)__ast_pthread_mutex_lock("app_voicemail.c", 12860, __PRETTY_FUNCTION__
, "&(&zones)->lock", &(&zones)->lock)
;
12861 if (!AST_LIST_EMPTY(&zones)(((&zones)->first) == ((void*)0))) {
12862 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT"%-15s %-20s %-45s\n", "Zone", "Timezone", "Message Format");
12863 AST_LIST_TRAVERSE(&zones, zone, list)for((zone) = (&zones)->first; (zone); (zone) = (zone)->
list.next)
{
12864 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT"%-15s %-20s %-45s\n", zone->name, zone->timezone, zone->msg_format);
12865 }
12866 } else {
12867 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
12868 res = CLI_FAILURE(char *)2;
12869 }
12870 AST_LIST_UNLOCK(&zones)__ast_pthread_mutex_unlock("app_voicemail.c", 12870, __PRETTY_FUNCTION__
, "&(&zones)->lock", &(&zones)->lock)
;
12871
12872 return res;
12873}
12874
12875/*! \brief Reload voicemail configuration from the CLI */
12876static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12877{
12878 switch (cmd) {
12879 case CLI_INIT:
12880 e->command = "voicemail reload";
12881 e->usage =
12882 "Usage: voicemail reload\n"
12883 " Reload voicemail configuration\n";
12884 return NULL((void*)0);
12885 case CLI_GENERATE:
12886 return NULL((void*)0);
12887 }
12888
12889 if (a->argc != 2)
12890 return CLI_SHOWUSAGE(char *)1;
12891
12892 ast_cli(a->fd, "Reloading voicemail configuration...\n");
12893 load_config(1);
12894
12895 return CLI_SUCCESS(char *)0;
12896}
12897
12898static struct ast_cli_entry cli_voicemail[] = {
12899 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"){ .handler = handle_voicemail_show_users, .summary = "List defined voicemail boxes"
}
,
12900 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"){ .handler = handle_voicemail_show_zones, .summary = "List zone message formats"
}
,
12901 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"){ .handler = handle_voicemail_reload, .summary = "Reload voicemail configuration"
}
,
12902};
12903
12904#ifdef IMAP_STORAGE
12905 #define DATA_EXPORT_VM_USERS(USER)USER(ast_vm_user, context, AST_DATA_STRING) USER(ast_vm_user,
mailbox, AST_DATA_STRING) USER(ast_vm_user, password, AST_DATA_PASSWORD
) USER(ast_vm_user, fullname, AST_DATA_STRING) USER(ast_vm_user
, email, AST_DATA_STRING) USER(ast_vm_user, emailsubject, AST_DATA_STRING
) USER(ast_vm_user, emailbody, AST_DATA_STRING) USER(ast_vm_user
, pager, AST_DATA_STRING) USER(ast_vm_user, serveremail, AST_DATA_STRING
) USER(ast_vm_user, language, AST_DATA_STRING) USER(ast_vm_user
, zonetag, AST_DATA_STRING) USER(ast_vm_user, callback, AST_DATA_STRING
) USER(ast_vm_user, dialout, AST_DATA_STRING) USER(ast_vm_user
, uniqueid, AST_DATA_STRING) USER(ast_vm_user, exit, AST_DATA_STRING
) USER(ast_vm_user, attachfmt, AST_DATA_STRING) USER(ast_vm_user
, flags, AST_DATA_UNSIGNED_INTEGER) USER(ast_vm_user, saydurationm
, AST_DATA_INTEGER) USER(ast_vm_user, maxmsg, AST_DATA_INTEGER
) USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) USER(ast_vm_user
, maxsecs, AST_DATA_INTEGER) USER(ast_vm_user, volgain, AST_DATA_DOUBLE
)
\
12906 USER(ast_vm_user, context, AST_DATA_STRING) \
12907 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
12908 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
12909 USER(ast_vm_user, fullname, AST_DATA_STRING) \
12910 USER(ast_vm_user, email, AST_DATA_STRING) \
12911 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
12912 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
12913 USER(ast_vm_user, pager, AST_DATA_STRING) \
12914 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
12915 USER(ast_vm_user, language, AST_DATA_STRING) \
12916 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
12917 USER(ast_vm_user, callback, AST_DATA_STRING) \
12918 USER(ast_vm_user, dialout, AST_DATA_STRING) \
12919 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
12920 USER(ast_vm_user, exit, AST_DATA_STRING) \
12921 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
12922 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
12923 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
12924 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
12925 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
12926 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
12927 USER(ast_vm_user, imapuser, AST_DATA_STRING) \
12928 USER(ast_vm_user, imappassword, AST_DATA_STRING) \
12929 USER(ast_vm_user, imapvmshareid, AST_DATA_STRING) \
12930 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
12931#else
12932 #define DATA_EXPORT_VM_USERS(USER)USER(ast_vm_user, context, AST_DATA_STRING) USER(ast_vm_user,
mailbox, AST_DATA_STRING) USER(ast_vm_user, password, AST_DATA_PASSWORD
) USER(ast_vm_user, fullname, AST_DATA_STRING) USER(ast_vm_user
, email, AST_DATA_STRING) USER(ast_vm_user, emailsubject, AST_DATA_STRING
) USER(ast_vm_user, emailbody, AST_DATA_STRING) USER(ast_vm_user
, pager, AST_DATA_STRING) USER(ast_vm_user, serveremail, AST_DATA_STRING
) USER(ast_vm_user, language, AST_DATA_STRING) USER(ast_vm_user
, zonetag, AST_DATA_STRING) USER(ast_vm_user, callback, AST_DATA_STRING
) USER(ast_vm_user, dialout, AST_DATA_STRING) USER(ast_vm_user
, uniqueid, AST_DATA_STRING) USER(ast_vm_user, exit, AST_DATA_STRING
) USER(ast_vm_user, attachfmt, AST_DATA_STRING) USER(ast_vm_user
, flags, AST_DATA_UNSIGNED_INTEGER) USER(ast_vm_user, saydurationm
, AST_DATA_INTEGER) USER(ast_vm_user, maxmsg, AST_DATA_INTEGER
) USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) USER(ast_vm_user
, maxsecs, AST_DATA_INTEGER) USER(ast_vm_user, volgain, AST_DATA_DOUBLE
)
\
12933 USER(ast_vm_user, context, AST_DATA_STRING) \
12934 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
12935 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
12936 USER(ast_vm_user, fullname, AST_DATA_STRING) \
12937 USER(ast_vm_user, email, AST_DATA_STRING) \
12938 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
12939 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
12940 USER(ast_vm_user, pager, AST_DATA_STRING) \
12941 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
12942 USER(ast_vm_user, language, AST_DATA_STRING) \
12943 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
12944 USER(ast_vm_user, callback, AST_DATA_STRING) \
12945 USER(ast_vm_user, dialout, AST_DATA_STRING) \
12946 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
12947 USER(ast_vm_user, exit, AST_DATA_STRING) \
12948 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
12949 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
12950 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
12951 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
12952 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
12953 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
12954 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
12955#endif
12956
12957AST_DATA_STRUCTURE(ast_vm_user, DATA_EXPORT_VM_USERS)static char * data_mapping_structure_get_ast_vm_usercontext(void
*ptr) { struct ast_vm_user *struct_context = (struct ast_vm_user
*) ptr; return (char *) struct_context->context; } static
char * data_mapping_structure_get_ast_vm_usermailbox(void *ptr
) { struct ast_vm_user *struct_mailbox = (struct ast_vm_user *
) ptr; return (char *) struct_mailbox->mailbox; } static char
* data_mapping_structure_get_ast_vm_userpassword(void *ptr) {
struct ast_vm_user *struct_password = (struct ast_vm_user *)
ptr; return (char *) struct_password->password; } static char
* data_mapping_structure_get_ast_vm_userfullname(void *ptr) {
struct ast_vm_user *struct_fullname = (struct ast_vm_user *)
ptr; return (char *) struct_fullname->fullname; } static char
* data_mapping_structure_get_ast_vm_useremail(void *ptr) { struct
ast_vm_user *struct_email = (struct ast_vm_user *) ptr; return
(char *) struct_email->email; } static char * data_mapping_structure_get_ast_vm_useremailsubject
(void *ptr) { struct ast_vm_user *struct_emailsubject = (struct
ast_vm_user *) ptr; return (char *) struct_emailsubject->
emailsubject; } static char * data_mapping_structure_get_ast_vm_useremailbody
(void *ptr) { struct ast_vm_user *struct_emailbody = (struct ast_vm_user
*) ptr; return (char *) struct_emailbody->emailbody; } static
char * data_mapping_structure_get_ast_vm_userpager(void *ptr
) { struct ast_vm_user *struct_pager = (struct ast_vm_user *)
ptr; return (char *) struct_pager->pager; } static char *
data_mapping_structure_get_ast_vm_userserveremail(void *ptr)
{ struct ast_vm_user *struct_serveremail = (struct ast_vm_user
*) ptr; return (char *) struct_serveremail->serveremail; }
static char * data_mapping_structure_get_ast_vm_userlanguage
(void *ptr) { struct ast_vm_user *struct_language = (struct ast_vm_user
*) ptr; return (char *) struct_language->language; } static
char * data_mapping_structure_get_ast_vm_userzonetag(void *ptr
) { struct ast_vm_user *struct_zonetag = (struct ast_vm_user *
) ptr; return (char *) struct_zonetag->zonetag; } static char
* data_mapping_structure_get_ast_vm_usercallback(void *ptr) {
struct ast_vm_user *struct_callback = (struct ast_vm_user *)
ptr; return (char *) struct_callback->callback; } static char
* data_mapping_structure_get_ast_vm_userdialout(void *ptr) {
struct ast_vm_user *struct_dialout = (struct ast_vm_user *) ptr
; return (char *) struct_dialout->dialout; } static char *
data_mapping_structure_get_ast_vm_useruniqueid(void *ptr) { struct
ast_vm_user *struct_uniqueid = (struct ast_vm_user *) ptr; return
(char *) struct_uniqueid->uniqueid; } static char * data_mapping_structure_get_ast_vm_userexit
(void *ptr) { struct ast_vm_user *struct_exit = (struct ast_vm_user
*) ptr; return (char *) struct_exit->exit; } static char *
data_mapping_structure_get_ast_vm_userattachfmt(void *ptr) {
struct ast_vm_user *struct_attachfmt = (struct ast_vm_user *
) ptr; return (char *) struct_attachfmt->attachfmt; } static
unsigned int data_mapping_structure_get_ast_vm_userflags(void
*ptr) { struct ast_vm_user *struct_flags = (struct ast_vm_user
*) ptr; return (unsigned int) struct_flags->flags; } static
int data_mapping_structure_get_ast_vm_usersaydurationm(void *
ptr) { struct ast_vm_user *struct_saydurationm = (struct ast_vm_user
*) ptr; return (int) struct_saydurationm->saydurationm; }
static int data_mapping_structure_get_ast_vm_usermaxmsg(void
*ptr) { struct ast_vm_user *struct_maxmsg = (struct ast_vm_user
*) ptr; return (int) struct_maxmsg->maxmsg; } static int data_mapping_structure_get_ast_vm_usermaxdeletedmsg
(void *ptr) { struct ast_vm_user *struct_maxdeletedmsg = (struct
ast_vm_user *) ptr; return (int) struct_maxdeletedmsg->maxdeletedmsg
; } static int data_mapping_structure_get_ast_vm_usermaxsecs(
void *ptr) { struct ast_vm_user *struct_maxsecs = (struct ast_vm_user
*) ptr; return (int) struct_maxsecs->maxsecs; } static double
data_mapping_structure_get_ast_vm_uservolgain(void *ptr) { struct
ast_vm_user *struct_volgain = (struct ast_vm_user *) ptr; return
(double) struct_volgain->volgain; }; static const struct ast_data_mapping_structure
__data_mapping_structure_ast_vm_user[] = { { .name = "context"
, .get.AST_DATA_STRING = data_mapping_structure_get_ast_vm_usercontext
, .type = AST_DATA_STRING }, { .name = "mailbox", .get.AST_DATA_STRING
= data_mapping_structure_get_ast_vm_usermailbox, .type = AST_DATA_STRING
}, { .name = "password", .get.AST_DATA_PASSWORD = data_mapping_structure_get_ast_vm_userpassword
, .type = AST_DATA_PASSWORD }, { .name = "fullname", .get.AST_DATA_STRING
= data_mapping_structure_get_ast_vm_userfullname, .type = AST_DATA_STRING
}, { .name = "email", .get.AST_DATA_STRING = data_mapping_structure_get_ast_vm_useremail
, .type = AST_DATA_STRING }, { .name = "emailsubject", .get.AST_DATA_STRING
= data_mapping_structure_get_ast_vm_useremailsubject, .type =
AST_DATA_STRING }, { .name = "emailbody", .get.AST_DATA_STRING
= data_mapping_structure_get_ast_vm_useremailbody, .type = AST_DATA_STRING
}, { .name = "pager", .get.AST_DATA_STRING = data_mapping_structure_get_ast_vm_userpager
, .type = AST_DATA_STRING }, { .name = "serveremail", .get.AST_DATA_STRING
= data_mapping_structure_get_ast_vm_userserveremail, .type =
AST_DATA_STRING }, { .name = "language", .get.AST_DATA_STRING
= data_mapping_structure_get_ast_vm_userlanguage, .type = AST_DATA_STRING
}, { .name = "zonetag", .get.AST_DATA_STRING = data_mapping_structure_get_ast_vm_userzonetag
, .type = AST_DATA_STRING }, { .name = "callback", .get.AST_DATA_STRING
= data_mapping_structure_get_ast_vm_usercallback, .type = AST_DATA_STRING
}, { .name = "dialout", .get.AST_DATA_STRING = data_mapping_structure_get_ast_vm_userdialout
, .type = AST_DATA_STRING }, { .name = "uniqueid", .get.AST_DATA_STRING
= data_mapping_structure_get_ast_vm_useruniqueid, .type = AST_DATA_STRING
}, { .name = "exit", .get.AST_DATA_STRING = data_mapping_structure_get_ast_vm_userexit
, .type = AST_DATA_STRING }, { .name = "attachfmt", .get.AST_DATA_STRING
= data_mapping_structure_get_ast_vm_userattachfmt, .type = AST_DATA_STRING
}, { .name = "flags", .get.AST_DATA_UNSIGNED_INTEGER = data_mapping_structure_get_ast_vm_userflags
, .type = AST_DATA_UNSIGNED_INTEGER }, { .name = "saydurationm"
, .get.AST_DATA_INTEGER = data_mapping_structure_get_ast_vm_usersaydurationm
, .type = AST_DATA_INTEGER }, { .name = "maxmsg", .get.AST_DATA_INTEGER
= data_mapping_structure_get_ast_vm_usermaxmsg, .type = AST_DATA_INTEGER
}, { .name = "maxdeletedmsg", .get.AST_DATA_INTEGER = data_mapping_structure_get_ast_vm_usermaxdeletedmsg
, .type = AST_DATA_INTEGER }, { .name = "maxsecs", .get.AST_DATA_INTEGER
= data_mapping_structure_get_ast_vm_usermaxsecs, .type = AST_DATA_INTEGER
}, { .name = "volgain", .get.AST_DATA_DOUBLE = data_mapping_structure_get_ast_vm_uservolgain
, .type = AST_DATA_DOUBLE }, }
;
12958
12959#define DATA_EXPORT_VM_ZONES(ZONE)ZONE(vm_zone, name, AST_DATA_STRING) ZONE(vm_zone, timezone, AST_DATA_STRING
) ZONE(vm_zone, msg_format, AST_DATA_STRING)
\
12960 ZONE(vm_zone, name, AST_DATA_STRING) \
12961 ZONE(vm_zone, timezone, AST_DATA_STRING) \
12962 ZONE(vm_zone, msg_format, AST_DATA_STRING)
12963
12964AST_DATA_STRUCTURE(vm_zone, DATA_EXPORT_VM_ZONES)static char * data_mapping_structure_get_vm_zonename(void *ptr
) { struct vm_zone *struct_name = (struct vm_zone *) ptr; return
(char *) struct_name->name; } static char * data_mapping_structure_get_vm_zonetimezone
(void *ptr) { struct vm_zone *struct_timezone = (struct vm_zone
*) ptr; return (char *) struct_timezone->timezone; } static
char * data_mapping_structure_get_vm_zonemsg_format(void *ptr
) { struct vm_zone *struct_msg_format = (struct vm_zone *) ptr
; return (char *) struct_msg_format->msg_format; }; static
const struct ast_data_mapping_structure __data_mapping_structure_vm_zone
[] = { { .name = "name", .get.AST_DATA_STRING = data_mapping_structure_get_vm_zonename
, .type = AST_DATA_STRING }, { .name = "timezone", .get.AST_DATA_STRING
= data_mapping_structure_get_vm_zonetimezone, .type = AST_DATA_STRING
}, { .name = "msg_format", .get.AST_DATA_STRING = data_mapping_structure_get_vm_zonemsg_format
, .type = AST_DATA_STRING }, }
;
12965
12966/*!
12967 * \internal
12968 * \brief Add voicemail user to the data_root.
12969 * \param[in] search The search tree.
12970 * \param[in] data_root The main result node.
12971 * \param[in] user The voicemail user.
12972 */
12973static int vm_users_data_provider_get_helper(const struct ast_data_search *search,
12974 struct ast_data *data_root, struct ast_vm_user *user)
12975{
12976 struct ast_data *data_user, *data_zone;
12977 struct ast_data *data_state;
12978 struct vm_zone *zone = NULL((void*)0);
12979 int urgentmsg = 0, newmsg = 0, oldmsg = 0;
12980 char ext_context[256] = "";
12981
12982 data_user = ast_data_add_node(data_root, "user");
12983 if (!data_user) {
12984 return -1;
12985 }
12986
12987 ast_data_add_structure(ast_vm_user, data_user, user)__ast_data_add_structure(data_user, __data_mapping_structure_ast_vm_user
, (size_t) (sizeof(__data_mapping_structure_ast_vm_user) / sizeof
(0[__data_mapping_structure_ast_vm_user])), user)
;
12988
12989 AST_LIST_LOCK(&zones)__ast_pthread_mutex_lock("app_voicemail.c", 12989, __PRETTY_FUNCTION__
, "&(&zones)->lock", &(&zones)->lock)
;
12990 AST_LIST_TRAVERSE(&zones, zone, list)for((zone) = (&zones)->first; (zone); (zone) = (zone)->
list.next)
{
12991 if (!strcmp(zone->name, user->zonetag)) {
12992 break;
12993 }
12994 }
12995 AST_LIST_UNLOCK(&zones)__ast_pthread_mutex_unlock("app_voicemail.c", 12995, __PRETTY_FUNCTION__
, "&(&zones)->lock", &(&zones)->lock)
;
12996
12997 /* state */
12998 data_state = ast_data_add_node(data_user, "state");
12999 if (!data_state) {
13000 return -1;
13001 }
13002 snprintf(ext_context, sizeof(ext_context), "%s@%s", user->mailbox, user->context);
13003 inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg);
13004 ast_data_add_int(data_state, "urgentmsg", urgentmsg);
13005 ast_data_add_int(data_state, "newmsg", newmsg);
13006 ast_data_add_int(data_state, "oldmsg", oldmsg);
13007
13008 if (zone) {
13009 data_zone = ast_data_add_node(data_user, "zone");
13010 ast_data_add_structure(vm_zone, data_zone, zone)__ast_data_add_structure(data_zone, __data_mapping_structure_vm_zone
, (size_t) (sizeof(__data_mapping_structure_vm_zone) / sizeof
(0[__data_mapping_structure_vm_zone])), zone)
;
13011 }
13012
13013 if (!ast_data_search_match(search, data_user)) {
13014 ast_data_remove_node(data_root, data_user);
13015 }
13016
13017 return 0;
13018}
13019
13020static int vm_users_data_provider_get(const struct ast_data_search *search,
13021 struct ast_data *data_root)
13022{
13023 struct ast_vm_user *user;
13024
13025 AST_LIST_LOCK(&users)__ast_pthread_mutex_lock("app_voicemail.c", 13025, __PRETTY_FUNCTION__
, "&(&users)->lock", &(&users)->lock)
;
13026 AST_LIST_TRAVERSE(&users, user, list)for((user) = (&users)->first; (user); (user) = (user)->
list.next)
{
13027 vm_users_data_provider_get_helper(search, data_root, user);
13028 }
13029 AST_LIST_UNLOCK(&users)__ast_pthread_mutex_unlock("app_voicemail.c", 13029, __PRETTY_FUNCTION__
, "&(&users)->lock", &(&users)->lock)
;
13030
13031 return 0;
13032}
13033
13034static const struct ast_data_handler vm_users_data_provider = {
13035 .version = AST_DATA_HANDLER_VERSION1,
13036 .get = vm_users_data_provider_get
13037};
13038
13039static const struct ast_data_entry vm_data_providers[] = {
13040 AST_DATA_ENTRY("asterisk/application/voicemail/list", &vm_users_data_provider){ .path = "asterisk/application/voicemail/list", .handler = &
vm_users_data_provider }
13041};
13042
13043static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
13044{
13045 int new = 0, old = 0, urgent = 0;
13046
13047 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
13048
13049 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
13050 mwi_sub->old_urgent = urgent;
13051 mwi_sub->old_new = new;
13052 mwi_sub->old_old = old;
13053 queue_mwi_event(NULL((void*)0), mwi_sub->mailbox, urgent, new, old);
13054 run_externnotify(NULL((void*)0), mwi_sub->mailbox, NULL((void*)0));
13055 }
13056}
13057
13058static void poll_subscribed_mailboxes(void)
13059{
13060 struct mwi_sub *mwi_sub;
13061
13062 AST_RWLIST_RDLOCK(&mwi_subs)__ast_rwlock_rdlock("app_voicemail.c", 13062, __PRETTY_FUNCTION__
, &(&mwi_subs)->lock, "&(&mwi_subs)->lock"
)
;
13063 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry)for((mwi_sub) = (&mwi_subs)->first; (mwi_sub); (mwi_sub
) = (mwi_sub)->entry.next)
{
13064 if (!ast_strlen_zero(mwi_sub->mailbox)_ast_strlen_zero(mwi_sub->mailbox, "app_voicemail.c", __PRETTY_FUNCTION__
, 13064)
) {
13065 poll_subscribed_mailbox(mwi_sub);
13066 }
13067 }
13068 AST_RWLIST_UNLOCK(&mwi_subs)__ast_rwlock_unlock("app_voicemail.c", 13068, __PRETTY_FUNCTION__
, &(&mwi_subs)->lock, "&(&mwi_subs)->lock"
)
;
13069}
13070
13071static void *mb_poll_thread(void *data)
13072{
13073 while (poll_thread_run) {
13074 struct timespec ts = { 0, };
13075 struct timeval wait;
13076
13077 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
13078 ts.tv_sec = wait.tv_sec;
13079 ts.tv_nsec = wait.tv_usec * 1000;
13080
13081 ast_mutex_lock(&poll_lock)__ast_pthread_mutex_lock("app_voicemail.c", 13081, __PRETTY_FUNCTION__
, "&poll_lock", &poll_lock)
;
13082 ast_cond_timedwait(&poll_cond, &poll_lock, &ts)__ast_cond_timedwait("app_voicemail.c", 13082, __PRETTY_FUNCTION__
, "&poll_cond", "&poll_lock", &poll_cond, &poll_lock
, &ts)
;
13083 ast_mutex_unlock(&poll_lock)__ast_pthread_mutex_unlock("app_voicemail.c", 13083, __PRETTY_FUNCTION__
, "&poll_lock", &poll_lock)
;
13084
13085 if (!poll_thread_run)
13086 break;
13087
13088 poll_subscribed_mailboxes();
13089 }
13090
13091 return NULL((void*)0);
13092}
13093
13094static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
13095{
13096 ast_freefree(mwi_sub->uniqueid);
13097 ast_freefree(mwi_sub);
13098}
13099
13100static int handle_unsubscribe(void *datap)
13101{
13102 struct mwi_sub *mwi_sub;
13103 char *uniqueid = datap;
13104
13105 AST_RWLIST_WRLOCK(&mwi_subs)__ast_rwlock_wrlock("app_voicemail.c", 13105, __PRETTY_FUNCTION__
, &(&mwi_subs)->lock, "&(&mwi_subs)->lock"
)
;
13106 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry){ typeof((&mwi_subs)) __list_head = &mwi_subs; typeof
(__list_head->first) __list_next; typeof(__list_head->first
) __list_prev = ((void*)0); typeof(__list_head->first) __list_current
; for ((mwi_sub) = __list_head->first, __list_current = (mwi_sub
), __list_next = (mwi_sub) ? (mwi_sub)->entry.next : ((void
*)0); (mwi_sub); __list_prev = __list_current, (mwi_sub) = __list_next
, __list_current = (mwi_sub), __list_next = (mwi_sub) ? (mwi_sub
)->entry.next : ((void*)0), (void) __list_prev )
{
13107 if (!strcmp(mwi_sub->uniqueid, uniqueid)) {
13108 AST_LIST_REMOVE_CURRENT(entry)do { __list_current->entry.next = ((void*)0); __list_current
= __list_prev; if (__list_prev) { __list_prev->entry.next
= __list_next; } else { __list_head->first = __list_next;
} if (!__list_next) { __list_head->last = __list_prev; } }
while (0)
;
13109 /* Don't break here since a duplicate uniqueid
13110 * may have been added as a result of a cache dump. */
13111 mwi_sub_destroy(mwi_sub);
13112 }
13113 }
13114 AST_RWLIST_TRAVERSE_SAFE_END}
13115 AST_RWLIST_UNLOCK(&mwi_subs)__ast_rwlock_unlock("app_voicemail.c", 13115, __PRETTY_FUNCTION__
, &(&mwi_subs)->lock, "&(&mwi_subs)->lock"
)
;
13116
13117 ast_freefree(uniqueid);
13118 return 0;
13119}
13120
13121static int handle_subscribe(void *datap)
13122{
13123 unsigned int len;
13124 struct mwi_sub *mwi_sub;
13125 struct mwi_sub_task *p = datap;
13126
13127 len = sizeof(*mwi_sub);
13128 if (!ast_strlen_zero(p->mailbox)_ast_strlen_zero(p->mailbox, "app_voicemail.c", __PRETTY_FUNCTION__
, 13128)
)
1
Taking false branch
13129 len += strlen(p->mailbox);
13130
13131 if (!ast_strlen_zero(p->context)_ast_strlen_zero(p->context, "app_voicemail.c", __PRETTY_FUNCTION__
, 13131)
)
2
Taking true branch
13132 len += strlen(p->context) + 1; /* Allow for seperator */
13133
13134 if (!(mwi_sub = ast_calloc(1, len)_ast_calloc((1), (len), "app_voicemail.c", 13134, __PRETTY_FUNCTION__
)
))
3
Taking false branch
13135 return -1;
13136
13137 mwi_sub->uniqueid = ast_strdup(p->uniqueid)_ast_strdup((p->uniqueid), "app_voicemail.c", 13137, __PRETTY_FUNCTION__
)
;
13138 if (!ast_strlen_zero(p->mailbox)_ast_strlen_zero(p->mailbox, "app_voicemail.c", __PRETTY_FUNCTION__
, 13138)
)
4
Taking false branch
13139 strcpy(mwi_sub->mailbox, p->mailbox);
13140
13141 if (!ast_strlen_zero(p->context)_ast_strlen_zero(p->context, "app_voicemail.c", __PRETTY_FUNCTION__
, 13141)
) {
5
Taking true branch
13142 strcat(mwi_sub->mailbox, "@");
6
String copy function overflows destination buffer
13143 strcat(mwi_sub->mailbox, p->context);
13144 }
13145
13146 AST_RWLIST_WRLOCK(&mwi_subs)__ast_rwlock_wrlock("app_voicemail.c", 13146, __PRETTY_FUNCTION__
, &(&mwi_subs)->lock, "&(&mwi_subs)->lock"
)
;
13147 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry)do { if (!(&mwi_subs)->first) { (&mwi_subs)->first
= (mwi_sub); (&mwi_subs)->last = (mwi_sub); } else { (
&mwi_subs)->last->entry.next = (mwi_sub); (&mwi_subs
)->last = (mwi_sub); } } while (0)
;
13148 AST_RWLIST_UNLOCK(&mwi_subs)__ast_rwlock_unlock("app_voicemail.c", 13148, __PRETTY_FUNCTION__
, &(&mwi_subs)->lock, "&(&mwi_subs)->lock"
)
;
13149 mwi_sub_task_dtor(p);
13150 poll_subscribed_mailbox(mwi_sub);
13151 return 0;
13152}
13153
13154static void mwi_unsub_event_cb(struct stasis_subscription_change *change)
13155{
13156 char *uniqueid = ast_strdup(change->uniqueid)_ast_strdup((change->uniqueid), "app_voicemail.c", 13156, __PRETTY_FUNCTION__
)
;
13157
13158 if (!uniqueid) {
13159 ast_log(LOG_ERROR4, "app_voicemail.c", 13159, __PRETTY_FUNCTION__, "Unable to allocate memory for uniqueid\n");
13160 return;
13161 }
13162
13163 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
13164 ast_freefree(uniqueid);
13165 }
13166}
13167
13168static void mwi_sub_event_cb(struct stasis_subscription_change *change)
13169{
13170 struct mwi_sub_task *mwist;
13171 char *context;
13172 char *mailbox;
13173
13174 mwist = ast_calloc(1, (sizeof(*mwist)))_ast_calloc((1), ((sizeof(*mwist))), "app_voicemail.c", 13174
, __PRETTY_FUNCTION__)
;
13175 if (!mwist) {
13176 return;
13177 }
13178
13179 if (separate_mailbox(ast_strdupa(stasis_topic_name(change->topic))(__extension__ ({ const char *__old = (stasis_topic_name(change
->topic)); size_t __len = strlen(__old) + 1; char *__new =
__builtin_alloca(__len); memcpy (__new, __old, __len); __new
; }))
, &mailbox, &context)) {
13180 return;
13181 }
13182
13183 mwist->mailbox = ast_strdup(mailbox)_ast_strdup((mailbox), "app_voicemail.c", 13183, __PRETTY_FUNCTION__
)
;
13184 mwist->context = ast_strdup(context)_ast_strdup((context), "app_voicemail.c", 13184, __PRETTY_FUNCTION__
)
;
13185 mwist->uniqueid = ast_strdup(change->uniqueid)_ast_strdup((change->uniqueid), "app_voicemail.c", 13185, __PRETTY_FUNCTION__
)
;
13186
13187 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
13188 mwi_sub_task_dtor(mwist);
13189 }
13190}
13191
13192static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
13193{
13194 struct stasis_subscription_change *change;
13195 /* Only looking for subscription change notices here */
13196 if (stasis_message_type(msg) != stasis_subscription_change_type()) {
13197 return;
13198 }
13199
13200 change = stasis_message_data(msg);
13201 if (change->topic == ast_mwi_topic_all()) {
13202 return;
13203 }
13204
13205 if (!strcmp(change->description, "Subscribe")) {
13206 mwi_sub_event_cb(change);
13207 } else if (!strcmp(change->description, "Unsubscribe")) {
13208 mwi_unsub_event_cb(change);
13209 }
13210}
13211
13212static int dump_cache(void *obj, void *arg, int flags)
13213{
13214 struct stasis_message *msg = obj;
13215 mwi_event_cb(NULL((void*)0), NULL((void*)0), msg);
13216 return 0;
13217}
13218
13219static void start_poll_thread(void)
13220{
13221 int errcode;
13222 mwi_sub_sub = stasis_subscribe(ast_mwi_topic_all(), mwi_event_cb, NULL((void*)0));
13223
13224 if (mwi_sub_sub) {
13225 struct ao2_container *cached = stasis_cache_dump(ast_mwi_state_cache(), stasis_subscription_change_type());
13226 if (cached) {
13227 ao2_callback(cached, OBJ_MULTIPLE | OBJ_NODATA, dump_cache, NULL)__ao2_callback((cached), (OBJ_MULTIPLE | OBJ_NODATA), (dump_cache
), (((void*)0)), "", "app_voicemail.c", 13227, __PRETTY_FUNCTION__
)
;
13228 }
13229 ao2_cleanup(cached)__ao2_cleanup_debug((cached), "", "app_voicemail.c", 13229, __PRETTY_FUNCTION__
)
;
13230 }
13231
13232 poll_thread_run = 1;
13233
13234 if ((errcode = ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL)ast_pthread_create_stack(&poll_thread, ((void*)0), mb_poll_thread
, ((void*)0), 0, "app_voicemail.c", __FUNCTION__, 13234, "mb_poll_thread"
)
)) {
13235 ast_log(LOG_ERROR4, "app_voicemail.c", 13235, __PRETTY_FUNCTION__, "Could not create thread: %s\n", strerror(errcode));
13236 }
13237}
13238
13239static void stop_poll_thread(void)
13240{
13241 poll_thread_run = 0;
13242
13243 mwi_sub_sub = stasis_unsubscribe_and_join(mwi_sub_sub);
13244
13245 ast_mutex_lock(&poll_lock)__ast_pthread_mutex_lock("app_voicemail.c", 13245, __PRETTY_FUNCTION__
, "&poll_lock", &poll_lock)
;
13246 ast_cond_signal(&poll_cond)__ast_cond_signal("app_voicemail.c", 13246, __PRETTY_FUNCTION__
, "&poll_cond", &poll_cond)
;
13247 ast_mutex_unlock(&poll_lock)__ast_pthread_mutex_unlock("app_voicemail.c", 13247, __PRETTY_FUNCTION__
, "&poll_lock", &poll_lock)
;
13248
13249 pthread_join(poll_thread, NULL((void*)0));
13250
13251 poll_thread = AST_PTHREADT_NULL(pthread_t) -1;
13252}
13253
13254static int manager_voicemail_refresh(struct mansession *s, const struct message *m)
13255{
13256 const char *context = astman_get_header(m, "Context");
13257 const char *mailbox = astman_get_header(m, "Mailbox");
13258 struct mwi_sub *mwi_sub;
13259 const char *at;
13260
13261 AST_RWLIST_RDLOCK(&mwi_subs)__ast_rwlock_rdlock("app_voicemail.c", 13261, __PRETTY_FUNCTION__
, &(&mwi_subs)->lock, "&(&mwi_subs)->lock"
)
;
13262 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry)for((mwi_sub) = (&mwi_subs)->first; (mwi_sub); (mwi_sub
) = (mwi_sub)->entry.next)
{
13263 if (!ast_strlen_zero(mwi_sub->mailbox)_ast_strlen_zero(mwi_sub->mailbox, "app_voicemail.c", __PRETTY_FUNCTION__
, 13263)
) {
13264 if (
13265 /* First case: everything matches */
13266 (ast_strlen_zero(context)_ast_strlen_zero(context, "app_voicemail.c", __PRETTY_FUNCTION__
, 13266)
&& ast_strlen_zero(mailbox)_ast_strlen_zero(mailbox, "app_voicemail.c", __PRETTY_FUNCTION__
, 13266)
) ||
13267 /* Second case: match the mailbox only */
13268 (ast_strlen_zero(context)_ast_strlen_zero(context, "app_voicemail.c", __PRETTY_FUNCTION__
, 13268)
&& !ast_strlen_zero(mailbox)_ast_strlen_zero(mailbox, "app_voicemail.c", __PRETTY_FUNCTION__
, 13268)
&&
13269 (at = strchr(mwi_sub->mailbox, '@')(__extension__ (__builtin_constant_p ('@') && !__builtin_constant_p
(mwi_sub->mailbox) && ('@') == '\0' ? (char *) __rawmemchr
(mwi_sub->mailbox, '@') : __builtin_strchr (mwi_sub->mailbox
, '@')))
) &&
13270 strncmp(mailbox, mwi_sub->mailbox, at - mwi_sub->mailbox)(__extension__ (__builtin_constant_p (at - mwi_sub->mailbox
) && ((__builtin_constant_p (mailbox) && strlen
(mailbox) < ((size_t) (at - mwi_sub->mailbox))) || (__builtin_constant_p
(mwi_sub->mailbox) && strlen (mwi_sub->mailbox
) < ((size_t) (at - mwi_sub->mailbox)))) ? strcmp (mailbox
, mwi_sub->mailbox) : strncmp (mailbox, mwi_sub->mailbox
, at - mwi_sub->mailbox)))
== 0) ||
13271 /* Third case: match the context only */
13272 (!ast_strlen_zero(context)_ast_strlen_zero(context, "app_voicemail.c", __PRETTY_FUNCTION__
, 13272)
&& ast_strlen_zero(mailbox)_ast_strlen_zero(mailbox, "app_voicemail.c", __PRETTY_FUNCTION__
, 13272)
&&
13273 (at = strchr(mwi_sub->mailbox, '@')(__extension__ (__builtin_constant_p ('@') && !__builtin_constant_p
(mwi_sub->mailbox) && ('@') == '\0' ? (char *) __rawmemchr
(mwi_sub->mailbox, '@') : __builtin_strchr (mwi_sub->mailbox
, '@')))
) &&
13274 strcmp(context, at + 1) == 0) ||
13275 /* Final case: match an exact specified mailbox */
13276 (!ast_strlen_zero(context)_ast_strlen_zero(context, "app_voicemail.c", __PRETTY_FUNCTION__
, 13276)
&& !ast_strlen_zero(mailbox)_ast_strlen_zero(mailbox, "app_voicemail.c", __PRETTY_FUNCTION__
, 13276)
&&
13277 (at = strchr(mwi_sub->mailbox, '@')(__extension__ (__builtin_constant_p ('@') && !__builtin_constant_p
(mwi_sub->mailbox) && ('@') == '\0' ? (char *) __rawmemchr
(mwi_sub->mailbox, '@') : __builtin_strchr (mwi_sub->mailbox
, '@')))
) &&
13278 strncmp(mailbox, mwi_sub->mailbox, at - mwi_sub->mailbox)(__extension__ (__builtin_constant_p (at - mwi_sub->mailbox
) && ((__builtin_constant_p (mailbox) && strlen
(mailbox) < ((size_t) (at - mwi_sub->mailbox))) || (__builtin_constant_p
(mwi_sub->mailbox) && strlen (mwi_sub->mailbox
) < ((size_t) (at - mwi_sub->mailbox)))) ? strcmp (mailbox
, mwi_sub->mailbox) : strncmp (mailbox, mwi_sub->mailbox
, at - mwi_sub->mailbox)))
== 0 &&
13279 strcmp(context, at + 1) == 0)
13280 ) {
13281 poll_subscribed_mailbox(mwi_sub);
13282 }
13283 }
13284 }
13285 AST_RWLIST_UNLOCK(&mwi_subs)__ast_rwlock_unlock("app_voicemail.c", 13285, __PRETTY_FUNCTION__
, &(&mwi_subs)->lock, "&(&mwi_subs)->lock"
)
;
13286 astman_send_ack(s, m, "Refresh sent");
13287 return RESULT_SUCCESS0;
13288}
13289
13290/*! \brief Manager list voicemail users command */
13291static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
13292{
13293 struct ast_vm_user *vmu = NULL((void*)0);
13294 const char *id = astman_get_header(m, "ActionID");
13295 char actionid[128];
13296 int num_users = 0;
13297
13298 actionid[0] = '\0';
13299 if (!ast_strlen_zero(id)_ast_strlen_zero(id, "app_voicemail.c", __PRETTY_FUNCTION__, 13299
)
) {
13300 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
13301 }
13302
13303 AST_LIST_LOCK(&users)__ast_pthread_mutex_lock("app_voicemail.c", 13303, __PRETTY_FUNCTION__
, "&(&users)->lock", &(&users)->lock)
;
13304
13305 if (AST_LIST_EMPTY(&users)(((&users)->first) == ((void*)0))) {
13306 astman_send_ack(s, m, "There are no voicemail users currently defined.");
13307 AST_LIST_UNLOCK(&users)__ast_pthread_mutex_unlock("app_voicemail.c", 13307, __PRETTY_FUNCTION__
, "&(&users)->lock", &(&users)->lock)
;
13308 return RESULT_SUCCESS0;
13309 }
13310
13311 astman_send_listack(s, m, "Voicemail user list will follow", "start");
13312
13313 AST_LIST_TRAVERSE(&users, vmu, list)for((vmu) = (&users)->first; (vmu); (vmu) = (vmu)->
list.next)
{
13314 char dirname[256];
13315#ifdef IMAP_STORAGE
13316 int new, old;
13317
13318 inboxcount(vmu->mailbox, &new, &old);
13319#endif
13320
13321 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
13322 astman_append(s,
13323 "Event: VoicemailUserEntry\r\n"
13324 "%s"
13325 "VMContext: %s\r\n"
13326 "VoiceMailbox: %s\r\n"
13327 "Fullname: %s\r\n"
13328 "Email: %s\r\n"
13329 "Pager: %s\r\n"
13330 "ServerEmail: %s\r\n"
13331 "MailCommand: %s\r\n"
13332 "Language: %s\r\n"
13333 "TimeZone: %s\r\n"
13334 "Callback: %s\r\n"
13335 "Dialout: %s\r\n"
13336 "UniqueID: %s\r\n"
13337 "ExitContext: %s\r\n"
13338 "SayDurationMinimum: %d\r\n"
13339 "SayEnvelope: %s\r\n"
13340 "SayCID: %s\r\n"
13341 "AttachMessage: %s\r\n"
13342 "AttachmentFormat: %s\r\n"
13343 "DeleteMessage: %s\r\n"
13344 "VolumeGain: %.2f\r\n"
13345 "CanReview: %s\r\n"
13346 "CallOperator: %s\r\n"
13347 "MaxMessageCount: %d\r\n"
13348 "MaxMessageLength: %d\r\n"
13349 "NewMessageCount: %d\r\n"
13350#ifdef IMAP_STORAGE
13351 "OldMessageCount: %d\r\n"
13352 "IMAPUser: %s\r\n"
13353 "IMAPServer: %s\r\n"
13354 "IMAPPort: %s\r\n"
13355 "IMAPFlags: %s\r\n"
13356#endif
13357 "\r\n",
13358 actionid,
13359 vmu->context,
13360 vmu->mailbox,
13361 vmu->fullname,
13362 vmu->email,
13363 vmu->pager,
13364 ast_strlen_zero(vmu->serveremail)_ast_strlen_zero(vmu->serveremail, "app_voicemail.c", __PRETTY_FUNCTION__
, 13364)
? serveremail : vmu->serveremail,
13365 mailcmd,
13366 vmu->language,
13367 vmu->zonetag,
13368 vmu->callback,
13369 vmu->dialout,
13370 vmu->uniqueid,
13371 vmu->exit,
13372 vmu->saydurationm,
13373 ast_test_flag(vmu, VM_ENVELOPE)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 4))); })
? "Yes" : "No",
13374 ast_test_flag(vmu, VM_SAYCID)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 2))); })
? "Yes" : "No",
13375 ast_test_flag(vmu, VM_ATTACH)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 11))); })
? "Yes" : "No",
13376 vmu->attachfmt,
13377 ast_test_flag(vmu, VM_DELETE)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 12))); })
? "Yes" : "No",
13378 vmu->volgain,
13379 ast_test_flag(vmu, VM_REVIEW)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 0))); })
? "Yes" : "No",
13380 ast_test_flag(vmu, VM_OPERATOR)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 1))); })
? "Yes" : "No",
13381 vmu->maxmsg,
13382 vmu->maxsecs,
13383#ifdef IMAP_STORAGE
13384 new, old,
13385 vmu->imapuser,
13386 vmu->imapserver,
13387 vmu->imapport,
13388 vmu->imapflags
13389#else
13390 count_messages(vmu, dirname)
13391#endif
13392 );
13393 ++num_users;
13394 }
13395
13396 astman_send_list_complete_start(s, m, "VoicemailUserEntryComplete", num_users);
13397 astman_send_list_complete_end(s);
13398
13399 AST_LIST_UNLOCK(&users)__ast_pthread_mutex_unlock("app_voicemail.c", 13399, __PRETTY_FUNCTION__
, "&(&users)->lock", &(&users)->lock)
;
13400
13401 return RESULT_SUCCESS0;
13402}
13403
13404/*! \brief Free the users structure. */
13405static void free_vm_users(void)
13406{
13407 struct ast_vm_user *current;
13408 AST_LIST_LOCK(&users)__ast_pthread_mutex_lock("app_voicemail.c", 13408, __PRETTY_FUNCTION__
, "&(&users)->lock", &(&users)->lock)
;
13409 while ((current = AST_LIST_REMOVE_HEAD(&users, list)({ typeof((&users)->first) __cur = (&users)->first
; if (__cur) { (&users)->first = __cur->list.next; __cur
->list.next = ((void*)0); if ((&users)->last == __cur
) (&users)->last = ((void*)0); } __cur; })
)) {
13410 ast_set_flag(current, VM_ALLOCED)do { typeof ((current)->flags) __p = (current)->flags; typeof
(__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); ((current)->flags |= ((1 << 13))); } while(0)
;
13411 free_user(current);
13412 }
13413 AST_LIST_UNLOCK(&users)__ast_pthread_mutex_unlock("app_voicemail.c", 13413, __PRETTY_FUNCTION__
, "&(&users)->lock", &(&users)->lock)
;
13414}
13415
13416/*! \brief Free the zones structure. */
13417static void free_vm_zones(void)
13418{
13419 struct vm_zone *zcur;
13420 AST_LIST_LOCK(&zones)__ast_pthread_mutex_lock("app_voicemail.c", 13420, __PRETTY_FUNCTION__
, "&(&zones)->lock", &(&zones)->lock)
;
13421 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)({ typeof((&zones)->first) __cur = (&zones)->first
; if (__cur) { (&zones)->first = __cur->list.next; __cur
->list.next = ((void*)0); if ((&zones)->last == __cur
) (&zones)->last = ((void*)0); } __cur; })
))
13422 free_zone(zcur);
13423 AST_LIST_UNLOCK(&zones)__ast_pthread_mutex_unlock("app_voicemail.c", 13423, __PRETTY_FUNCTION__
, "&(&zones)->lock", &(&zones)->lock)
;
13424}
13425
13426static const char *substitute_escapes(const char *value)
13427{
13428 char *current;
13429
13430 /* Add 16 for fudge factor */
13431 struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
13432
13433 ast_str_reset(str);
13434
13435 /* Substitute strings \r, \n, and \t into the appropriate characters */
13436 for (current = (char *) value; *current; current++) {
13437 if (*current == '\\') {
13438 current++;
13439 if (!*current) {
13440 ast_log(AST_LOG_NOTICE2, "app_voicemail.c", 13440, __PRETTY_FUNCTION__, "Incomplete escape at end of value.\n");
13441 break;
13442 }
13443 switch (*current) {
13444 case '\\':
13445 ast_str_append(&str, 0, "\\");
13446 break;
13447 case 'r':
13448 ast_str_append(&str, 0, "\r");
13449 break;
13450 case 'n':
13451#ifdef IMAP_STORAGE
13452 if (!str->used || str->str[str->used - 1] != '\r') {
13453 ast_str_append(&str, 0, "\r");
13454 }
13455#endif
13456 ast_str_append(&str, 0, "\n");
13457 break;
13458 case 't':
13459 ast_str_append(&str, 0, "\t");
13460 break;
13461 default:
13462 ast_log(AST_LOG_NOTICE2, "app_voicemail.c", 13462, __PRETTY_FUNCTION__, "Substitution routine does not support this character: \\%c\n", *current);
13463 break;
13464 }
13465 } else {
13466 ast_str_append(&str, 0, "%c", *current);
13467 }
13468 }
13469
13470 return ast_str_buffer(str);
13471}
13472
13473static int load_config(int reload)
13474{
13475 struct ast_config *cfg, *ucfg;
13476 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
13477 int res;
13478
13479 ast_unload_realtime("voicemail");
13480 ast_unload_realtime("voicemail_data");
13481
13482 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)ast_config_load2("voicemail.conf", "app_voicemail", config_flags
)
) == CONFIG_STATUS_FILEUNCHANGED(void *)-1) {
13483 if ((ucfg = ast_config_load("users.conf", config_flags)ast_config_load2("users.conf", "app_voicemail", config_flags)) == CONFIG_STATUS_FILEUNCHANGED(void *)-1) {
13484 return 0;
13485 } else if (ucfg == CONFIG_STATUS_FILEINVALID(void *)-2) {
13486 ast_log(LOG_ERROR4, "app_voicemail.c", 13486, __PRETTY_FUNCTION__, "Config file users.conf is in an invalid format. Avoiding.\n");
13487 ucfg = NULL((void*)0);
13488 }
13489 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED)do { typeof ((&config_flags)->flags) __p = (&config_flags
)->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); ((&config_flags)->flags &=
~(CONFIG_FLAG_FILEUNCHANGED)); } while(0)
;
13490 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)ast_config_load2("voicemail.conf", "app_voicemail", config_flags
)
) == CONFIG_STATUS_FILEINVALID(void *)-2) {
13491 ast_config_destroy(ucfg);
13492 ast_log(LOG_ERROR4, "app_voicemail.c", 13492, __PRETTY_FUNCTION__, "Config file " VOICEMAIL_CONFIG"voicemail.conf" " is in an invalid format. Aborting.\n");
13493 return 0;
13494 }
13495 } else if (cfg == CONFIG_STATUS_FILEINVALID(void *)-2) {
13496 ast_log(LOG_ERROR4, "app_voicemail.c", 13496, __PRETTY_FUNCTION__, "Config file " VOICEMAIL_CONFIG"voicemail.conf" " is in an invalid format. Aborting.\n");
13497 return 0;
13498 } else {
13499 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED)do { typeof ((&config_flags)->flags) __p = (&config_flags
)->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); ((&config_flags)->flags &=
~(CONFIG_FLAG_FILEUNCHANGED)); } while(0)
;
13500 if ((ucfg = ast_config_load("users.conf", config_flags)ast_config_load2("users.conf", "app_voicemail", config_flags)) == CONFIG_STATUS_FILEINVALID(void *)-2) {
13501 ast_log(LOG_ERROR4, "app_voicemail.c", 13501, __PRETTY_FUNCTION__, "Config file users.conf is in an invalid format. Avoiding.\n");
13502 ucfg = NULL((void*)0);
13503 }
13504 }
13505
13506 res = actual_load_config(reload, cfg, ucfg);
13507
13508 ast_config_destroy(cfg);
13509 ast_config_destroy(ucfg);
13510
13511 return res;
13512}
13513
13514#ifdef TEST_FRAMEWORK
13515static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg)
13516{
13517 ast_unload_realtime("voicemail");
13518 ast_unload_realtime("voicemail_data");
13519 return actual_load_config(reload, cfg, ucfg);
13520}
13521#endif
13522
13523static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg)
13524{
13525 struct ast_vm_user *current;
13526 char *cat;
13527 struct ast_variable *var;
13528 const char *val;
13529 char *q, *stringp, *tmp;
13530 int x;
13531 unsigned int tmpadsi[4];
13532 char secretfn[PATH_MAX4096] = "";
13533
13534#ifdef IMAP_STORAGE
13535 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
13536#endif
13537 /* set audio control prompts */
13538 strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY"#");
13539 strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY"*");
13540 strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY"0");
13541 strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY"2");
13542 strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY"13456789");
13543
13544 /* Free all the users structure */
13545 free_vm_users();
13546
13547 /* Free all the zones structure */
13548 free_vm_zones();
13549
13550 AST_LIST_LOCK(&users)__ast_pthread_mutex_lock("app_voicemail.c", 13550, __PRETTY_FUNCTION__
, "&(&users)->lock", &(&users)->lock)
;
13551
13552 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
13553 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
13554
13555 if (cfg) {
13556 /* General settings */
13557
13558 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
13559 val = "default";
13560 ast_copy_string(userscontext, val, sizeof(userscontext));
13561 /* Attach voice message to mail message ? */
13562 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
13563 val = "yes";
13564 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH)do { typeof (((&globalflags))->flags) __p = ((&globalflags
))->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); if (ast_true(val)) ((&globalflags
))->flags |= ((1 << 11)); else ((&globalflags))->
flags &= ~((1 << 11)); } while (0)
;
13565
13566 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
13567 val = "no";
13568 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH)do { typeof (((&globalflags))->flags) __p = ((&globalflags
))->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); if (ast_true(val)) ((&globalflags
))->flags |= ((1 << 14)); else ((&globalflags))->
flags &= ~((1 << 14)); } while (0)
;
13569
13570 volgain = 0.0;
13571 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
13572 sscanf(val, "%30lf", &volgain);
13573
13574#ifdef ODBC_STORAGE
13575 strcpy(odbc_database, "asterisk");
13576 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
13577 ast_copy_string(odbc_database, val, sizeof(odbc_database));
13578 }
13579 strcpy(odbc_table, "voicemessages");
13580 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
13581 ast_copy_string(odbc_table, val, sizeof(odbc_table));
13582 }
13583#endif
13584 /* Mail command */
13585 strcpy(mailcmd, SENDMAIL"/usr/sbin/sendmail -t");
13586 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
13587 ast_copy_string(mailcmd, val, sizeof(mailcmd)); /* User setting */
13588
13589 maxsilence = 0;
13590 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
13591 maxsilence = atoi(val);
13592 if (maxsilence > 0)
13593 maxsilence *= 1000;
13594 }
13595
13596 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
13597 maxmsg = MAXMSG100;
13598 } else {
13599 maxmsg = atoi(val);
13600 if (maxmsg < 0) {
13601 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 13601, __PRETTY_FUNCTION__, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG100);
13602 maxmsg = MAXMSG100;
13603 } else if (maxmsg > MAXMSGLIMIT9999) {
13604 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 13604, __PRETTY_FUNCTION__, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT9999, val);
13605 maxmsg = MAXMSGLIMIT9999;
13606 }
13607 }
13608
13609 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
13610 maxdeletedmsg = 0;
13611 } else {
13612 if (sscanf(val, "%30d", &x) == 1)
13613 maxdeletedmsg = x;
13614 else if (ast_true(val))
13615 maxdeletedmsg = MAXMSG100;
13616 else
13617 maxdeletedmsg = 0;
13618
13619 if (maxdeletedmsg < 0) {
13620 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 13620, __PRETTY_FUNCTION__, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG100);
13621 maxdeletedmsg = MAXMSG100;
13622 } else if (maxdeletedmsg > MAXMSGLIMIT9999) {
13623 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 13623, __PRETTY_FUNCTION__, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT9999, val);
13624 maxdeletedmsg = MAXMSGLIMIT9999;
13625 }
13626 }
13627
13628 /* Load date format config for voicemail mail */
13629 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
13630 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
13631 }
13632
13633 /* Load date format config for voicemail pager mail */
13634 if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
13635 ast_copy_string(pagerdateformat, val, sizeof(pagerdateformat));
13636 }
13637
13638 /* External password changing command */
13639 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
13640 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
13641 pwdchange = PWDCHANGE_EXTERNAL(1 << 2);
13642 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
13643 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
13644 pwdchange = PWDCHANGE_EXTERNAL(1 << 2) | PWDCHANGE_INTERNAL(1 << 1);
13645 }
13646
13647 /* External password validation command */
13648 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
13649 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
13650 ast_debug(1, "found externpasscheck: %s\n", ext_pass_check_cmd)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 13650, __PRETTY_FUNCTION__, "found externpasscheck: %s\n"
, ext_pass_check_cmd); } } while (0)
;
13651 }
13652
13653#ifdef IMAP_STORAGE
13654 /* IMAP server address */
13655 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
13656 ast_copy_string(imapserver, val, sizeof(imapserver));
13657 } else {
13658 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
13659 }
13660 /* IMAP server port */
13661 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
13662 ast_copy_string(imapport, val, sizeof(imapport));
13663 } else {
13664 ast_copy_string(imapport, "143", sizeof(imapport));
13665 }
13666 /* IMAP server flags */
13667 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
13668 ast_copy_string(imapflags, val, sizeof(imapflags));
13669 }
13670 /* IMAP server master username */
13671 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
13672 ast_copy_string(authuser, val, sizeof(authuser));
13673 }
13674 /* IMAP server master password */
13675 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
13676 ast_copy_string(authpassword, val, sizeof(authpassword));
13677 }
13678 /* Expunge on exit */
13679 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
13680 if (ast_false(val))
13681 expungeonhangup = 0;
13682 else
13683 expungeonhangup = 1;
13684 } else {
13685 expungeonhangup = 1;
13686 }
13687 /* IMAP voicemail folder */
13688 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
13689 ast_copy_string(imapfolder, val, sizeof(imapfolder));
13690 } else {
13691 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
13692 }
13693 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
13694 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
13695 }
13696 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
13697 imapgreetings = ast_true(val);
13698 } else {
13699 imapgreetings = 0;
13700 }
13701 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
13702 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
13703 } else if ((val = ast_variable_retrieve(cfg, "general", "greetingsfolder"))) {
13704 /* Also support greetingsfolder as documented in voicemail.conf.sample */
13705 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
13706 } else {
13707 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
13708 }
13709
13710 /* There is some very unorthodox casting done here. This is due
13711 * to the way c-client handles the argument passed in. It expects a
13712 * void pointer and casts the pointer directly to a long without
13713 * first dereferencing it. */
13714 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
13715 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
13716 } else {
13717 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
13718 }
13719
13720 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
13721 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
13722 } else {
13723 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
13724 }
13725
13726 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
13727 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
13728 } else {
13729 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
13730 }
13731
13732 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
13733 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
13734 } else {
13735 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
13736 }
13737
13738 /* Increment configuration version */
13739 imapversion++;
13740#endif
13741 /* External voicemail notify application */
13742 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
13743 ast_copy_string(externnotify, val, sizeof(externnotify));
13744 ast_debug(1, "found externnotify: %s\n", externnotify)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 13744, __PRETTY_FUNCTION__, "found externnotify: %s\n"
, externnotify); } } while (0)
;
13745 } else {
13746 externnotify[0] = '\0';
13747 }
13748
13749 /* SMDI voicemail notification */
13750 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
13751 ast_debug(1, "Enabled SMDI voicemail notification\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 13751, __PRETTY_FUNCTION__, "Enabled SMDI voicemail notification\n"
); } } while (0)
;
13752 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
13753 smdi_iface = ast_smdi_interface_find(val);
13754 } else {
13755 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 13755, __PRETTY_FUNCTION__, "No SMDI interface set, trying default (/dev/ttyS0)\n"
); } } while (0)
;
13756 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
13757 }
13758 if (!smdi_iface) {
13759 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 13759, __PRETTY_FUNCTION__, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
13760 }
13761 }
13762
13763 /* Silence treshold */
13764 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
13765 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
13766 silencethreshold = atoi(val);
13767
13768 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
13769 val = ASTERISK_USERNAME"asterisk";
13770 ast_copy_string(serveremail, val, sizeof(serveremail));
13771
13772 vmmaxsecs = 0;
13773 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
13774 if (sscanf(val, "%30d", &x) == 1) {
13775 vmmaxsecs = x;
13776 } else {
13777 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 13777, __PRETTY_FUNCTION__, "Invalid max message time length\n");
13778 }
13779 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
13780 static int maxmessage_deprecate = 0;
13781 if (maxmessage_deprecate == 0) {
13782 maxmessage_deprecate = 1;
13783 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 13783, __PRETTY_FUNCTION__, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
13784 }
13785 if (sscanf(val, "%30d", &x) == 1) {
13786 vmmaxsecs = x;
13787 } else {
13788 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 13788, __PRETTY_FUNCTION__, "Invalid max message time length\n");
13789 }
13790 }
13791
13792 vmminsecs = 0;
13793 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
13794 if (sscanf(val, "%30d", &x) == 1) {
13795 vmminsecs = x;
13796 if (maxsilence / 1000 >= vmminsecs) {
13797 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 13797, __PRETTY_FUNCTION__, "maxsilence should be less than minsecs or you may get empty messages\n");
13798 }
13799 } else {
13800 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 13800, __PRETTY_FUNCTION__, "Invalid min message time length\n");
13801 }
13802 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
13803 static int maxmessage_deprecate = 0;
13804 if (maxmessage_deprecate == 0) {
13805 maxmessage_deprecate = 1;
13806 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 13806, __PRETTY_FUNCTION__, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
13807 }
13808 if (sscanf(val, "%30d", &x) == 1) {
13809 vmminsecs = x;
13810 if (maxsilence / 1000 >= vmminsecs) {
13811 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 13811, __PRETTY_FUNCTION__, "maxsilence should be less than minmessage or you may get empty messages\n");
13812 }
13813 } else {
13814 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 13814, __PRETTY_FUNCTION__, "Invalid min message time length\n");
13815 }
13816 }
13817
13818 val = ast_variable_retrieve(cfg, "general", "format");
13819 if (!val) {
13820 val = "wav";
13821 } else {
13822 tmp = ast_strdupa(val)(__extension__ ({ const char *__old = (val); size_t __len = strlen
(__old) + 1; char *__new = __builtin_alloca(__len); memcpy (__new
, __old, __len); __new; }))
;
13823 val = ast_format_str_reduce(tmp);
13824 if (!val) {
13825 ast_log(LOG_ERROR4, "app_voicemail.c", 13825, __PRETTY_FUNCTION__, "Error processing format string, defaulting to format 'wav'\n");
13826 val = "wav";
13827 }
13828 }
13829 ast_copy_string(vmfmts, val, sizeof(vmfmts));
13830
13831 skipms = 3000;
13832 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
13833 if (sscanf(val, "%30d", &x) == 1) {
13834 maxgreet = x;
13835 } else {
13836 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 13836, __PRETTY_FUNCTION__, "Invalid max message greeting length\n");
13837 }
13838 }
13839
13840 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
13841 if (sscanf(val, "%30d", &x) == 1) {
13842 skipms = x;
13843 } else {
13844 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 13844, __PRETTY_FUNCTION__, "Invalid skipms value\n");
13845 }
13846 }
13847
13848 maxlogins = 3;
13849 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
13850 if (sscanf(val, "%30d", &x) == 1) {
13851 maxlogins = x;
13852 } else {
13853 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 13853, __PRETTY_FUNCTION__, "Invalid max failed login attempts\n");
13854 }
13855 }
13856
13857 minpassword = MINPASSWORD0;
13858 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
13859 if (sscanf(val, "%30d", &x) == 1) {
13860 minpassword = x;
13861 } else {
13862 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 13862, __PRETTY_FUNCTION__, "Invalid minimum password length. Default to %d\n", minpassword);
13863 }
13864 }
13865
13866 /* Force new user to record name ? */
13867 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
13868 val = "no";
13869 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME)do { typeof (((&globalflags))->flags) __p = ((&globalflags
))->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); if (ast_true(val)) ((&globalflags
))->flags |= ((1 << 7)); else ((&globalflags))->
flags &= ~((1 << 7)); } while (0)
;
13870
13871 /* Force new user to record greetings ? */
13872 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
13873 val = "no";
13874 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET)do { typeof (((&globalflags))->flags) __p = ((&globalflags
))->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); if (ast_true(val)) ((&globalflags
))->flags |= ((1 << 8)); else ((&globalflags))->
flags &= ~((1 << 8)); } while (0)
;
13875
13876 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
13877 ast_debug(1, "VM_CID Internal context string: %s\n", val)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 13877, __PRETTY_FUNCTION__, "VM_CID Internal context string: %s\n"
, val); } } while (0)
;
13878 stringp = ast_strdupa(val)(__extension__ ({ const char *__old = (val); size_t __len = strlen
(__old) + 1; char *__new = __builtin_alloca(__len); memcpy (__new
, __old, __len); __new; }))
;
13879 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS10 ; x++){
13880 if (!ast_strlen_zero(stringp)_ast_strlen_zero(stringp, "app_voicemail.c", __PRETTY_FUNCTION__
, 13880)
) {
13881 q = strsep(&stringp, ",");
13882 while ((*q == ' ')||(*q == '\t')) /* Eat white space between contexts */
13883 q++;
13884 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
13885 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x])do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 13885, __PRETTY_FUNCTION__, "VM_CID Internal context %d: %s\n"
, x, cidinternalcontexts[x]); } } while (0)
;
13886 } else {
13887 cidinternalcontexts[x][0] = '\0';
13888 }
13889 }
13890 }
13891 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
13892 ast_debug(1, "VM Review Option disabled globally\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 13892, __PRETTY_FUNCTION__, "VM Review Option disabled globally\n"
); } } while (0)
;
13893 val = "no";
13894 }
13895 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW)do { typeof (((&globalflags))->flags) __p = ((&globalflags
))->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); if (ast_true(val)) ((&globalflags
))->flags |= ((1 << 0)); else ((&globalflags))->
flags &= ~((1 << 0)); } while (0)
;
13896
13897 /* Temporary greeting reminder */
13898 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
13899 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 13899, __PRETTY_FUNCTION__, "VM Temporary Greeting Reminder Option disabled globally\n"
); } } while (0)
;
13900 val = "no";
13901 } else {
13902 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 13902, __PRETTY_FUNCTION__, "VM Temporary Greeting Reminder Option enabled globally\n"
); } } while (0)
;
13903 }
13904 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN)do { typeof (((&globalflags))->flags) __p = ((&globalflags
))->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); if (ast_true(val)) ((&globalflags
))->flags |= ((1 << 15)); else ((&globalflags))->
flags &= ~((1 << 15)); } while (0)
;
13905 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
13906 ast_debug(1, "VM next message wrap disabled globally\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 13906, __PRETTY_FUNCTION__, "VM next message wrap disabled globally\n"
); } } while (0)
;
13907 val = "no";
13908 }
13909 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP)do { typeof (((&globalflags))->flags) __p = ((&globalflags
))->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); if (ast_true(val)) ((&globalflags
))->flags |= ((1 << 17)); else ((&globalflags))->
flags &= ~((1 << 17)); } while (0)
;
13910
13911 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
13912 ast_debug(1, "VM Operator break disabled globally\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 13912, __PRETTY_FUNCTION__, "VM Operator break disabled globally\n"
); } } while (0)
;
13913 val = "no";
13914 }
13915 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR)do { typeof (((&globalflags))->flags) __p = ((&globalflags
))->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); if (ast_true(val)) ((&globalflags
))->flags |= ((1 << 1)); else ((&globalflags))->
flags &= ~((1 << 1)); } while (0)
;
13916
13917 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
13918 ast_debug(1, "VM CID Info before msg disabled globally\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 13918, __PRETTY_FUNCTION__, "VM CID Info before msg disabled globally\n"
); } } while (0)
;
13919 val = "no";
13920 }
13921 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID)do { typeof (((&globalflags))->flags) __p = ((&globalflags
))->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); if (ast_true(val)) ((&globalflags
))->flags |= ((1 << 2)); else ((&globalflags))->
flags &= ~((1 << 2)); } while (0)
;
13922
13923 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
13924 ast_debug(1, "Send Voicemail msg disabled globally\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 13924, __PRETTY_FUNCTION__, "Send Voicemail msg disabled globally\n"
); } } while (0)
;
13925 val = "no";
13926 }
13927 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL)do { typeof (((&globalflags))->flags) __p = ((&globalflags
))->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); if (ast_true(val)) ((&globalflags
))->flags |= ((1 << 3)); else ((&globalflags))->
flags &= ~((1 << 3)); } while (0)
;
13928
13929 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
13930 ast_debug(1, "ENVELOPE before msg enabled globally\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 13930, __PRETTY_FUNCTION__, "ENVELOPE before msg enabled globally\n"
); } } while (0)
;
13931 val = "yes";
13932 }
13933 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE)do { typeof (((&globalflags))->flags) __p = ((&globalflags
))->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); if (ast_true(val)) ((&globalflags
))->flags |= ((1 << 4)); else ((&globalflags))->
flags &= ~((1 << 4)); } while (0)
;
13934
13935 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
13936 ast_debug(1, "Move Heard enabled globally\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 13936, __PRETTY_FUNCTION__, "Move Heard enabled globally\n"
); } } while (0)
;
13937 val = "yes";
13938 }
13939 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD)do { typeof (((&globalflags))->flags) __p = ((&globalflags
))->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); if (ast_true(val)) ((&globalflags
))->flags |= ((1 << 16)); else ((&globalflags))->
flags &= ~((1 << 16)); } while (0)
;
13940
13941 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
13942 ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 13942, __PRETTY_FUNCTION__, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n"
); } } while (0)
;
13943 val = "no";
13944 }
13945 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO)do { typeof (((&globalflags))->flags) __p = ((&globalflags
))->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); if (ast_true(val)) ((&globalflags
))->flags |= ((1 << 18)); else ((&globalflags))->
flags &= ~((1 << 18)); } while (0)
;
13946
13947 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
13948 ast_debug(1, "Duration info before msg enabled globally\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 13948, __PRETTY_FUNCTION__, "Duration info before msg enabled globally\n"
); } } while (0)
;
13949 val = "yes";
13950 }
13951 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION)do { typeof (((&globalflags))->flags) __p = ((&globalflags
))->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); if (ast_true(val)) ((&globalflags
))->flags |= ((1 << 5)); else ((&globalflags))->
flags &= ~((1 << 5)); } while (0)
;
13952
13953 saydurationminfo = 2;
13954 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
13955 if (sscanf(val, "%30d", &x) == 1) {
13956 saydurationminfo = x;
13957 } else {
13958 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 13958, __PRETTY_FUNCTION__, "Invalid min duration for say duration\n");
13959 }
13960 }
13961
13962 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
13963 ast_debug(1, "We are not going to skip to the next msg after save/delete\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 13963, __PRETTY_FUNCTION__, "We are not going to skip to the next msg after save/delete\n"
); } } while (0)
;
13964 val = "no";
13965 }
13966 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD)do { typeof (((&globalflags))->flags) __p = ((&globalflags
))->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); if (ast_true(val)) ((&globalflags
))->flags |= ((1 << 6)); else ((&globalflags))->
flags &= ~((1 << 6)); } while (0)
;
13967
13968 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
13969 ast_copy_string(dialcontext, val, sizeof(dialcontext));
13970 ast_debug(1, "found dialout context: %s\n", dialcontext)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 13970, __PRETTY_FUNCTION__, "found dialout context: %s\n"
, dialcontext); } } while (0)
;
13971 } else {
13972 dialcontext[0] = '\0';
13973 }
13974
13975 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
13976 ast_copy_string(callcontext, val, sizeof(callcontext));
13977 ast_debug(1, "found callback context: %s\n", callcontext)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 13977, __PRETTY_FUNCTION__, "found callback context: %s\n"
, callcontext); } } while (0)
;
13978 } else {
13979 callcontext[0] = '\0';
13980 }
13981
13982 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
13983 ast_copy_string(exitcontext, val, sizeof(exitcontext));
13984 ast_debug(1, "found operator context: %s\n", exitcontext)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (1)))) { ast_log
(0, "app_voicemail.c", 13984, __PRETTY_FUNCTION__, "found operator context: %s\n"
, exitcontext); } } while (0)
;
13985 } else {
13986 exitcontext[0] = '\0';
13987 }
13988
13989 /* load password sounds configuration */
13990 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
13991 ast_copy_string(vm_password, val, sizeof(vm_password));
13992 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
13993 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
13994 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
13995 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
13996 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
13997 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
13998 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
13999 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
14000 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
14001 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
14002 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
14003 ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
14004 }
14005 if ((val = ast_variable_retrieve(cfg, "general", "vm-prepend-timeout"))) {
14006 ast_copy_string(vm_prepend_timeout, val, sizeof(vm_prepend_timeout));
14007 }
14008 /* load configurable audio prompts */
14009 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
14010 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
14011 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
14012 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
14013 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
14014 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
14015 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
14016 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
14017 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
14018 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
14019
14020 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
14021 val = "no";
14022 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD)do { typeof (((&globalflags))->flags) __p = ((&globalflags
))->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); if (ast_true(val)) ((&globalflags
))->flags |= ((1 << 10)); else ((&globalflags))->
flags &= ~((1 << 10)); } while (0)
;
14023
14024 if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
14025 val = "voicemail.conf";
14026 }
14027 if (!(strcmp(val, "spooldir"))) {
14028 passwordlocation = OPT_PWLOC_SPOOLDIR;
14029 } else {
14030 passwordlocation = OPT_PWLOC_VOICEMAILCONF;
14031 }
14032
14033 poll_freq = DEFAULT_POLL_FREQ30;
14034 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
14035 if (sscanf(val, "%30u", &poll_freq) != 1) {
14036 poll_freq = DEFAULT_POLL_FREQ30;
14037 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 14037, __PRETTY_FUNCTION__, "'%s' is not a valid value for the pollfreq option!\n", val);
14038 }
14039 }
14040
14041 poll_mailboxes = 0;
14042 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
14043 poll_mailboxes = ast_true(val);
14044
14045 memset(fromstring, 0, sizeof(fromstring));
14046 memset(pagerfromstring, 0, sizeof(pagerfromstring));
14047 strcpy(charset, "ISO-8859-1");
14048 if (emailbody) {
14049 ast_freefree(emailbody);
14050 emailbody = NULL((void*)0);
14051 }
14052 if (emailsubject) {
14053 ast_freefree(emailsubject);
14054 emailsubject = NULL((void*)0);
14055 }
14056 if (pagerbody) {
14057 ast_freefree(pagerbody);
14058 pagerbody = NULL((void*)0);
14059 }
14060 if (pagersubject) {
14061 ast_freefree(pagersubject);
14062 pagersubject = NULL((void*)0);
14063 }
14064 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
14065 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP)do { typeof (((&globalflags))->flags) __p = ((&globalflags
))->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); if (ast_true(val)) ((&globalflags
))->flags |= ((1 << 9)); else ((&globalflags))->
flags &= ~((1 << 9)); } while (0)
;
14066 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
14067 ast_copy_string(fromstring, val, sizeof(fromstring));
14068 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
14069 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
14070 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
14071 ast_copy_string(charset, val, sizeof(charset));
14072 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
14073 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
14074 for (x = 0; x < 4; x++) {
14075 memcpy(&adsifdn[x], &tmpadsi[x], 1);
14076 }
14077 }
14078 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
14079 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
14080 for (x = 0; x < 4; x++) {
14081 memcpy(&adsisec[x], &tmpadsi[x], 1);
14082 }
14083 }
14084 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
14085 if (atoi(val)) {
14086 adsiver = atoi(val);
14087 }
14088 }
14089 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
14090 ast_copy_string(zonetag, val, sizeof(zonetag));
14091 }
14092 if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
14093 ast_copy_string(locale, val, sizeof(locale));
14094 }
14095 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
14096 emailsubject = ast_strdup(substitute_escapes(val))_ast_strdup((substitute_escapes(val)), "app_voicemail.c", 14096
, __PRETTY_FUNCTION__)
;
14097 }
14098 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
14099 emailbody = ast_strdup(substitute_escapes(val))_ast_strdup((substitute_escapes(val)), "app_voicemail.c", 14099
, __PRETTY_FUNCTION__)
;
14100 }
14101 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
14102 pagersubject = ast_strdup(substitute_escapes(val))_ast_strdup((substitute_escapes(val)), "app_voicemail.c", 14102
, __PRETTY_FUNCTION__)
;
14103 }
14104 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
14105 pagerbody = ast_strdup(substitute_escapes(val))_ast_strdup((substitute_escapes(val)), "app_voicemail.c", 14105
, __PRETTY_FUNCTION__)
;
14106 }
14107
14108 /* load mailboxes from users.conf */
14109 if (ucfg) {
14110 for (cat = ast_category_browse(ucfg, NULL((void*)0)); cat ; cat = ast_category_browse(ucfg, cat)) {
14111 if (!strcasecmp(cat, "general")) {
14112 continue;
14113 }
14114 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
14115 continue;
14116 if ((current = find_or_create(userscontext, cat))) {
14117 populate_defaults(current);
14118 apply_options_full(current, ast_variable_browse(ucfg, cat));
14119 ast_copy_string(current->context, userscontext, sizeof(current->context));
14120 if (!ast_strlen_zero(current->password)_ast_strlen_zero(current->password, "app_voicemail.c", __PRETTY_FUNCTION__
, 14120)
&& current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
14121 current->passwordlocation = OPT_PWLOC_USERSCONF;
14122 }
14123
14124 switch (current->passwordlocation) {
14125 case OPT_PWLOC_SPOOLDIR:
14126 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
14127 read_password_from_file(secretfn, current->password, sizeof(current->password));
14128 }
14129 }
14130 }
14131 }
14132
14133 /* load mailboxes from voicemail.conf */
14134 cat = ast_category_browse(cfg, NULL((void*)0));
14135 while (cat) {
14136 if (strcasecmp(cat, "general")) {
14137 var = ast_variable_browse(cfg, cat);
14138 if (strcasecmp(cat, "zonemessages")) {
14139 /* Process mailboxes in this context */
14140 while (var) {
14141 append_mailbox(cat, var->name, var->value);
14142 var = var->next;
14143 }
14144 } else {
14145 /* Timezones in this context */
14146 while (var) {
14147 struct vm_zone *z;
14148 if ((z = ast_malloc(sizeof(*z))_ast_malloc((sizeof(*z)), "app_voicemail.c", 14148, __PRETTY_FUNCTION__
)
)) {
14149 char *msg_format, *tzone;
14150 msg_format = ast_strdupa(var->value)(__extension__ ({ const char *__old = (var->value); size_t
__len = strlen(__old) + 1; char *__new = __builtin_alloca(__len
); memcpy (__new, __old, __len); __new; }))
;
14151 tzone = strsep(&msg_format, "|,");
14152 if (msg_format) {
14153 ast_copy_string(z->name, var->name, sizeof(z->name));
14154 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
14155 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
14156 AST_LIST_LOCK(&zones)__ast_pthread_mutex_lock("app_voicemail.c", 14156, __PRETTY_FUNCTION__
, "&(&zones)->lock", &(&zones)->lock)
;
14157 AST_LIST_INSERT_HEAD(&zones, z, list)do { (z)->list.next = (&zones)->first; (&zones)
->first = (z); if (!(&zones)->last) (&zones)->
last = (z); } while (0)
;
14158 AST_LIST_UNLOCK(&zones)__ast_pthread_mutex_unlock("app_voicemail.c", 14158, __PRETTY_FUNCTION__
, "&(&zones)->lock", &(&zones)->lock)
;
14159 } else {
14160 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 14160, __PRETTY_FUNCTION__, "Invalid timezone definition at line %d\n", var->lineno);
14161 ast_freefree(z);
14162 }
14163 } else {
14164 AST_LIST_UNLOCK(&users)__ast_pthread_mutex_unlock("app_voicemail.c", 14164, __PRETTY_FUNCTION__
, "&(&users)->lock", &(&users)->lock)
;
14165 return -1;
14166 }
14167 var = var->next;
14168 }
14169 }
14170 }
14171 cat = ast_category_browse(cfg, cat);
14172 }
14173
14174 AST_LIST_UNLOCK(&users)__ast_pthread_mutex_unlock("app_voicemail.c", 14174, __PRETTY_FUNCTION__
, "&(&users)->lock", &(&users)->lock)
;
14175
14176 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL(pthread_t) -1)
14177 start_poll_thread();
14178 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL(pthread_t) -1)
14179 stop_poll_thread();;
14180
14181 return 0;
14182 } else {
14183 AST_LIST_UNLOCK(&users)__ast_pthread_mutex_unlock("app_voicemail.c", 14183, __PRETTY_FUNCTION__
, "&(&users)->lock", &(&users)->lock)
;
14184 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 14184, __PRETTY_FUNCTION__, "Failed to load configuration file.\n");
14185 return 0;
14186 }
14187}
14188
14189static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
14190{
14191 int res = -1;
14192 char dir[PATH_MAX4096];
14193 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
14194 ast_debug(2, "About to try retrieving name file %s\n", dir)do { if ((option_debug >= (2) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (2)))) { ast_log
(0, "app_voicemail.c", 14194, __PRETTY_FUNCTION__, "About to try retrieving name file %s\n"
, dir); } } while (0)
;
14195 RETRIEVE(dir, -1, mailbox, context);
14196 if (ast_fileexists(dir, NULL((void*)0), NULL((void*)0))) {
14197 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY"0123456789#*ABCD");
14198 }
14199 DISPOSE(dir, -1);
14200 return res;
14201}
14202
14203/*!
14204 * \internal
14205 * \brief Play a recorded user name for the mailbox to the specified channel.
14206 *
14207 * \param chan Where to play the recorded name file.
14208 * \param mailbox_id The mailbox name.
14209 *
14210 * \retval 0 Name played without interruption
14211 * \retval dtmf ASCII value of the DTMF which interrupted playback.
14212 * \retval -1 Unable to locate mailbox or hangup occurred.
14213 */
14214static int vm_sayname(struct ast_channel *chan, const char *mailbox_id)
14215{
14216 char *context;
14217 char *mailbox;
14218
14219 if (ast_strlen_zero(mailbox_id)_ast_strlen_zero(mailbox_id, "app_voicemail.c", __PRETTY_FUNCTION__
, 14219)
14220 || separate_mailbox(ast_strdupa(mailbox_id)(__extension__ ({ const char *__old = (mailbox_id); size_t __len
= strlen(__old) + 1; char *__new = __builtin_alloca(__len); memcpy
(__new, __old, __len); __new; }))
, &mailbox, &context)) {
14221 return -1;
14222 }
14223 return sayname(chan, mailbox, context);
14224}
14225
14226static void read_password_from_file(const char *secretfn, char *password, int passwordlen) {
14227 struct ast_config *pwconf;
14228 struct ast_flags config_flags = { 0 };
14229
14230 pwconf = ast_config_load(secretfn, config_flags)ast_config_load2(secretfn, "app_voicemail", config_flags);
14231 if (valid_config(pwconf)) {
14232 const char *val = ast_variable_retrieve(pwconf, "general", "password");
14233 if (val) {
14234 ast_copy_string(password, val, passwordlen);
14235 ast_config_destroy(pwconf);
14236 return;
14237 }
14238 ast_config_destroy(pwconf);
14239 }
14240 ast_log(LOG_NOTICE2, "app_voicemail.c", 14240, __PRETTY_FUNCTION__, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
14241}
14242
14243static int write_password_to_file(const char *secretfn, const char *password) {
14244 struct ast_config *conf;
14245 struct ast_category *cat;
14246 struct ast_variable *var;
14247 int res = -1;
14248
14249 if (!(conf = ast_config_new())) {
14250 ast_log(LOG_ERROR4, "app_voicemail.c", 14250, __PRETTY_FUNCTION__, "Error creating new config structure\n");
14251 return res;
14252 }
14253 if (!(cat = ast_category_new("general", "", 1))) {
14254 ast_log(LOG_ERROR4, "app_voicemail.c", 14254, __PRETTY_FUNCTION__, "Error creating new category structure\n");
14255 ast_config_destroy(conf);
14256 return res;
14257 }
14258 if (!(var = ast_variable_new("password", password, ""))) {
14259 ast_log(LOG_ERROR4, "app_voicemail.c", 14259, __PRETTY_FUNCTION__, "Error creating new variable structure\n");
14260 ast_config_destroy(conf);
14261 ast_category_destroy(cat);
14262 return res;
14263 }
14264 ast_category_append(conf, cat);
14265 ast_variable_append(cat, var);
14266 if (!ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
14267 res = 0;
14268 } else {
14269 ast_log(LOG_ERROR4, "app_voicemail.c", 14269, __PRETTY_FUNCTION__, "Error writing voicemail password to %s\n", secretfn);
14270 }
14271
14272 ast_config_destroy(conf);
14273 return res;
14274}
14275
14276static int vmsayname_exec(struct ast_channel *chan, const char *data)
14277{
14278 char *context;
14279 char *mailbox;
14280 int res;
14281
14282 if (ast_strlen_zero(data)_ast_strlen_zero(data, "app_voicemail.c", __PRETTY_FUNCTION__
, 14282)
14283 || separate_mailbox(ast_strdupa(data)(__extension__ ({ const char *__old = (data); size_t __len = strlen
(__old) + 1; char *__new = __builtin_alloca(__len); memcpy (__new
, __old, __len); __new; }))
, &mailbox, &context)) {
14284 ast_log(LOG_WARNING3, "app_voicemail.c", 14284, __PRETTY_FUNCTION__, "VMSayName requires argument mailbox@context\n");
14285 return -1;
14286 }
14287
14288 if ((res = sayname(chan, mailbox, context)) < 0) {
14289 ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", mailbox, context)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("app_voicemail") >= (3)))) { ast_log
(0, "app_voicemail.c", 14289, __PRETTY_FUNCTION__, "Greeting not found for '%s@%s', falling back to mailbox number.\n"
, mailbox, context); } } while (0)
;
14290 res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY"0123456789#*ABCD");
14291 if (!res) {
14292 res = ast_say_character_str(chan, mailbox, AST_DIGIT_ANY"0123456789#*ABCD", ast_channel_language(chan), AST_SAY_CASE_NONE);
14293 }
14294 }
14295
14296 return res;
14297}
14298
14299#ifdef TEST_FRAMEWORK
14300static int fake_write(struct ast_channel *ast, struct ast_frame *frame)
14301{
14302 return 0;
14303}
14304
14305static struct ast_frame *fake_read(struct ast_channel *ast)
14306{
14307 return &ast_null_frame;
14308}
14309
14310AST_TEST_DEFINE(test_voicemail_vmsayname)static enum ast_test_result_state __attribute__((unused)) test_voicemail_vmsayname
(struct ast_test_info *info, enum ast_test_command cmd, struct
ast_test *test)
14311{
14312 char dir[PATH_MAX4096];
14313 char dir2[PATH_MAX4096];
14314 static const char TEST_CONTEXT[] = "very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
14315 static const char TEST_EXTENSION[] = "1234";
14316
14317 struct ast_channel *test_channel1 = NULL((void*)0);
14318 int res = -1;
14319 struct ast_format_cap *capabilities;
14320
14321 static const struct ast_channel_tech fake_tech = {
14322 .write = fake_write,
14323 .read = fake_read,
14324 };
14325
14326 switch (cmd) {
14327 case TEST_INIT:
14328 info->name = "vmsayname_exec";
14329 info->category = "/apps/app_voicemail/";
14330 info->summary = "Vmsayname unit test";
14331 info->description =
14332 "This tests passing various parameters to vmsayname";
14333 return AST_TEST_NOT_RUN;
14334 case TEST_EXECUTE:
14335 break;
14336 }
14337
14338 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL,__ast_channel_alloc(0, AST_STATE_DOWN, ((void*)0), ((void*)0)
, ((void*)0), ((void*)0), ((void*)0), ((void*)0), 0, 0, ((void
*)0), "app_voicemail.c", 14339, __FUNCTION__, "TestChannel1")
14339 NULL, NULL, 0, 0, "TestChannel1")__ast_channel_alloc(0, AST_STATE_DOWN, ((void*)0), ((void*)0)
, ((void*)0), ((void*)0), ((void*)0), ((void*)0), 0, 0, ((void
*)0), "app_voicemail.c", 14339, __FUNCTION__, "TestChannel1")
)) {
14340 goto exit_vmsayname_test;
14341 }
14342
14343 /* normally this is done in the channel driver */
14344 capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)__ast_format_cap_alloc((AST_FORMAT_CAP_FLAG_DEFAULT), "ast_format_cap_alloc"
, "app_voicemail.c", 14344, __PRETTY_FUNCTION__)
;
14345 if (!capabilities) {
14346 goto exit_vmsayname_test;
14347 }
14348 ast_format_cap_append(capabilities, ast_format_gsm, 0)__ast_format_cap_append((capabilities), (ast_format_gsm), (0)
, "ast_format_cap_append", "app_voicemail.c", 14348, __PRETTY_FUNCTION__
)
;
14349 ast_channel_nativeformats_set(test_channel1, capabilities);
14350 ao2_ref(capabilities, -1)__ao2_ref((capabilities), (-1), "", "app_voicemail.c", 14350,
__PRETTY_FUNCTION__)
;
14351 ast_channel_set_writeformat(test_channel1, ast_format_gsm);
14352 ast_channel_set_rawwriteformat(test_channel1, ast_format_gsm);
14353 ast_channel_set_readformat(test_channel1, ast_format_gsm);
14354 ast_channel_set_rawreadformat(test_channel1, ast_format_gsm);
14355 ast_channel_tech_set(test_channel1, &fake_tech);
14356
14357 ast_channel_unlock(test_channel1)__ao2_unlock(test_channel1, "app_voicemail.c", __PRETTY_FUNCTION__
, 14357, "test_channel1")
;
14358
14359 ast_test_status_update(test, "Test playing of extension when greeting is not available...\n");
14360 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT); /* not a dir, don't get confused */
14361 if (!(res = vmsayname_exec(test_channel1, dir))) {
14362 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
14363 if (ast_fileexists(dir, NULL((void*)0), NULL((void*)0))) {
14364 ast_test_status_update(test, "This should not happen, most likely means clean up from previous test failed\n");
14365 res = -1;
14366 goto exit_vmsayname_test;
14367 } else {
14368 /* no greeting already exists as expected, let's create one to fully test sayname */
14369 if ((res = create_dirpath(dir, sizeof(dir), TEST_CONTEXT, TEST_EXTENSION, ""))) {
14370 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 14370, __PRETTY_FUNCTION__, "Failed to make test directory\n");
14371 goto exit_vmsayname_test;
14372 }
14373 snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_VAR_DIR);
14374 snprintf(dir2, sizeof(dir2), "%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
14375 /* we're not going to hear the sound anyway, just use a valid gsm audio file */
14376 if ((res = symlink(dir, dir2))) {
14377 ast_log(LOG_WARNING3, "app_voicemail.c", 14377, __PRETTY_FUNCTION__, "Symlink reported %s\n", strerror(errno(*__errno_location ())));
14378 goto exit_vmsayname_test;
14379 }
14380 ast_test_status_update(test, "Test playing created mailbox greeting...\n");
14381 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT); /* not a dir, don't get confused */
14382 res = vmsayname_exec(test_channel1, dir);
14383
14384 /* TODO: there may be a better way to do this */
14385 unlink(dir2);
14386 snprintf(dir2, sizeof(dir2), "%s%s/%s", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
14387 rmdir(dir2);
14388 snprintf(dir2, sizeof(dir2), "%s%s", VM_SPOOL_DIR, TEST_CONTEXT);
14389 rmdir(dir2);
14390 }
14391 }
14392
14393exit_vmsayname_test:
14394
14395 ast_hangup(test_channel1);
14396
14397 return res ? AST_TEST_FAIL : AST_TEST_PASS;
14398}
14399
14400AST_TEST_DEFINE(test_voicemail_msgcount)static enum ast_test_result_state __attribute__((unused)) test_voicemail_msgcount
(struct ast_test_info *info, enum ast_test_command cmd, struct
ast_test *test)
14401{
14402 int i, j, res = AST_TEST_PASS, syserr;
14403 struct ast_vm_user *vmu;
14404 struct ast_vm_user svm;
14405 struct vm_state vms;
14406#ifdef IMAP_STORAGE
14407 struct ast_channel *chan = NULL((void*)0);
14408#endif
14409 struct {
14410 char dir[256];
14411 char file[256];
14412 char txtfile[256];
14413 } tmp[3];
14414 char syscmd[256];
14415 const char origweasels[] = "tt-weasels";
14416 const char testcontext[] = "test";
14417 const char testmailbox[] = "00000000";
14418 const char testspec[] = "00000000@test";
14419 FILE *txt;
14420 int new, old, urgent;
14421 const char *folders[3] = { "Old", "Urgent", "INBOX" };
14422 const int folder2mbox[3] = { 1, 11, 0 };
14423 const int expected_results[3][12] = {
14424 /* hasvm-old, hasvm-urgent, hasvm-new, ic-old, ic-urgent, ic-new, ic2-old, ic2-urgent, ic2-new, mc-old, mc-urgent, mc-new */
14425 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
14426 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
14427 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
14428 };
14429
14430 switch (cmd) {
14431 case TEST_INIT:
14432 info->name = "test_voicemail_msgcount";
14433 info->category = "/apps/app_voicemail/";
14434 info->summary = "Test Voicemail status checks";
14435 info->description =
14436 "Verify that message counts are correct when retrieved through the public API";
14437 return AST_TEST_NOT_RUN;
14438 case TEST_EXECUTE:
14439 break;
14440 }
14441
14442 /* Make sure the original path was completely empty */
14443 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
14444 if ((syserr = ast_safe_system(syscmd))) {
14445 ast_test_status_update(test, "Unable to clear test directory: %s\n",
14446 syserr > 0 ? strerror(syserr) : "unable to fork()");
14447 return AST_TEST_FAIL;
14448 }
14449
14450#ifdef IMAP_STORAGE
14451 if (!(chan = ast_dummy_channel_alloc()__ast_dummy_channel_alloc("app_voicemail.c", 14451, __PRETTY_FUNCTION__
)
)) {
14452 ast_test_status_update(test, "Unable to create dummy channel\n");
14453 return AST_TEST_FAIL;
14454 }
14455#endif
14456
14457 memset(&svm, 0, sizeof(svm));
14458 if (!(vmu = find_user(&svm, testcontext, testmailbox)) &&
14459 !(vmu = find_or_create(testcontext, testmailbox))) {
14460 ast_test_status_update(test, "Cannot create vmu structure\n");
14461 ast_unreplace_sigchld();
14462#ifdef IMAP_STORAGE
14463 chan = ast_channel_unref(chan)({ __ao2_ref((chan), (-1), "", "app_voicemail.c", 14463, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
14464#endif
14465 return AST_TEST_FAIL;
14466 }
14467
14468 populate_defaults(vmu);
14469 memset(&vms, 0, sizeof(vms));
14470
14471 /* Create temporary voicemail */
14472 for (i = 0; i < 3; i++) {
14473 create_dirpath(tmp[i].dir, sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
14474 make_file(tmp[i].file, sizeof(tmp[i].file), tmp[i].dir, 0);
14475 snprintf(tmp[i].txtfile, sizeof(tmp[i].txtfile), "%s.txt", tmp[i].file);
14476
14477 if (ast_fileexists(origweasels, "gsm", "en") > 0) {
14478 snprintf(syscmd, sizeof(syscmd), "cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"", ast_config_AST_DATA_DIR, origweasels,
14479 VM_SPOOL_DIR, testcontext, testmailbox, folders[i]);
14480 if ((syserr = ast_safe_system(syscmd))) {
14481 ast_test_status_update(test, "Unable to create test voicemail: %s\n",
14482 syserr > 0 ? strerror(syserr) : "unable to fork()");
14483 ast_unreplace_sigchld();
14484#ifdef IMAP_STORAGE
14485 chan = ast_channel_unref(chan)({ __ao2_ref((chan), (-1), "", "app_voicemail.c", 14485, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
14486#endif
14487 free_user(vmu);
14488 return AST_TEST_FAIL;
14489 }
14490 }
14491
14492 if ((txt = fopen(tmp[i].txtfile, "w+"))) {
14493 fprintf(txt, "; just a stub\n[message]\nflag=%s\n", strcmp(folders[i], "Urgent") ? "" : "Urgent");
14494 fclose(txt);
14495 } else {
14496 ast_test_status_update(test, "Unable to write message file '%s'\n", tmp[i].txtfile);
14497 res = AST_TEST_FAIL;
14498 break;
14499 }
14500 open_mailbox(&vms, vmu, folder2mbox[i]);
14501 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu, "gsm", 600, &vms, strcmp(folders[i], "Urgent") ? "" : "Urgent", NULL);
14502
14503 /* hasvm-old, hasvm-urgent, hasvm-new, ic-old, ic-urgent, ic-new, ic2-old, ic2-urgent, ic2-new, mc-old, mc-urgent, mc-new */
14504 for (j = 0; j < 3; j++) {
14505 /* folder[2] is INBOX, __has_voicemail will default back to INBOX */
14506 if (ast_app_has_voicemail(testspec, (j==2 ? NULL((void*)0) : folders[j])) != expected_results[i][0 + j]) {
14507 ast_test_status_update(test, "has_voicemail(%s, %s) returned %d and we expected %d\n",
14508 testspec, folders[j], ast_app_has_voicemail(testspec, folders[j]), expected_results[i][0 + j]);
14509 res = AST_TEST_FAIL;
14510 }
14511 }
14512
14513 new = old = urgent = 0;
14514 if (ast_app_inboxcount(testspec, &new, &old)) {
14515 ast_test_status_update(test, "inboxcount returned failure\n");
14516 res = AST_TEST_FAIL;
14517 } else if (old != expected_results[i][3 + 0] || new != expected_results[i][3 + 2]) {
14518 ast_test_status_update(test, "inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n",
14519 testspec, old, expected_results[i][3 + 0], new, expected_results[i][3 + 2]);
14520 res = AST_TEST_FAIL;
14521 }
14522
14523 new = old = urgent = 0;
14524 if (ast_app_inboxcount2(testspec, &urgent, &new, &old)) {
14525 ast_test_status_update(test, "inboxcount2 returned failure\n");
14526 res = AST_TEST_FAIL;
14527 } else if (old != expected_results[i][6 + 0] ||
14528 urgent != expected_results[i][6 + 1] ||
14529 new != expected_results[i][6 + 2] ) {
14530 ast_test_status_update(test, "inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
14531 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1], new, expected_results[i][6 + 2]);
14532 res = AST_TEST_FAIL;
14533 }
14534
14535 new = old = urgent = 0;
14536 for (j = 0; j < 3; j++) {
14537 if (ast_app_messagecount(testspec, folders[j]) != expected_results[i][9 + j]) {
14538 ast_test_status_update(test, "messagecount(%s, %s) returned %d and we expected %d\n",
14539 testspec, folders[j], ast_app_messagecount(testspec, folders[j]), expected_results[i][9 + j]);
14540 res = AST_TEST_FAIL;
14541 }
14542 }
14543 }
14544
14545 for (i = 0; i < 3; i++) {
14546 /* This is necessary if the voicemails are stored on an ODBC/IMAP
14547 * server, in which case, the rm below will not affect the
14548 * voicemails. */
14549 DELETE(tmp[i].dir, 0, tmp[i].file, vmu)(vm_delete(tmp[i].file));
14550 DISPOSE(tmp[i].dir, 0);
14551 }
14552
14553 if (vms.deleted) {
14554 ast_freefree(vms.deleted);
14555 }
14556 if (vms.heard) {
14557 ast_freefree(vms.heard);
14558 }
14559
14560#ifdef IMAP_STORAGE
14561 chan = ast_channel_unref(chan)({ __ao2_ref((chan), (-1), "", "app_voicemail.c", 14561, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
14562#endif
14563
14564 /* And remove test directory */
14565 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
14566 if ((syserr = ast_safe_system(syscmd))) {
14567 ast_test_status_update(test, "Unable to clear test directory: %s\n",
14568 syserr > 0 ? strerror(syserr) : "unable to fork()");
14569 }
14570
14571 free_user(vmu);
14572 return res;
14573}
14574
14575AST_TEST_DEFINE(test_voicemail_notify_endl)static enum ast_test_result_state __attribute__((unused)) test_voicemail_notify_endl
(struct ast_test_info *info, enum ast_test_command cmd, struct
ast_test *test)
14576{
14577 int res = AST_TEST_PASS;
14578 char testcontext[] = "test";
14579 char testmailbox[] = "00000000";
14580 char from[] = "test@example.net", cidnum[] = "1234", cidname[] = "Mark Spencer", format[] = "gsm";
14581 char attach[256], attach2[256];
14582 char buf[256] = ""; /* No line should actually be longer than 80 */
14583 struct ast_channel *chan = NULL((void*)0);
14584 struct ast_vm_user *vmu, vmus = {
14585 .flags = 0,
14586 };
14587 FILE *file;
14588 struct {
14589 char *name;
14590 enum { INT, FLAGVAL, STATIC, STRPTR } type;
14591 void *location;
14592 union {
14593 int intval;
14594 char *strval;
14595 } u;
14596 } test_items[] = {
14597 { "plain jane config", STATIC, vmus.password, .u.strval = "1234" }, /* No, this doesn't change this test any. */
14598 { "emailsubject", STRPTR, vmus.emailsubject, .u.strval = "Oogly boogly\xf8koogly with what appears to be UTF-8" },
14599 { "emailbody", STRPTR, vmus.emailbody, .u.strval = "This is a test\n\twith multiple\nlines\nwithin\n" },
14600 { "serveremail", STATIC, vmus.serveremail, .u.strval = "\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
14601 { "attachment flag", FLAGVAL, &vmus.flags, .u.intval = VM_ATTACH(1 << 11) },
14602 { "attach2", STRPTR, attach2, .u.strval = "" },
14603 { "attach", STRPTR, attach, .u.strval = "" },
14604 };
14605 int which;
14606
14607 switch (cmd) {
14608 case TEST_INIT:
14609 info->name = "test_voicemail_notify_endl";
14610 info->category = "/apps/app_voicemail/";
14611 info->summary = "Test Voicemail notification end-of-line";
14612 info->description =
14613 "Verify that notification emails use a consistent end-of-line character";
14614 return AST_TEST_NOT_RUN;
14615 case TEST_EXECUTE:
14616 break;
14617 }
14618
14619 snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_VAR_DIR);
14620 snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_VAR_DIR);
14621
14622 if (!(vmu = find_user(&vmus, testcontext, testmailbox)) &&
14623 !(vmu = find_or_create(testcontext, testmailbox))) {
14624 ast_test_status_update(test, "Cannot create vmu structure\n");
14625 return AST_TEST_NOT_RUN;
14626 }
14627
14628 if (vmu != &vmus && !(vmu = find_user(&vmus, testcontext, testmailbox))) {
14629 ast_test_status_update(test, "Cannot find vmu structure?!!\n");
14630 return AST_TEST_NOT_RUN;
14631 }
14632
14633 populate_defaults(vmu);
14634 vmu->email = ast_strdup("test2@example.net")_ast_strdup(("test2@example.net"), "app_voicemail.c", 14634, __PRETTY_FUNCTION__
)
;
14635#ifdef IMAP_STORAGE
14636 /* TODO When we set up the IMAP server test, we'll need to have credentials for the VMU structure added here */
14637#endif
14638
14639 file = tmpfile();
14640 for (which = 0; which < ARRAY_LEN(test_items)(size_t) (sizeof(test_items) / sizeof(0[test_items])); which++) {
14641 /* Kill previous test, if any */
14642 rewind(file);
14643 if (ftruncate(fileno(file), 0)) {
14644 ast_test_status_update(test, "Cannot truncate test output file: %s\n", strerror(errno));
14645 res = AST_TEST_FAIL;
14646 break;
14647 }
14648
14649 /* Make each change, in order, to the test mailbox */
14650 if (test_items[which].type == INT) {
14651 *((int *) test_items[which].location) = test_items[which].u.intval;
14652 } else if (test_items[which].type == FLAGVAL) {
14653 if (ast_test_flag(vmu, test_items[which].u.intval)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
(test_items[which].u.intval)); })
) {
14654 ast_clear_flag(vmu, test_items[which].u.intval)do { typeof ((vmu)->flags) __p = (vmu)->flags; typeof (
__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); ((vmu)->flags &= ~(test_items[which].u.intval));
} while(0)
;
14655 } else {
14656 ast_set_flag(vmu, test_items[which].u.intval)do { typeof ((vmu)->flags) __p = (vmu)->flags; typeof (
__unsigned_int_flags_dummy) __x = 0; (void) (&__p == &
__x); ((vmu)->flags |= (test_items[which].u.intval)); } while
(0)
;
14657 }
14658 } else if (test_items[which].type == STATIC) {
14659 strcpy(test_items[which].location, test_items[which].u.strval);
14660 } else if (test_items[which].type == STRPTR) {
14661 test_items[which].location = test_items[which].u.strval;
14662 }
14663
14664 make_email_file(file, from, vmu, 0, testcontext, testmailbox, "INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan, NULL((void*)0), 0, NULL((void*)0), NULL((void*)0));
14665 rewind(file);
14666 while (fgets(buf, sizeof(buf), file)) {
14667 if (
14668 (strlen(buf) > 1 &&
14669#ifdef IMAP_STORAGE
14670 buf[strlen(buf) - 2] != '\r'
14671#else
14672 buf[strlen(buf) - 2] == '\r'
14673#endif
14674 )
14675 || buf[strlen(buf) - 1] != '\n') {
14676 res = AST_TEST_FAIL;
14677 }
14678 }
14679 }
14680 fclose(file);
14681 free_user(vmu);
14682 return res;
14683}
14684
14685AST_TEST_DEFINE(test_voicemail_load_config)static enum ast_test_result_state __attribute__((unused)) test_voicemail_load_config
(struct ast_test_info *info, enum ast_test_command cmd, struct
ast_test *test)
14686{
14687 int res = AST_TEST_PASS;
14688 struct ast_vm_user *vmu;
14689 struct ast_config *cfg;
14690 char config_filename[32] = "/tmp/voicemail.conf.XXXXXX";
14691 int fd;
14692 FILE *file;
14693 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
14694
14695 switch (cmd) {
14696 case TEST_INIT:
14697 info->name = "test_voicemail_load_config";
14698 info->category = "/apps/app_voicemail/";
14699 info->summary = "Test loading Voicemail config";
14700 info->description =
14701 "Verify that configuration is loaded consistently. "
14702 "This is to test regressions of ASTERISK-18838 where it was noticed that "
14703 "some options were loaded after the mailboxes were instantiated, causing "
14704 "those options not to be set correctly.";
14705 return AST_TEST_NOT_RUN;
14706 case TEST_EXECUTE:
14707 break;
14708 }
14709
14710 /* build a config file by hand... */
14711 if ((fd = mkstemp(config_filename)) < 0) {
14712 return AST_TEST_FAIL;
14713 }
14714 if (!(file = fdopen(fd, "w"))) {
14715 close(fd);
14716 unlink(config_filename);
14717 return AST_TEST_FAIL;
14718 }
14719 fputs("[general]\ncallback=somecontext\nlocale=de_DE.UTF-8\ntz=european\n[test]", file);
14720 fputs("00000001 => 9999,Mr. Test,,,callback=othercontext|locale=nl_NL.UTF-8|tz=central\n", file);
14721 fputs("00000002 => 9999,Mrs. Test\n", file);
14722 fclose(file);
14723
14724 if (!(cfg = ast_config_load(config_filename, config_flags)ast_config_load2(config_filename, "app_voicemail", config_flags
)
) || !valid_config(cfg)) {
14725 res = AST_TEST_FAIL;
14726 goto cleanup;
14727 }
14728
14729 load_config_from_memory(1, cfg, NULL((void*)0));
14730 ast_config_destroy(cfg);
14731
14732#define CHECK(u, attr, value) else if (strcmp(u->attr, value)) { \
14733 ast_test_status_update(test, "mailbox %s should have %s '%s', but has '%s'\n", \
14734 u->mailbox, #attr, value, u->attr); res = AST_TEST_FAIL; break; }
14735
14736 AST_LIST_LOCK(&users)__ast_pthread_mutex_lock("app_voicemail.c", 14736, __PRETTY_FUNCTION__
, "&(&users)->lock", &(&users)->lock)
;
14737 AST_LIST_TRAVERSE(&users, vmu, list)for((vmu) = (&users)->first; (vmu); (vmu) = (vmu)->
list.next)
{
14738 if (!strcmp(vmu->mailbox, "00000001")) {
14739 if (0); /* trick to get CHECK to work */
14740 CHECK(vmu, callback, "othercontext")
14741 CHECK(vmu, locale, "nl_NL.UTF-8")
14742 CHECK(vmu, zonetag, "central")
14743 } else if (!strcmp(vmu->mailbox, "00000002")) {
14744 if (0); /* trick to get CHECK to work */
14745 CHECK(vmu, callback, "somecontext")
14746 CHECK(vmu, locale, "de_DE.UTF-8")
14747 CHECK(vmu, zonetag, "european")
14748 }
14749 }
14750 AST_LIST_UNLOCK(&users)__ast_pthread_mutex_unlock("app_voicemail.c", 14750, __PRETTY_FUNCTION__
, "&(&users)->lock", &(&users)->lock)
;
14751
14752#undef CHECK
14753
14754 /* restore config */
14755 load_config(1); /* this might say "Failed to load configuration file." */
14756
14757cleanup:
14758 unlink(config_filename);
14759 return res;
14760}
14761
14762AST_TEST_DEFINE(test_voicemail_vm_info)static enum ast_test_result_state __attribute__((unused)) test_voicemail_vm_info
(struct ast_test_info *info, enum ast_test_command cmd, struct
ast_test *test)
14763{
14764 struct ast_vm_user *vmu;
14765 struct ast_channel *chan = NULL((void*)0);
14766 const char testcontext[] = "test";
14767 const char testmailbox[] = "00000000";
14768 const char vminfo_cmd[] = "VM_INFO";
14769 char vminfo_buf[256], vminfo_args[256];
14770 int res = AST_TEST_PASS;
14771 int test_ret = 0;
14772 int test_counter = 0;
14773
14774 struct {
14775 char *vminfo_test_args;
14776 char *vminfo_expected;
14777 int vminfo_ret;
14778 } test_items[] = {
14779 { "", "", -1 }, /* Missing argument */
14780 { "00000000@test,badparam", "", -1 }, /* Wrong argument */
14781 { "00000000@test", "", -1 }, /* Missing argument */
14782 { "00000000@test,exists", "1", 0 },
14783 { "11111111@test,exists", "0", 0 }, /* Invalid mailbox */
14784 { "00000000@test,email", "vm-info-test@example.net", 0 },
14785 { "11111111@test,email", "", 0 }, /* Invalid mailbox */
14786 { "00000000@test,fullname", "Test Framework Mailbox", 0 },
14787 { "00000000@test,pager", "vm-info-pager-test@example.net", 0 },
14788 { "00000000@test,locale", "en_US", 0 },
14789 { "00000000@test,tz", "central", 0 },
14790 { "00000000@test,language", "en", 0 },
14791 { "00000000@test,password", "9876", 0 },
14792 };
14793
14794 switch (cmd) {
14795 case TEST_INIT:
14796 info->name = "test_voicemail_vm_info";
14797 info->category = "/apps/app_voicemail/";
14798 info->summary = "VM_INFO unit test";
14799 info->description =
14800 "This tests passing various parameters to VM_INFO";
14801 return AST_TEST_NOT_RUN;
14802 case TEST_EXECUTE:
14803 break;
14804 }
14805
14806 if (!(chan = ast_dummy_channel_alloc()__ast_dummy_channel_alloc("app_voicemail.c", 14806, __PRETTY_FUNCTION__
)
)) {
14807 ast_test_status_update(test, "Unable to create dummy channel\n");
14808 return AST_TEST_FAIL;
14809 }
14810
14811 if (!(vmu = find_user(NULL((void*)0), testcontext, testmailbox)) &&
14812 !(vmu = find_or_create(testcontext, testmailbox))) {
14813 ast_test_status_update(test, "Cannot create vmu structure\n");
14814 chan = ast_channel_unref(chan)({ __ao2_ref((chan), (-1), "", "app_voicemail.c", 14814, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
14815 return AST_TEST_FAIL;
14816 }
14817
14818 populate_defaults(vmu);
14819
14820 vmu->email = ast_strdup("vm-info-test@example.net")_ast_strdup(("vm-info-test@example.net"), "app_voicemail.c", 14820
, __PRETTY_FUNCTION__)
;
14821 ast_copy_string(vmu->fullname, "Test Framework Mailbox", sizeof(vmu->fullname));
14822 ast_copy_string(vmu->pager, "vm-info-pager-test@example.net", sizeof(vmu->pager));
14823 ast_copy_string(vmu->language, "en", sizeof(vmu->language));
14824 ast_copy_string(vmu->zonetag, "central", sizeof(vmu->zonetag));
14825 ast_copy_string(vmu->locale, "en_US", sizeof(vmu->zonetag));
14826 ast_copy_string(vmu->password, "9876", sizeof(vmu->password));
14827
14828 for (test_counter = 0; test_counter < ARRAY_LEN(test_items)(size_t) (sizeof(test_items) / sizeof(0[test_items])); test_counter++) {
14829 ast_copy_string(vminfo_args, test_items[test_counter].vminfo_test_args, sizeof(vminfo_args));
14830 test_ret = acf_vm_info(chan, vminfo_cmd, vminfo_args, vminfo_buf, sizeof(vminfo_buf));
14831 if (strcmp(vminfo_buf, test_items[test_counter].vminfo_expected)) {
14832 ast_test_status_update(test, "VM_INFO respose was: '%s', but expected: '%s'\n", vminfo_buf, test_items[test_counter].vminfo_expected);
14833 res = AST_TEST_FAIL;
14834 }
14835 if (!(test_ret == test_items[test_counter].vminfo_ret)) {
14836 ast_test_status_update(test, "VM_INFO return code was: '%i', but expected '%i'\n", test_ret, test_items[test_counter].vminfo_ret);
14837 res = AST_TEST_FAIL;
14838 }
14839 }
14840
14841 chan = ast_channel_unref(chan)({ __ao2_ref((chan), (-1), "", "app_voicemail.c", 14841, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
14842 free_user(vmu);
14843 return res;
14844}
14845#endif /* defined(TEST_FRAMEWORK) */
14846
14847static const struct ast_vm_functions vm_table = {
14848 .module_version = VM_MODULE_VERSION2,
14849 .module_name = AST_MODULE"app_voicemail",
14850
14851 .has_voicemail = has_voicemail,
14852 .inboxcount = inboxcount,
14853 .inboxcount2 = inboxcount2,
14854 .messagecount = messagecount,
14855 .copy_recording_to_vm = msg_create_from_file,
14856 .index_to_foldername = vm_index_to_foldername,
14857 .mailbox_snapshot_create = vm_mailbox_snapshot_create,
14858 .mailbox_snapshot_destroy = vm_mailbox_snapshot_destroy,
14859 .msg_move = vm_msg_move,
14860 .msg_remove = vm_msg_remove,
14861 .msg_forward = vm_msg_forward,
14862 .msg_play = vm_msg_play,
14863};
14864
14865static const struct ast_vm_greeter_functions vm_greeter_table = {
14866 .module_version = VM_GREETER_MODULE_VERSION1,
14867 .module_name = AST_MODULE"app_voicemail",
14868
14869 .sayname = vm_sayname,
14870};
14871
14872static int reload(void)
14873{
14874 return load_config(1);
14875}
14876
14877static int unload_module(void)
14878{
14879 int res;
14880
14881 res = ast_unregister_application(app);
14882 res |= ast_unregister_application(app2);
14883 res |= ast_unregister_application(app3);
14884 res |= ast_unregister_application(app4);
14885 res |= ast_unregister_application(playmsg_app);
14886 res |= ast_unregister_application(sayname_app);
14887 res |= ast_custom_function_unregister(&mailbox_exists_acf);
14888 res |= ast_custom_function_unregister(&vm_info_acf);
14889 res |= ast_manager_unregister("VoicemailUsersList");
14890 res |= ast_manager_unregister("VoicemailRefresh");
14891 res |= ast_data_unregister(NULL)__ast_data_unregister(((void*)0), "app_voicemail.c");
14892#ifdef TEST_FRAMEWORK
14893 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
14894 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
14895 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
14896 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
14897 res |= AST_TEST_UNREGISTER(test_voicemail_load_config);
14898 res |= AST_TEST_UNREGISTER(test_voicemail_vm_info);
14899#endif
14900 ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail)(size_t) (sizeof(cli_voicemail) / sizeof(0[cli_voicemail])));
14901 ast_vm_unregister(vm_table.module_name);
14902 ast_vm_greeter_unregister(vm_greeter_table.module_name);
14903#ifdef TEST_FRAMEWORK
14904 ast_uninstall_vm_test_functions();
14905#endif
14906 ao2_ref(inprocess_container, -1)__ao2_ref((inprocess_container), (-1), "", "app_voicemail.c",
14906, __PRETTY_FUNCTION__)
;
14907
14908 if (poll_thread != AST_PTHREADT_NULL(pthread_t) -1)
14909 stop_poll_thread();
14910
14911 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
14912 ast_unload_realtime("voicemail");
14913 ast_unload_realtime("voicemail_data");
14914
14915 free_vm_users();
14916 free_vm_zones();
14917 return res;
14918}
14919
14920/*!
14921 * \brief Load the module
14922 *
14923 * Module loading including tests for configuration or dependencies.
14924 * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
14925 * or AST_MODULE_LOAD_SUCCESS.
14926 *
14927 * If a dependency, allocation or environment variable fails tests, return AST_MODULE_LOAD_FAILURE.
14928 *
14929 * If the module can't load the configuration file, can't register as a provider or
14930 * has another issue not fatal to Asterisk itself, return AST_MODULE_LOAD_DECLINE.
14931 *
14932 * On success return AST_MODULE_LOAD_SUCCESS.
14933 */
14934static int load_module(void)
14935{
14936 int res;
14937 my_umask = umask(0);
14938 umask(my_umask);
14939
14940 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn)__ao2_container_alloc_hash(((AO2_ALLOC_OPT_LOCK_MUTEX)), (0),
(((573))), (((inprocess_hash_fn))), (((void*)0)), (((inprocess_cmp_fn
))), "", "app_voicemail.c", 14940, __PRETTY_FUNCTION__)
)) {
14941 return AST_MODULE_LOAD_FAILURE;
14942 }
14943
14944 /* compute the location of the voicemail spool directory */
14945 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
14946
14947 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
14948 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 14948, __PRETTY_FUNCTION__, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
14949 }
14950
14951 if ((res = load_config(0))) {
14952 unload_module();
14953 return AST_MODULE_LOAD_DECLINE;
14954 }
14955
14956 res = ast_register_application_xml(app, vm_exec)ast_register_application2(app, vm_exec, ((void*)0), ((void*)0
), __internal_app_voicemail_self())
;
14957 res |= ast_register_application_xml(app2, vm_execmain)ast_register_application2(app2, vm_execmain, ((void*)0), ((void
*)0), __internal_app_voicemail_self())
;
14958 res |= ast_register_application_xml(app3, vm_box_exists)ast_register_application2(app3, vm_box_exists, ((void*)0), ((
void*)0), __internal_app_voicemail_self())
;
14959 res |= ast_register_application_xml(app4, vmauthenticate)ast_register_application2(app4, vmauthenticate, ((void*)0), (
(void*)0), __internal_app_voicemail_self())
;
14960 res |= ast_register_application_xml(playmsg_app, vm_playmsgexec)ast_register_application2(playmsg_app, vm_playmsgexec, ((void
*)0), ((void*)0), __internal_app_voicemail_self())
;
14961 res |= ast_register_application_xml(sayname_app, vmsayname_exec)ast_register_application2(sayname_app, vmsayname_exec, ((void
*)0), ((void*)0), __internal_app_voicemail_self())
;
14962 res |= ast_custom_function_register(&mailbox_exists_acf)__ast_custom_function_register(&mailbox_exists_acf, __internal_app_voicemail_self
())
;
14963 res |= ast_custom_function_register(&vm_info_acf)__ast_custom_function_register(&vm_info_acf, __internal_app_voicemail_self
())
;
14964 res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users)ast_manager_register2("VoicemailUsersList", (1 << 1) | (
1 << 9), manager_list_voicemail_users, __internal_app_voicemail_self
(), ((void*)0), ((void*)0))
;
14965 res |= ast_manager_register_xml("VoicemailRefresh", EVENT_FLAG_USER, manager_voicemail_refresh)ast_manager_register2("VoicemailRefresh", (1 << 6), manager_voicemail_refresh
, __internal_app_voicemail_self(), ((void*)0), ((void*)0))
;
14966#ifdef TEST_FRAMEWORK
14967 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
14968 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
14969 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
14970 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
14971 res |= AST_TEST_REGISTER(test_voicemail_load_config);
14972 res |= AST_TEST_REGISTER(test_voicemail_vm_info);
14973#endif
14974
14975 if (res) {
14976 ast_log(LOG_ERROR4, "app_voicemail.c", 14976, __PRETTY_FUNCTION__, "Failure registering applications, functions or tests\n");
14977 unload_module();
14978 return AST_MODULE_LOAD_DECLINE;
14979 }
14980
14981 /* ast_vm_register may return DECLINE if another module registered for vm */
14982 res = ast_vm_register(&vm_table)__ast_vm_register(&vm_table, __internal_app_voicemail_self
())
;
14983 if (res) {
14984 ast_log(LOG_ERROR4, "app_voicemail.c", 14984, __PRETTY_FUNCTION__, "Failure registering as a voicemail provider\n");
14985 unload_module();
14986 return AST_MODULE_LOAD_DECLINE;
14987 }
14988
14989 /* ast_vm_greeter_register may return DECLINE if another module registered as a greeter */
14990 res = ast_vm_greeter_register(&vm_greeter_table)__ast_vm_greeter_register(&vm_greeter_table, __internal_app_voicemail_self
())
;
14991 if (res) {
14992 ast_log(LOG_ERROR4, "app_voicemail.c", 14992, __PRETTY_FUNCTION__, "Failure registering as a greeter provider\n");
14993 unload_module();
14994 return AST_MODULE_LOAD_DECLINE;
14995 }
14996
14997 ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail))__ast_cli_register_multiple(cli_voicemail, (size_t) (sizeof(cli_voicemail
) / sizeof(0[cli_voicemail])), __internal_app_voicemail_self(
))
;
14998 ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers))__ast_data_register_multiple(vm_data_providers, (size_t) (sizeof
(vm_data_providers) / sizeof(0[vm_data_providers])), "app_voicemail.c"
, __internal_app_voicemail_self())
;
14999
15000#ifdef TEST_FRAMEWORK
15001 ast_install_vm_test_functions(vm_test_create_user, vm_test_destroy_user);
15002#endif
15003
15004 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL((char *)((void*)0)));
15005 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL((char *)((void*)0)));
15006
15007 return AST_MODULE_LOAD_SUCCESS;
15008}
15009
15010static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
15011{
15012 int cmd = 0;
15013 char destination[80] = "";
15014 int retries = 0;
15015
15016 if (!num) {
15017 ast_verb(3, "Destination number will be entered manually\n")do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 15017, __PRETTY_FUNCTION__, 3, "Destination number will be entered manually\n"
); } } while (0)
;
15018 while (retries < 3 && cmd != 't') {
15019 destination[1] = '\0';
15020 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
15021 if (!cmd)
15022 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
15023 if (!cmd)
15024 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
15025 if (!cmd) {
15026 cmd = ast_waitfordigit(chan, 6000);
15027 if (cmd)
15028 destination[0] = cmd;
15029 }
15030 if (!cmd) {
15031 retries++;
15032 } else {
15033
15034 if (cmd < 0)
15035 return 0;
15036 if (cmd == '*') {
15037 ast_verb(3, "User hit '*' to cancel outgoing call\n")do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 15037, __PRETTY_FUNCTION__, 3, "User hit '*' to cancel outgoing call\n"
); } } while (0)
;
15038 return 0;
15039 }
15040 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0)
15041 retries++;
15042 else
15043 cmd = 't';
15044 }
15045 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
15046 }
15047 if (retries >= 3) {
15048 return 0;
15049 }
15050
15051 } else {
15052 ast_verb(3, "Destination number is CID number '%s'\n", num)do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 15052, __PRETTY_FUNCTION__, 3, "Destination number is CID number '%s'\n"
, num); } } while (0)
;
15053 ast_copy_string(destination, num, sizeof(destination));
15054 }
15055
15056 if (!ast_strlen_zero(destination)_ast_strlen_zero(destination, "app_voicemail.c", __PRETTY_FUNCTION__
, 15056)
) {
15057 if (destination[strlen(destination) -1 ] == '*')
15058 return 0;
15059 ast_verb(3, "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, ast_channel_context(chan))do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 15059, __PRETTY_FUNCTION__, 3, "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n"
, destination, outgoing_context, ast_channel_context(chan)); }
} while (0)
;
15060 ast_channel_exten_set(chan, destination);
15061 ast_channel_context_set(chan, outgoing_context);
15062 ast_channel_priority_set(chan, 0);
15063 return 9;
15064 }
15065 return 0;
15066}
15067
15068/*!
15069 * \brief The advanced options within a message.
15070 * \param chan
15071 * \param vmu
15072 * \param vms
15073 * \param msg
15074 * \param option
15075 * \param record_gain
15076 *
15077 * Provides handling for the play message envelope, call the person back, or reply to message.
15078 *
15079 * \return zero on success, -1 on error.
15080 */
15081static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, int option, signed char record_gain)
15082{
15083 int res = 0;
15084 char filename[PATH_MAX4096];
15085 struct ast_config *msg_cfg = NULL((void*)0);
15086 const char *origtime, *context;
15087 char *name, *num;
15088 int retries = 0;
15089 char *cid;
15090 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
15091
15092 vms->starting = 0;
15093
15094 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
15095
15096 /* Retrieve info from VM attribute file */
15097 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
15098 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
15099 msg_cfg = ast_config_load(filename, config_flags)ast_config_load2(filename, "app_voicemail", config_flags);
15100 DISPOSE(vms->curdir, vms->curmsg);
15101 if (!valid_config(msg_cfg)) {
15102 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 15102, __PRETTY_FUNCTION__, "No message attribute file?!! (%s)\n", filename);
15103 return 0;
15104 }
15105
15106 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
15107 ast_config_destroy(msg_cfg);
15108 return 0;
15109 }
15110
15111 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"))(__extension__ ({ const char *__old = (ast_variable_retrieve(
msg_cfg, "message", "callerid")); size_t __len = strlen(__old
) + 1; char *__new = __builtin_alloca(__len); memcpy (__new, __old
, __len); __new; }))
;
15112
15113 context = ast_variable_retrieve(msg_cfg, "message", "context");
15114 if (!strncasecmp("macro", context, 5)) /* Macro names in contexts are useless for our needs */
15115 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
15116 switch (option) {
15117 case 3: /* Play message envelope */
15118 if (!res) {
15119 res = play_message_datetime(chan, vmu, origtime, filename);
15120 }
15121 if (!res) {
15122 res = play_message_callerid(chan, vms, cid, context, 0, 1);
15123 }
15124
15125 res = 't';
15126 break;
15127
15128 case 2: /* Call back */
15129
15130 if (ast_strlen_zero(cid)_ast_strlen_zero(cid, "app_voicemail.c", __PRETTY_FUNCTION__,
15130)
)
15131 break;
15132
15133 ast_callerid_parse(cid, &name, &num);
15134 while ((res > -1) && (res != 't')) {
15135 switch (res) {
15136 case '1':
15137 if (num) {
15138 /* Dial the CID number */
15139 res = dialout(chan, vmu, num, vmu->callback);
15140 if (res) {
15141 ast_config_destroy(msg_cfg);
15142 return 9;
15143 }
15144 } else {
15145 res = '2';
15146 }
15147 break;
15148
15149 case '2':
15150 /* Want to enter a different number, can only do this if there's a dialout context for this user */
15151 if (!ast_strlen_zero(vmu->dialout)_ast_strlen_zero(vmu->dialout, "app_voicemail.c", __PRETTY_FUNCTION__
, 15151)
) {
15152 res = dialout(chan, vmu, NULL((void*)0), vmu->dialout);
15153 if (res) {
15154 ast_config_destroy(msg_cfg);
15155 return 9;
15156 }
15157 } else {
15158 ast_verb(3, "Caller can not specify callback number - no dialout context available\n")do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 15158, __PRETTY_FUNCTION__, 3, "Caller can not specify callback number - no dialout context available\n"
); } } while (0)
;
15159 res = ast_play_and_wait(chan, "vm-sorry");
15160 }
15161 ast_config_destroy(msg_cfg);
15162 return res;
15163 case '*':
15164 res = 't';
15165 break;
15166 case '3':
15167 case '4':
15168 case '5':
15169 case '6':
15170 case '7':
15171 case '8':
15172 case '9':
15173 case '0':
15174
15175 res = ast_play_and_wait(chan, "vm-sorry");
15176 retries++;
15177 break;
15178 default:
15179 if (num) {
15180 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num)do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 15180, __PRETTY_FUNCTION__, 3, "Confirm CID number '%s' is number to use for callback\n"
, num); } } while (0)
;
15181 res = ast_play_and_wait(chan, "vm-num-i-have");
15182 if (!res)
15183 res = play_message_callerid(chan, vms, num, vmu->context, 1, 1);
15184 if (!res)
15185 res = ast_play_and_wait(chan, "vm-tocallnum");
15186 /* Only prompt for a caller-specified number if there is a dialout context specified */
15187 if (!ast_strlen_zero(vmu->dialout)_ast_strlen_zero(vmu->dialout, "app_voicemail.c", __PRETTY_FUNCTION__
, 15187)
) {
15188 if (!res)
15189 res = ast_play_and_wait(chan, "vm-calldiffnum");
15190 }
15191 } else {
15192 res = ast_play_and_wait(chan, "vm-nonumber");
15193 if (!ast_strlen_zero(vmu->dialout)_ast_strlen_zero(vmu->dialout, "app_voicemail.c", __PRETTY_FUNCTION__
, 15193)
) {
15194 if (!res)
15195 res = ast_play_and_wait(chan, "vm-toenternumber");
15196 }
15197 }
15198 if (!res) {
15199 res = ast_play_and_wait(chan, "vm-star-cancel");
15200 }
15201 if (!res) {
15202 res = ast_waitfordigit(chan, 6000);
15203 }
15204 if (!res) {
15205 retries++;
15206 if (retries > 3) {
15207 res = 't';
15208 }
15209 }
15210 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
15211 break;
15212
15213 }
15214 if (res == 't')
15215 res = 0;
15216 else if (res == '*')
15217 res = -1;
15218 }
15219 break;
15220
15221 case 1: /* Reply */
15222 /* Send reply directly to sender */
15223 if (ast_strlen_zero(cid)_ast_strlen_zero(cid, "app_voicemail.c", __PRETTY_FUNCTION__,
15223)
)
15224 break;
15225
15226 ast_callerid_parse(cid, &name, &num);
15227 if (!num) {
15228 ast_verb(3, "No CID number available, no reply sent\n")do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 15228, __PRETTY_FUNCTION__, 3, "No CID number available, no reply sent\n"
); } } while (0)
;
15229 if (!res)
15230 res = ast_play_and_wait(chan, "vm-nonumber");
15231 ast_config_destroy(msg_cfg);
15232 return res;
15233 } else {
15234 struct ast_vm_user vmu2, *vmu3;
15235 memset(&vmu2, 0, sizeof(vmu2));
15236 vmu3 = find_user(&vmu2, vmu->context, num);
15237 if (vmu3) {
15238 struct leave_vm_options leave_options;
15239 char mailbox[AST_MAX_EXTENSION80 * 2 + 2];
15240 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
15241
15242 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context)do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 15242, __PRETTY_FUNCTION__, 3, "Leaving voicemail for '%s' in context '%s'\n"
, num, vmu->context); } } while (0)
;
15243
15244 memset(&leave_options, 0, sizeof(leave_options));
15245 leave_options.record_gain = record_gain;
15246 res = leave_voicemail(chan, mailbox, &leave_options);
15247 if (!res)
15248 res = 't';
15249 ast_config_destroy(msg_cfg);
15250 free_user(vmu3);
15251 return res;
15252 } else {
15253 /* Sender has no mailbox, can't reply */
15254 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context)do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 15254, __PRETTY_FUNCTION__, 3, "No mailbox number '%s' in context '%s', no reply sent\n"
, num, vmu->context); } } while (0)
;
15255 ast_play_and_wait(chan, "vm-nobox");
15256 res = 't';
15257 ast_config_destroy(msg_cfg);
15258 return res;
15259 }
15260 }
15261 res = 0;
15262
15263 break;
15264 }
15265
15266 ast_config_destroy(msg_cfg);
15267
15268#ifndef IMAP_STORAGE
15269 if (!res) {
15270 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
15271 vms->heard[msg] = 1;
15272 res = wait_file(chan, vms, vms->fn);
15273 }
15274#endif
15275 return res;
15276}
15277
15278static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
15279 int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
15280 signed char record_gain, struct vm_state *vms, char *flag, const char *msg_id, int forwardintro)
15281{
15282 /* Record message & let caller review or re-record it, or set options if applicable */
15283 int res = 0;
15284 int cmd = 0;
15285 int max_attempts = 3;
15286 int attempts = 0;
15287 int recorded = 0;
15288 int msg_exists = 0;
15289 signed char zero_gain = 0;
15290 char tempfile[PATH_MAX4096];
15291 char *acceptdtmf = "#";
15292 char *canceldtmf = "";
15293 int canceleddtmf = 0;
15294
15295 /* Note that urgent and private are for flagging messages as such in the future */
15296
15297 /* barf if no pointer passed to store duration in */
15298 if (duration == NULL((void*)0)) {
15299 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 15299, __PRETTY_FUNCTION__, "Error play_record_review called without duration pointer\n");
15300 return -1;
15301 }
15302
15303 if (!outsidecaller)
15304 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
15305 else
15306 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
15307
15308 cmd = '3'; /* Want to start by recording */
15309
15310 while ((cmd >= 0) && (cmd != 't')) {
15311 switch (cmd) {
15312 case '1':
15313 if (!msg_exists) {
15314 /* In this case, 1 is to record a message */
15315 cmd = '3';
15316 break;
15317 } else {
15318 /* Otherwise 1 is to save the existing message */
15319 ast_verb(3, "Saving message as is\n")do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 15319, __PRETTY_FUNCTION__, 3, "Saving message as is\n"); }
} while (0)
;
15320 if (!outsidecaller)
15321 ast_filerename(tempfile, recordfile, NULL((void*)0));
15322 if (!forwardintro) {
15323 ast_stream_and_wait(chan, "vm-msgsaved", "");
15324 }
15325 if (!outsidecaller) {
15326 /* Saves to IMAP server only if imapgreeting=yes */
15327 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag, msg_id);
15328 DISPOSE(recordfile, -1);
15329 }
15330 cmd = 't';
15331 return res;
15332 }
15333 case '2':
15334 /* Review */
15335 ast_verb(3, "Reviewing the message\n")do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 15335, __PRETTY_FUNCTION__, 3, "Reviewing the message\n"); }
} while (0)
;
15336 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY"0123456789#*ABCD");
15337 break;
15338 case '3':
15339 msg_exists = 0;
15340 /* Record */
15341 if (recorded == 1)
15342 ast_verb(3, "Re-recording the message\n")do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 15342, __PRETTY_FUNCTION__, 3, "Re-recording the message\n"
); } } while (0)
;
15343 else
15344 ast_verb(3, "Recording the message\n")do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 15344, __PRETTY_FUNCTION__, 3, "Recording the message\n"); }
} while (0)
;
15345
15346 if (recorded && outsidecaller) {
15347 if (forwardintro) {
15348 cmd = ast_play_and_wait(chan, "vm-record-prepend");
15349 } else {
15350 cmd = ast_play_and_wait(chan, INTRO"vm-intro");
15351 }
15352 cmd = ast_play_and_wait(chan, "beep");
15353 }
15354 recorded = 1;
15355 /* After an attempt has been made to record message, we have to take care of INTRO and beep for incoming messages, but not for greetings */
15356 if (record_gain)
15357 ast_channel_setoption(chan, AST_OPTION_RXGAIN6, &record_gain, sizeof(record_gain), 0);
15358 if (ast_test_flag(vmu, VM_OPERATOR)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 1))); })
)
15359 canceldtmf = "0";
15360 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, 0, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf, 0, AST_RECORD_IF_EXISTS_OVERWRITE);
15361 if (strchr(canceldtmf, cmd)(__extension__ (__builtin_constant_p (cmd) && !__builtin_constant_p
(canceldtmf) && (cmd) == '\0' ? (char *) __rawmemchr
(canceldtmf, cmd) : __builtin_strchr (canceldtmf, cmd)))
) {
15362 /* need this flag here to distinguish between pressing '0' during message recording or after */
15363 canceleddtmf = 1;
15364 }
15365 if (record_gain)
15366 ast_channel_setoption(chan, AST_OPTION_RXGAIN6, &zero_gain, sizeof(zero_gain), 0);
15367 if (cmd == -1) {
15368 /* User has hung up, no options to give */
15369 if (!outsidecaller) {
15370 /* user was recording a greeting and they hung up, so let's delete the recording. */
15371 ast_filedelete(tempfile, NULL((void*)0));
15372 }
15373 return cmd;
15374 }
15375 if (cmd == '0') {
15376 break;
15377 } else if (cmd == '*') {
15378 break;
15379#if 0
15380 } else if (vmu->review && sound_duration && (*sound_duration < 5)) {
15381 /* Message is too short */
15382 ast_verb(3, "Message too short\n")do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 15382, __PRETTY_FUNCTION__, 3, "Message too short\n"); } } while
(0)
;
15383 cmd = ast_play_and_wait(chan, "vm-tooshort");
15384 cmd = ast_filedelete(tempfile, NULL((void*)0));
15385 break;
15386 } else if (vmu->review && (cmd == 2 && sound_duration && *sound_duration < (maxsilence + 3))) {
15387 /* Message is all silence */
15388 ast_verb(3, "Nothing recorded\n")do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 15388, __PRETTY_FUNCTION__, 3, "Nothing recorded\n"); } } while
(0)
;
15389 cmd = ast_filedelete(tempfile, NULL((void*)0));
15390 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
15391 if (!cmd)
15392 cmd = ast_play_and_wait(chan, "vm-speakup");
15393 break;
15394#endif
15395 } else {
15396 /* If all is well, a message exists */
15397 msg_exists = 1;
15398 cmd = 0;
15399 }
15400 break;
15401 case '4':
15402 if (outsidecaller) { /* only mark vm messages */
15403 /* Mark Urgent */
15404 if ((flag && ast_strlen_zero(flag)_ast_strlen_zero(flag, "app_voicemail.c", __PRETTY_FUNCTION__
, 15404)
) || (!ast_strlen_zero(flag)_ast_strlen_zero(flag, "app_voicemail.c", __PRETTY_FUNCTION__
, 15404)
&& strcmp(flag, "Urgent"))) {
15405 ast_verb(3, "marking message as Urgent\n")do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 15405, __PRETTY_FUNCTION__, 3, "marking message as Urgent\n"
); } } while (0)
;
15406 res = ast_play_and_wait(chan, "vm-marked-urgent");
15407 strcpy(flag, "Urgent");
15408 } else if (flag) {
15409 ast_verb(3, "UNmarking message as Urgent\n")do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("app_voicemail.c"
, 15409, __PRETTY_FUNCTION__, 3, "UNmarking message as Urgent\n"
); } } while (0)
;
15410 res = ast_play_and_wait(chan, "vm-marked-nonurgent");
15411 strcpy(flag, "");
15412 } else {
15413 ast_play_and_wait(chan, "vm-sorry");
15414 }
15415 cmd = 0;
15416 } else {
15417 cmd = ast_play_and_wait(chan, "vm-sorry");
15418 }
15419 break;
15420 case '5':
15421 case '6':
15422 case '7':
15423 case '8':
15424 case '9':
15425 case '*':
15426 case '#':
15427 cmd = ast_play_and_wait(chan, "vm-sorry");
15428 break;
15429#if 0
15430/* XXX Commented out for the moment because of the dangers of deleting
15431 a message while recording (can put the message numbers out of sync) */
15432 case '*':
15433 /* Cancel recording, delete message, offer to take another message*/
15434 cmd = ast_play_and_wait(chan, "vm-deleted");
15435 cmd = ast_filedelete(tempfile, NULL((void*)0));
15436 if (outsidecaller) {
15437 res = vm_exec(chan, NULL((void*)0));
15438 return res;
15439 }
15440 else
15441 return 1;
15442#endif
15443 case '0':
15444 if (!ast_test_flag(vmu, VM_OPERATOR)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 1))); })
|| (!canceleddtmf && !outsidecaller)) {
15445 cmd = ast_play_and_wait(chan, "vm-sorry");
15446 break;
15447 }
15448 if (msg_exists || recorded) {
15449 cmd = ast_play_and_wait(chan, "vm-saveoper");
15450 if (!cmd)
15451 cmd = ast_waitfordigit(chan, 3000);
15452 if (cmd == '1') {
15453 ast_filerename(tempfile, recordfile, NULL((void*)0));
15454 ast_play_and_wait(chan, "vm-msgsaved");
15455 cmd = '0';
15456 } else if (cmd == '4') {
15457 if (flag) {
15458 ast_play_and_wait(chan, "vm-marked-urgent");
15459 strcpy(flag, "Urgent");
15460 }
15461 ast_play_and_wait(chan, "vm-msgsaved");
15462 cmd = '0';
15463 } else {
15464 ast_play_and_wait(chan, "vm-deleted");
15465 DELETE(tempfile, -1, tempfile, vmu)(vm_delete(tempfile));
15466 DISPOSE(tempfile, -1);
15467 cmd = '0';
15468 }
15469 }
15470 return cmd;
15471 default:
15472 /* If the caller is an ouside caller and the review option is enabled or it's forward intro
15473 allow them to review the message, but let the owner of the box review
15474 their OGM's */
15475 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 0))); })
&& !forwardintro)
15476 return cmd;
15477 if (msg_exists) {
15478 cmd = ast_play_and_wait(chan, "vm-review");
15479 if (!cmd && outsidecaller) {
15480 if ((flag && ast_strlen_zero(flag)_ast_strlen_zero(flag, "app_voicemail.c", __PRETTY_FUNCTION__
, 15480)
) || (!ast_strlen_zero(flag)_ast_strlen_zero(flag, "app_voicemail.c", __PRETTY_FUNCTION__
, 15480)
&& strcmp(flag, "Urgent"))) {
15481 cmd = ast_play_and_wait(chan, "vm-review-urgent");
15482 } else if (flag) {
15483 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
15484 }
15485 }
15486 } else {
15487 cmd = ast_play_and_wait(chan, "vm-torerecord");
15488 if (!cmd)
15489 cmd = ast_waitfordigit(chan, 600);
15490 }
15491
15492 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)({ typeof ((vmu)->flags) __p = (vmu)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((vmu)->flags &
((1 << 1))); })
) {
15493 cmd = ast_play_and_wait(chan, "vm-reachoper");
15494 if (!cmd)
15495 cmd = ast_waitfordigit(chan, 600);
15496 }
15497#if 0
15498 if (!cmd)
15499 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
15500#endif
15501 if (!cmd)
15502 cmd = ast_waitfordigit(chan, 6000);
15503 if (!cmd) {
15504 attempts++;
15505 }
15506 if (attempts > max_attempts) {
15507 cmd = 't';
15508 }
15509 }
15510 }
15511 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
15512 /* Hang up or timeout, so delete the recording. */
15513 ast_filedelete(tempfile, NULL((void*)0));
15514 }
15515
15516 if (cmd != 't' && outsidecaller)
15517 ast_play_and_wait(chan, "vm-goodbye");
15518
15519 return cmd;
15520}
15521
15522static struct ast_vm_msg_snapshot *vm_msg_snapshot_alloc(void)
15523{
15524 struct ast_vm_msg_snapshot *msg_snapshot;
15525
15526 if (!(msg_snapshot = ast_calloc(1, sizeof(*msg_snapshot))_ast_calloc((1), (sizeof(*msg_snapshot)), "app_voicemail.c", 15526
, __PRETTY_FUNCTION__)
)) {
15527 return NULL((void*)0);
15528 }
15529
15530 if (ast_string_field_init(msg_snapshot, 512)({ int __res__ = -1; if (((void *)(msg_snapshot)) != ((void*)
0)) { __res__ = __ast_string_field_init(&(msg_snapshot)->
__field_mgr, &(msg_snapshot)->__field_mgr_pool, 512, "app_voicemail.c"
, 15530, __PRETTY_FUNCTION__); } __res__ ; })
) {
15531 ast_freefree(msg_snapshot);
15532 return NULL((void*)0);
15533 }
15534
15535 return msg_snapshot;
15536}
15537
15538static struct ast_vm_msg_snapshot *vm_msg_snapshot_destroy(struct ast_vm_msg_snapshot *msg_snapshot)
15539{
15540 ast_string_field_free_memory(msg_snapshot)({ int __res__ = -1; if (((void *)(msg_snapshot)) != ((void*)
0)) { __res__ = __ast_string_field_free_memory(&(msg_snapshot
)->__field_mgr, &(msg_snapshot)->__field_mgr_pool, AST_STRINGFIELD_DESTROY
, "app_voicemail.c", 15540, __PRETTY_FUNCTION__); } __res__; }
)
;
15541 ast_freefree(msg_snapshot);
15542
15543 return NULL((void*)0);
15544}
15545
15546#ifdef TEST_FRAMEWORK
15547
15548static int vm_test_destroy_user(const char *context, const char *mailbox)
15549{
15550 struct ast_vm_user *vmu;
15551
15552 AST_LIST_LOCK(&users)__ast_pthread_mutex_lock("app_voicemail.c", 15552, __PRETTY_FUNCTION__
, "&(&users)->lock", &(&users)->lock)
;
15553 AST_LIST_TRAVERSE_SAFE_BEGIN(&users, vmu, list){ typeof((&users)) __list_head = &users; typeof(__list_head
->first) __list_next; typeof(__list_head->first) __list_prev
= ((void*)0); typeof(__list_head->first) __list_current; for
((vmu) = __list_head->first, __list_current = (vmu), __list_next
= (vmu) ? (vmu)->list.next : ((void*)0); (vmu); __list_prev
= __list_current, (vmu) = __list_next, __list_current = (vmu
), __list_next = (vmu) ? (vmu)->list.next : ((void*)0), (void
) __list_prev )
{
15554 if (!strcmp(context, vmu->context)
15555 && !strcmp(mailbox, vmu->mailbox)) {
15556 AST_LIST_REMOVE_CURRENT(list)do { __list_current->list.next = ((void*)0); __list_current
= __list_prev; if (__list_prev) { __list_prev->list.next =
__list_next; } else { __list_head->first = __list_next; }
if (!__list_next) { __list_head->last = __list_prev; } } while
(0)
;
15557 ast_freefree(vmu);
15558 break;
15559 }
15560 }
15561 AST_LIST_TRAVERSE_SAFE_END}
15562 AST_LIST_UNLOCK(&users)__ast_pthread_mutex_unlock("app_voicemail.c", 15562, __PRETTY_FUNCTION__
, "&(&users)->lock", &(&users)->lock)
;
15563 return 0;
15564}
15565
15566static int vm_test_create_user(const char *context, const char *mailbox)
15567{
15568 struct ast_vm_user *vmu;
15569
15570 if (!(vmu = find_or_create(context, mailbox))) {
15571 return -1;
15572 }
15573 populate_defaults(vmu);
15574 return 0;
15575}
15576
15577#endif
15578
15579/*!
15580 * \brief Create and store off all the msgs in an open mailbox
15581 *
15582 * \note TODO XXX This function should work properly for all
15583 * voicemail storage options, but is far more expensive for
15584 * ODBC at the moment. This is because the RETRIEVE macro
15585 * not only pulls out the message's meta data file from the
15586 * database, but also the actual audio for each message, temporarily
15587 * writing it to the file system. This is an area that needs
15588 * to be made more efficient.
15589 */
15590static int vm_msg_snapshot_create(struct ast_vm_user *vmu,
15591 struct vm_state *vms,
15592 struct ast_vm_mailbox_snapshot *mailbox_snapshot,
15593 int snapshot_index,
15594 int mailbox_index,
15595 int descending,
15596 enum ast_vm_snapshot_sort_val sort_val)
15597{
15598 struct ast_vm_msg_snapshot *msg_snapshot;
15599 struct ast_vm_msg_snapshot *msg_snapshot_tmp;
15600 struct ast_config *msg_cfg;
15601 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
15602 char filename[PATH_MAX4096];
15603 const char *value;
15604
15605 for (vms->curmsg = 0; vms->curmsg <= vms->lastmsg; vms->curmsg++) {
15606 int inserted = 0;
15607 /* Find the msg */
15608 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
15609 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
15610 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
15611 msg_cfg = ast_config_load(filename, config_flags)ast_config_load2(filename, "app_voicemail", config_flags);
15612 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID(void *)-2) {
15613 DISPOSE(vms->curdir, vms->curmsg);
15614 continue;
15615 }
15616
15617 /* Create the snapshot object */
15618 if (!(msg_snapshot = vm_msg_snapshot_alloc())) {
15619 ast_config_destroy(msg_cfg);
15620 return -1;
15621 }
15622
15623 /* Fill in the snapshot object */
15624 if ((value = ast_variable_retrieve(msg_cfg, "message", "msg_id"))) {
15625 ast_string_field_set(msg_snapshot, msg_id, value)({ int __res__ = -1; if (((void *)(msg_snapshot)) != ((void*)
0)) { __res__ = ({ int __res__ = -1; if (((void *)(msg_snapshot
)) != ((void*)0)) { __res__ = ({ int __res__ = 0; const char *
__d__ = (value); size_t __dlen__ = (__d__) ? strlen(__d__) + 1
: 1; ast_string_field *__p__ = (ast_string_field *) (&(msg_snapshot
)->msg_id); ast_string_field target = *__p__; if (__dlen__
== 1) { __ast_string_field_release_active((msg_snapshot)->
__field_mgr_pool, *__p__); *__p__ = __ast_string_field_empty;
} else if ((__dlen__ <= *((ast_string_field_allocation *)
(*__p__ - __alignof__(ast_string_field_allocation)))) || (!__ast_string_field_ptr_grow
(&(msg_snapshot)->__field_mgr, &(msg_snapshot)->
__field_mgr_pool, __dlen__, __p__)) || (target = __ast_string_field_alloc_space
(&(msg_snapshot)->__field_mgr, &(msg_snapshot)->
__field_mgr_pool, __dlen__))) { if (target != *__p__) { __ast_string_field_release_active
((msg_snapshot)->__field_mgr_pool, *__p__); *__p__ = target
; } memcpy(* (void **) __p__, __d__, __dlen__); } else { __res__
= -1; } __res__; }); } __res__; }); } __res__; })
;
15626 } else {
15627 /* Message snapshots *really* should have a
15628 * message ID. Add one to the message config
15629 * if it does not already exist
15630 */
15631 char id[MSG_ID_LEN256];
15632 if (!(add_message_id(msg_cfg, vms->curdir, vms->curmsg,
15633 filename, id, sizeof(id), vmu, mailbox_index))) {
15634 ast_string_field_set(msg_snapshot, msg_id, id)({ int __res__ = -1; if (((void *)(msg_snapshot)) != ((void*)
0)) { __res__ = ({ int __res__ = -1; if (((void *)(msg_snapshot
)) != ((void*)0)) { __res__ = ({ int __res__ = 0; const char *
__d__ = (id); size_t __dlen__ = (__d__) ? strlen(__d__) + 1 :
1; ast_string_field *__p__ = (ast_string_field *) (&(msg_snapshot
)->msg_id); ast_string_field target = *__p__; if (__dlen__
== 1) { __ast_string_field_release_active((msg_snapshot)->
__field_mgr_pool, *__p__); *__p__ = __ast_string_field_empty;
} else if ((__dlen__ <= *((ast_string_field_allocation *)
(*__p__ - __alignof__(ast_string_field_allocation)))) || (!__ast_string_field_ptr_grow
(&(msg_snapshot)->__field_mgr, &(msg_snapshot)->
__field_mgr_pool, __dlen__, __p__)) || (target = __ast_string_field_alloc_space
(&(msg_snapshot)->__field_mgr, &(msg_snapshot)->
__field_mgr_pool, __dlen__))) { if (target != *__p__) { __ast_string_field_release_active
((msg_snapshot)->__field_mgr_pool, *__p__); *__p__ = target
; } memcpy(* (void **) __p__, __d__, __dlen__); } else { __res__
= -1; } __res__; }); } __res__; }); } __res__; })
;
15635 } else {
15636 ast_log(LOG_WARNING3, "app_voicemail.c", 15636, __PRETTY_FUNCTION__, "Unable to create a message ID for message %s/%d\n", vms->curdir, vms->curmsg);
15637 }
15638 }
15639 if ((value = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
15640 ast_string_field_set(msg_snapshot, callerid, value)({ int __res__ = -1; if (((void *)(msg_snapshot)) != ((void*)
0)) { __res__ = ({ int __res__ = -1; if (((void *)(msg_snapshot
)) != ((void*)0)) { __res__ = ({ int __res__ = 0; const char *
__d__ = (value); size_t __dlen__ = (__d__) ? strlen(__d__) + 1
: 1; ast_string_field *__p__ = (ast_string_field *) (&(msg_snapshot
)->callerid); ast_string_field target = *__p__; if (__dlen__
== 1) { __ast_string_field_release_active((msg_snapshot)->
__field_mgr_pool, *__p__); *__p__ = __ast_string_field_empty;
} else if ((__dlen__ <= *((ast_string_field_allocation *)
(*__p__ - __alignof__(ast_string_field_allocation)))) || (!__ast_string_field_ptr_grow
(&(msg_snapshot)->__field_mgr, &(msg_snapshot)->
__field_mgr_pool, __dlen__, __p__)) || (target = __ast_string_field_alloc_space
(&(msg_snapshot)->__field_mgr, &(msg_snapshot)->
__field_mgr_pool, __dlen__))) { if (target != *__p__) { __ast_string_field_release_active
((msg_snapshot)->__field_mgr_pool, *__p__); *__p__ = target
; } memcpy(* (void **) __p__, __d__, __dlen__); } else { __res__
= -1; } __res__; }); } __res__; }); } __res__; })
;
15641 }
15642 if ((value = ast_variable_retrieve(msg_cfg, "message", "callerchan"))) {
15643 ast_string_field_set(msg_snapshot, callerchan, value)({ int __res__ = -1; if (((void *)(msg_snapshot)) != ((void*)
0)) { __res__ = ({ int __res__ = -1; if (((void *)(msg_snapshot
)) != ((void*)0)) { __res__ = ({ int __res__ = 0; const char *
__d__ = (value); size_t __dlen__ = (__d__) ? strlen(__d__) + 1
: 1; ast_string_field *__p__ = (ast_string_field *) (&(msg_snapshot
)->callerchan); ast_string_field target = *__p__; if (__dlen__
== 1) { __ast_string_field_release_active((msg_snapshot)->
__field_mgr_pool, *__p__); *__p__ = __ast_string_field_empty;
} else if ((__dlen__ <= *((ast_string_field_allocation *)
(*__p__ - __alignof__(ast_string_field_allocation)))) || (!__ast_string_field_ptr_grow
(&(msg_snapshot)->__field_mgr, &(msg_snapshot)->
__field_mgr_pool, __dlen__, __p__)) || (target = __ast_string_field_alloc_space
(&(msg_snapshot)->__field_mgr, &(msg_snapshot)->
__field_mgr_pool, __dlen__))) { if (target != *__p__) { __ast_string_field_release_active
((msg_snapshot)->__field_mgr_pool, *__p__); *__p__ = target
; } memcpy(* (void **) __p__, __d__, __dlen__); } else { __res__
= -1; } __res__; }); } __res__; }); } __res__; })
;
15644 }
15645 if ((value = ast_variable_retrieve(msg_cfg, "message", "exten"))) {
15646 ast_string_field_set(msg_snapshot, exten, value)({ int __res__ = -1; if (((void *)(msg_snapshot)) != ((void*)
0)) { __res__ = ({ int __res__ = -1; if (((void *)(msg_snapshot
)) != ((void*)0)) { __res__ = ({ int __res__ = 0; const char *
__d__ = (value); size_t __dlen__ = (__d__) ? strlen(__d__) + 1
: 1; ast_string_field *__p__ = (ast_string_field *) (&(msg_snapshot
)->exten); ast_string_field target = *__p__; if (__dlen__ ==
1) { __ast_string_field_release_active((msg_snapshot)->__field_mgr_pool
, *__p__); *__p__ = __ast_string_field_empty; } else if ((__dlen__
<= *((ast_string_field_allocation *) (*__p__ - __alignof__
(ast_string_field_allocation)))) || (!__ast_string_field_ptr_grow
(&(msg_snapshot)->__field_mgr, &(msg_snapshot)->
__field_mgr_pool, __dlen__, __p__)) || (target = __ast_string_field_alloc_space
(&(msg_snapshot)->__field_mgr, &(msg_snapshot)->
__field_mgr_pool, __dlen__))) { if (target != *__p__) { __ast_string_field_release_active
((msg_snapshot)->__field_mgr_pool, *__p__); *__p__ = target
; } memcpy(* (void **) __p__, __d__, __dlen__); } else { __res__
= -1; } __res__; }); } __res__; }); } __res__; })
;
15647 }
15648 if ((value = ast_variable_retrieve(msg_cfg, "message", "origdate"))) {
15649 ast_string_field_set(msg_snapshot, origdate, value)({ int __res__ = -1; if (((void *)(msg_snapshot)) != ((void*)
0)) { __res__ = ({ int __res__ = -1; if (((void *)(msg_snapshot
)) != ((void*)0)) { __res__ = ({ int __res__ = 0; const char *
__d__ = (value); size_t __dlen__ = (__d__) ? strlen(__d__) + 1
: 1; ast_string_field *__p__ = (ast_string_field *) (&(msg_snapshot
)->origdate); ast_string_field target = *__p__; if (__dlen__
== 1) { __ast_string_field_release_active((msg_snapshot)->
__field_mgr_pool, *__p__); *__p__ = __ast_string_field_empty;
} else if ((__dlen__ <= *((ast_string_field_allocation *)
(*__p__ - __alignof__(ast_string_field_allocation)))) || (!__ast_string_field_ptr_grow
(&(msg_snapshot)->__field_mgr, &(msg_snapshot)->
__field_mgr_pool, __dlen__, __p__)) || (target = __ast_string_field_alloc_space
(&(msg_snapshot)->__field_mgr, &(msg_snapshot)->
__field_mgr_pool, __dlen__))) { if (target != *__p__) { __ast_string_field_release_active
((msg_snapshot)->__field_mgr_pool, *__p__); *__p__ = target
; } memcpy(* (void **) __p__, __d__, __dlen__); } else { __res__
= -1; } __res__; }); } __res__; }); } __res__; })
;
15650 }
15651 if ((value = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
15652 ast_string_field_set(msg_snapshot, origtime, value)({ int __res__ = -1; if (((void *)(msg_snapshot)) != ((void*)
0)) { __res__ = ({ int __res__ = -1; if (((void *)(msg_snapshot
)) != ((void*)0)) { __res__ = ({ int __res__ = 0; const char *
__d__ = (value); size_t __dlen__ = (__d__) ? strlen(__d__) + 1
: 1; ast_string_field *__p__ = (ast_string_field *) (&(msg_snapshot
)->origtime); ast_string_field target = *__p__; if (__dlen__
== 1) { __ast_string_field_release_active((msg_snapshot)->
__field_mgr_pool, *__p__); *__p__ = __ast_string_field_empty;
} else if ((__dlen__ <= *((ast_string_field_allocation *)
(*__p__ - __alignof__(ast_string_field_allocation)))) || (!__ast_string_field_ptr_grow
(&(msg_snapshot)->__field_mgr, &(msg_snapshot)->
__field_mgr_pool, __dlen__, __p__)) || (target = __ast_string_field_alloc_space
(&(msg_snapshot)->__field_mgr, &(msg_snapshot)->
__field_mgr_pool, __dlen__))) { if (target != *__p__) { __ast_string_field_release_active
((msg_snapshot)->__field_mgr_pool, *__p__); *__p__ = target
; } memcpy(* (void **) __p__, __d__, __dlen__); } else { __res__
= -1; } __res__; }); } __res__; }); } __res__; })
;
15653 }
15654 if ((value = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
15655 ast_string_field_set(msg_snapshot, duration, value)({ int __res__ = -1; if (((void *)(msg_snapshot)) != ((void*)
0)) { __res__ = ({ int __res__ = -1; if (((void *)(msg_snapshot
)) != ((void*)0)) { __res__ = ({ int __res__ = 0; const char *
__d__ = (value); size_t __dlen__ = (__d__) ? strlen(__d__) + 1
: 1; ast_string_field *__p__ = (ast_string_field *) (&(msg_snapshot
)->duration); ast_string_field target = *__p__; if (__dlen__
== 1) { __ast_string_field_release_active((msg_snapshot)->
__field_mgr_pool, *__p__); *__p__ = __ast_string_field_empty;
} else if ((__dlen__ <= *((ast_string_field_allocation *)
(*__p__ - __alignof__(ast_string_field_allocation)))) || (!__ast_string_field_ptr_grow
(&(msg_snapshot)->__field_mgr, &(msg_snapshot)->
__field_mgr_pool, __dlen__, __p__)) || (target = __ast_string_field_alloc_space
(&(msg_snapshot)->__field_mgr, &(msg_snapshot)->
__field_mgr_pool, __dlen__))) { if (target != *__p__) { __ast_string_field_release_active
((msg_snapshot)->__field_mgr_pool, *__p__); *__p__ = target
; } memcpy(* (void **) __p__, __d__, __dlen__); } else { __res__
= -1; } __res__; }); } __res__; }); } __res__; })
;
15656 }
15657 if ((value = ast_variable_retrieve(msg_cfg, "message", "flag"))) {
15658 ast_string_field_set(msg_snapshot, flag, value)({ int __res__ = -1; if (((void *)(msg_snapshot)) != ((void*)
0)) { __res__ = ({ int __res__ = -1; if (((void *)(msg_snapshot
)) != ((void*)0)) { __res__ = ({ int __res__ = 0; const char *
__d__ = (value); size_t __dlen__ = (__d__) ? strlen(__d__) + 1
: 1; ast_string_field *__p__ = (ast_string_field *) (&(msg_snapshot
)->flag); ast_string_field target = *__p__; if (__dlen__ ==
1) { __ast_string_field_release_active((msg_snapshot)->__field_mgr_pool
, *__p__); *__p__ = __ast_string_field_empty; } else if ((__dlen__
<= *((ast_string_field_allocation *) (*__p__ - __alignof__
(ast_string_field_allocation)))) || (!__ast_string_field_ptr_grow
(&(msg_snapshot)->__field_mgr, &(msg_snapshot)->
__field_mgr_pool, __dlen__, __p__)) || (target = __ast_string_field_alloc_space
(&(msg_snapshot)->__field_mgr, &(msg_snapshot)->
__field_mgr_pool, __dlen__))) { if (target != *__p__) { __ast_string_field_release_active
((msg_snapshot)->__field_mgr_pool, *__p__); *__p__ = target
; } memcpy(* (void **) __p__, __d__, __dlen__); } else { __res__
= -1; } __res__; }); } __res__; }); } __res__; })
;
15659 }
15660 msg_snapshot->msg_number = vms->curmsg;
15661 ast_string_field_set(msg_snapshot, folder_name, mailbox_folders[mailbox_index])({ int __res__ = -1; if (((void *)(msg_snapshot)) != ((void*)
0)) { __res__ = ({ int __res__ = -1; if (((void *)(msg_snapshot
)) != ((void*)0)) { __res__ = ({ int __res__ = 0; const char *
__d__ = (mailbox_folders[mailbox_index]); size_t __dlen__ = (
__d__) ? strlen(__d__) + 1 : 1; ast_string_field *__p__ = (ast_string_field
*) (&(msg_snapshot)->folder_name); ast_string_field target
= *__p__; if (__dlen__ == 1) { __ast_string_field_release_active
((msg_snapshot)->__field_mgr_pool, *__p__); *__p__ = __ast_string_field_empty
; } else if ((__dlen__ <= *((ast_string_field_allocation *
) (*__p__ - __alignof__(ast_string_field_allocation)))) || (!
__ast_string_field_ptr_grow(&(msg_snapshot)->__field_mgr
, &(msg_snapshot)->__field_mgr_pool, __dlen__, __p__))
|| (target = __ast_string_field_alloc_space(&(msg_snapshot
)->__field_mgr, &(msg_snapshot)->__field_mgr_pool, __dlen__
))) { if (target != *__p__) { __ast_string_field_release_active
((msg_snapshot)->__field_mgr_pool, *__p__); *__p__ = target
; } memcpy(* (void **) __p__, __d__, __dlen__); } else { __res__
= -1; } __res__; }); } __res__; }); } __res__; })
;
15662
15663 /* store msg snapshot in mailbox snapshot */
15664 switch (sort_val) {
15665 default:
15666 case AST_VM_SNAPSHOT_SORT_BY_ID:
15667 if (descending) {
15668 AST_LIST_INSERT_HEAD(&mailbox_snapshot->snapshots[snapshot_index], msg_snapshot, msg)do { (msg_snapshot)->msg.next = (&mailbox_snapshot->
snapshots[snapshot_index])->first; (&mailbox_snapshot->
snapshots[snapshot_index])->first = (msg_snapshot); if (!(
&mailbox_snapshot->snapshots[snapshot_index])->last
) (&mailbox_snapshot->snapshots[snapshot_index])->last
= (msg_snapshot); } while (0)
;
15669 } else {
15670 AST_LIST_INSERT_TAIL(&mailbox_snapshot->snapshots[snapshot_index], msg_snapshot, msg)do { if (!(&mailbox_snapshot->snapshots[snapshot_index
])->first) { (&mailbox_snapshot->snapshots[snapshot_index
])->first = (msg_snapshot); (&mailbox_snapshot->snapshots
[snapshot_index])->last = (msg_snapshot); } else { (&mailbox_snapshot
->snapshots[snapshot_index])->last->msg.next = (msg_snapshot
); (&mailbox_snapshot->snapshots[snapshot_index])->
last = (msg_snapshot); } } while (0)
;
15671 }
15672 inserted = 1;
15673 break;
15674 case AST_VM_SNAPSHOT_SORT_BY_TIME:
15675 AST_LIST_TRAVERSE_SAFE_BEGIN(&mailbox_snapshot->snapshots[snapshot_index], msg_snapshot_tmp, msg){ typeof((&mailbox_snapshot->snapshots[snapshot_index]
)) __list_head = &mailbox_snapshot->snapshots[snapshot_index
]; typeof(__list_head->first) __list_next; typeof(__list_head
->first) __list_prev = ((void*)0); typeof(__list_head->
first) __list_current; for ((msg_snapshot_tmp) = __list_head->
first, __list_current = (msg_snapshot_tmp), __list_next = (msg_snapshot_tmp
) ? (msg_snapshot_tmp)->msg.next : ((void*)0); (msg_snapshot_tmp
); __list_prev = __list_current, (msg_snapshot_tmp) = __list_next
, __list_current = (msg_snapshot_tmp), __list_next = (msg_snapshot_tmp
) ? (msg_snapshot_tmp)->msg.next : ((void*)0), (void) __list_prev
)
{
15676 int val = strcmp(msg_snapshot->origtime, msg_snapshot_tmp->origtime);
15677 if (descending && val >= 0) {
15678 AST_LIST_INSERT_BEFORE_CURRENT(msg_snapshot, msg)do { if (__list_prev) { (msg_snapshot)->msg.next = __list_prev
->msg.next; __list_prev->msg.next = msg_snapshot; } else
{ (msg_snapshot)->msg.next = __list_head->first; __list_head
->first = (msg_snapshot); } __list_prev = (msg_snapshot); }
while (0)
;
15679 inserted = 1;
15680 break;
15681 } else if (!descending && val <= 0) {
15682 AST_LIST_INSERT_BEFORE_CURRENT(msg_snapshot, msg)do { if (__list_prev) { (msg_snapshot)->msg.next = __list_prev
->msg.next; __list_prev->msg.next = msg_snapshot; } else
{ (msg_snapshot)->msg.next = __list_head->first; __list_head
->first = (msg_snapshot); } __list_prev = (msg_snapshot); }
while (0)
;
15683 inserted = 1;
15684 break;
15685 }
15686 }
15687 AST_LIST_TRAVERSE_SAFE_END};
15688 break;
15689 }
15690
15691 if (!inserted) {
15692 AST_LIST_INSERT_TAIL(&mailbox_snapshot->snapshots[snapshot_index], msg_snapshot, msg)do { if (!(&mailbox_snapshot->snapshots[snapshot_index
])->first) { (&mailbox_snapshot->snapshots[snapshot_index
])->first = (msg_snapshot); (&mailbox_snapshot->snapshots
[snapshot_index])->last = (msg_snapshot); } else { (&mailbox_snapshot
->snapshots[snapshot_index])->last->msg.next = (msg_snapshot
); (&mailbox_snapshot->snapshots[snapshot_index])->
last = (msg_snapshot); } } while (0)
;
15693 }
15694
15695 mailbox_snapshot->total_msg_num++;
15696
15697 /* cleanup configs and msg */
15698 ast_config_destroy(msg_cfg);
15699 DISPOSE(vms->curdir, vms->curmsg);
15700 }
15701
15702 return 0;
15703}
15704
15705static struct ast_vm_mailbox_snapshot *vm_mailbox_snapshot_create(const char *mailbox,
15706 const char *context,
15707 const char *folder,
15708 int descending,
15709 enum ast_vm_snapshot_sort_val sort_val,
15710 int combine_INBOX_and_OLD)
15711{
15712 struct ast_vm_mailbox_snapshot *mailbox_snapshot;
15713 struct vm_state vms;
15714 struct ast_vm_user *vmu = NULL((void*)0), vmus;
15715 int res;
15716 int i;
15717 int this_index_only = -1;
15718 int open = 0;
15719 int inbox_index = get_folder_by_name("INBOX");
15720 int old_index = get_folder_by_name("Old");
15721 int urgent_index = get_folder_by_name("Urgent");
15722
15723 if (ast_strlen_zero(mailbox)_ast_strlen_zero(mailbox, "app_voicemail.c", __PRETTY_FUNCTION__
, 15723)
) {
15724 ast_log(LOG_WARNING3, "app_voicemail.c", 15724, __PRETTY_FUNCTION__, "Cannot create a mailbox snapshot since no mailbox was specified\n");
15725 return NULL((void*)0);
15726 }
15727
15728 memset(&vmus, 0, sizeof(vmus));
15729
15730 if (!(ast_strlen_zero(folder)_ast_strlen_zero(folder, "app_voicemail.c", __PRETTY_FUNCTION__
, 15730)
)) {
15731 /* find the folder index */
15732 for (i = 0; i < ARRAY_LEN(mailbox_folders)(size_t) (sizeof(mailbox_folders) / sizeof(0[mailbox_folders]
))
; i++) {
15733 if (!strcasecmp(mailbox_folders[i], folder)) {
15734 this_index_only = i;
15735 break;
15736 }
15737 }
15738 if (this_index_only == -1) {
15739 /* Folder was specified and it did not match any folder in our list */
15740 return NULL((void*)0);
15741 }
15742 }
15743
15744 if (!(vmu = find_user(&vmus, context, mailbox))) {
15745 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 15745, __PRETTY_FUNCTION__, "Failed to create mailbox snapshot for unknown voicemail user %s@%s\n", mailbox, context);
15746 return NULL((void*)0);
15747 }
15748
15749 if (!(mailbox_snapshot = ast_calloc(1, sizeof(*mailbox_snapshot))_ast_calloc((1), (sizeof(*mailbox_snapshot)), "app_voicemail.c"
, 15749, __PRETTY_FUNCTION__)
)) {
15750 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 15750, __PRETTY_FUNCTION__, "Failed to allocate memory for mailbox snapshot\n");
15751 free_user(vmu);
15752 return NULL((void*)0);
15753 }
15754
15755 if (!(mailbox_snapshot->snapshots = ast_calloc(ARRAY_LEN(mailbox_folders), sizeof(*mailbox_snapshot->snapshots))_ast_calloc(((size_t) (sizeof(mailbox_folders) / sizeof(0[mailbox_folders
]))), (sizeof(*mailbox_snapshot->snapshots)), "app_voicemail.c"
, 15755, __PRETTY_FUNCTION__)
)) {
15756 ast_freefree(mailbox_snapshot);
15757 free_user(vmu);
15758 return NULL((void*)0);
15759 }
15760
15761 mailbox_snapshot->folders = ARRAY_LEN(mailbox_folders)(size_t) (sizeof(mailbox_folders) / sizeof(0[mailbox_folders]
))
;
15762
15763 for (i = 0; i < mailbox_snapshot->folders; i++) {
15764 int msg_folder_index = i;
15765
15766 /* We want this message in the snapshot if any of the following:
15767 * No folder was specified.
15768 * The specified folder matches the current folder.
15769 * The specified folder is INBOX AND we were asked to combine messages AND the current folder is either Old or Urgent.
15770 */
15771 if (!(this_index_only == -1 || this_index_only == i || (this_index_only == inbox_index && combine_INBOX_and_OLD && (i == old_index || i == urgent_index)))) {
15772 continue;
15773 }
15774
15775 /* Make sure that Old or Urgent messages are marked as being in INBOX. */
15776 if (combine_INBOX_and_OLD && (i == old_index || i == urgent_index)) {
15777 msg_folder_index = inbox_index;
15778 }
15779
15780 memset(&vms, 0, sizeof(vms));
15781 ast_copy_string(vms.username, mailbox, sizeof(vms.username));
15782 vms.lastmsg = -1;
15783 open = 0;
15784
15785 /* open the mailbox state */
15786 if ((res = open_mailbox(&vms, vmu, i)) < 0) {
15787 ast_log(LOG_WARNING3, "app_voicemail.c", 15787, __PRETTY_FUNCTION__, "Could not open mailbox %s\n", mailbox);
15788 goto snapshot_cleanup;
15789 }
15790 open = 1;
15791
15792 /* Iterate through each msg, storing off info */
15793 if (vms.lastmsg != -1) {
15794 if ((vm_msg_snapshot_create(vmu, &vms, mailbox_snapshot, msg_folder_index, i, descending, sort_val))) {
15795 ast_log(LOG_WARNING3, "app_voicemail.c", 15795, __PRETTY_FUNCTION__, "Failed to create msg snapshots for %s@%s\n", mailbox, context);
15796 goto snapshot_cleanup;
15797 }
15798 }
15799
15800 /* close mailbox */
15801 if ((res = close_mailbox(&vms, vmu) == ERROR_LOCK_PATH-100)) {
15802 goto snapshot_cleanup;
15803 }
15804 open = 0;
15805 }
15806
15807snapshot_cleanup:
15808 if (vmu && open) {
15809 close_mailbox(&vms, vmu);
15810 }
15811
15812#ifdef IMAP_STORAGE
15813 if (vmu) {
15814 vmstate_delete(&vms);
15815 }
15816#endif
15817
15818 free_user(vmu);
15819 return mailbox_snapshot;
15820}
15821
15822static struct ast_vm_mailbox_snapshot *vm_mailbox_snapshot_destroy(struct ast_vm_mailbox_snapshot *mailbox_snapshot)
15823{
15824 int i;
15825 struct ast_vm_msg_snapshot *msg_snapshot;
15826
15827 for (i = 0; i < mailbox_snapshot->folders; i++) {
15828 while ((msg_snapshot = AST_LIST_REMOVE_HEAD(&mailbox_snapshot->snapshots[i], msg)({ typeof((&mailbox_snapshot->snapshots[i])->first)
__cur = (&mailbox_snapshot->snapshots[i])->first; if
(__cur) { (&mailbox_snapshot->snapshots[i])->first
= __cur->msg.next; __cur->msg.next = ((void*)0); if ((
&mailbox_snapshot->snapshots[i])->last == __cur) (&
mailbox_snapshot->snapshots[i])->last = ((void*)0); } __cur
; })
)) {
15829 msg_snapshot = vm_msg_snapshot_destroy(msg_snapshot);
15830 }
15831 }
15832 ast_freefree(mailbox_snapshot->snapshots);
15833 ast_freefree(mailbox_snapshot);
15834 return NULL((void*)0);
15835}
15836
15837/*!
15838 * \brief common bounds checking and existence check for Voicemail API functions.
15839 *
15840 * \details
15841 * This is called by vm_msg_move, vm_msg_remove, and vm_msg_forward to
15842 * ensure that data passed in are valid. This ensures that given the
15843 * desired message IDs, they can be found.
15844 *
15845 * \param vms The voicemail state corresponding to an open mailbox
15846 * \param msg_ids An array of message identifiers
15847 * \param num_msgs The number of identifiers in msg_ids
15848 * \param msg_nums [out] The message indexes corresponding to the given
15849 * \param vmu
15850 * message IDs
15851 * \pre vms must have open_mailbox() called on it prior to this function.
15852 *
15853 * \retval -1 Failure
15854 * \retval 0 Success
15855 */
15856static int message_range_and_existence_check(struct vm_state *vms, const char *msg_ids [], size_t num_msgs, int *msg_nums, struct ast_vm_user *vmu)
15857{
15858 int i;
15859 int res = 0;
15860 for (i = 0; i < num_msgs; ++i) {
15861 const char *msg_id = msg_ids[i];
15862 int found = 0;
15863 for (vms->curmsg = 0; vms->curmsg <= vms->lastmsg; vms->curmsg++) {
15864 const char *other_msg_id;
15865 char filename[PATH_MAX4096];
15866 struct ast_config *msg_cfg;
15867 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
15868
15869 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
15870 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
15871 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
15872 msg_cfg = ast_config_load(filename, config_flags)ast_config_load2(filename, "app_voicemail", config_flags);
15873 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID(void *)-2) {
15874 DISPOSE(vms->curdir, vms->curmsg);
15875 res = -1;
15876 goto done;
15877 }
15878
15879 other_msg_id = ast_variable_retrieve(msg_cfg, "message", "msg_id");
15880
15881 if (!ast_strlen_zero(other_msg_id)_ast_strlen_zero(other_msg_id, "app_voicemail.c", __PRETTY_FUNCTION__
, 15881)
&& !strcmp(other_msg_id, msg_id)) {
15882 /* Message found. We can get out of this inner loop
15883 * and move on to the next message to find
15884 */
15885 found = 1;
15886 msg_nums[i] = vms->curmsg;
15887 ast_config_destroy(msg_cfg);
15888 DISPOSE(vms->curdir, vms->curmsg);
15889 break;
15890 }
15891 ast_config_destroy(msg_cfg);
15892 DISPOSE(vms->curdir, vms->curmsg);
15893 }
15894 if (!found) {
15895 /* If we can't find one of the message IDs requested, then OH NO! */
15896 res = -1;
15897 goto done;
15898 }
15899 }
15900
15901done:
15902 return res;
15903}
15904
15905static void notify_new_state(struct ast_vm_user *vmu)
15906{
15907 int new = 0, old = 0, urgent = 0;
15908 char ext_context[1024];
15909
15910 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
15911 run_externnotify(vmu->context, vmu->mailbox, NULL((void*)0));
15912 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
15913 queue_mwi_event(NULL((void*)0), ext_context, urgent, new, old);
15914}
15915
15916static int vm_msg_forward(const char *from_mailbox,
15917 const char *from_context,
15918 const char *from_folder,
15919 const char *to_mailbox,
15920 const char *to_context,
15921 const char *to_folder,
15922 size_t num_msgs,
15923 const char *msg_ids [],
15924 int delete_old)
15925{
15926 struct vm_state from_vms;
15927 struct ast_vm_user *vmu = NULL((void*)0), vmus;
15928 struct ast_vm_user *to_vmu = NULL((void*)0), to_vmus;
15929 struct ast_config *msg_cfg;
15930 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
15931 char filename[PATH_MAX4096];
15932 int from_folder_index;
15933 int open = 0;
15934 int res = 0;
15935 int i;
15936 int *msg_nums;
15937
15938 if (ast_strlen_zero(from_mailbox)_ast_strlen_zero(from_mailbox, "app_voicemail.c", __PRETTY_FUNCTION__
, 15938)
|| ast_strlen_zero(to_mailbox)_ast_strlen_zero(to_mailbox, "app_voicemail.c", __PRETTY_FUNCTION__
, 15938)
) {
15939 ast_log(LOG_WARNING3, "app_voicemail.c", 15939, __PRETTY_FUNCTION__, "Cannot forward message because either the from or to mailbox was not specified\n");
15940 return -1;
15941 }
15942
15943 if (!num_msgs) {
15944 ast_log(LOG_WARNING3, "app_voicemail.c", 15944, __PRETTY_FUNCTION__, "Invalid number of messages specified to forward: %zu\n", num_msgs);
15945 return -1;
15946 }
15947
15948 if (ast_strlen_zero(from_folder)_ast_strlen_zero(from_folder, "app_voicemail.c", __PRETTY_FUNCTION__
, 15948)
|| ast_strlen_zero(to_folder)_ast_strlen_zero(to_folder, "app_voicemail.c", __PRETTY_FUNCTION__
, 15948)
) {
15949 ast_log(LOG_WARNING3, "app_voicemail.c", 15949, __PRETTY_FUNCTION__, "Cannot forward message because the from_folder or to_folder was not specified\n");
15950 return -1;
15951 }
15952
15953 memset(&vmus, 0, sizeof(vmus));
15954 memset(&to_vmus, 0, sizeof(to_vmus));
15955 memset(&from_vms, 0, sizeof(from_vms));
15956
15957 from_folder_index = get_folder_by_name(from_folder);
15958 if (from_folder_index == -1) {
15959 return -1;
15960 }
15961
15962 if (get_folder_by_name(to_folder) == -1) {
15963 return -1;
15964 }
15965
15966 if (!(vmu = find_user(&vmus, from_context, from_mailbox))) {
15967 ast_log(LOG_WARNING3, "app_voicemail.c", 15967, __PRETTY_FUNCTION__, "Can't find voicemail user to forward from (%s@%s)\n", from_mailbox, from_context);
15968 return -1;
15969 }
15970
15971 if (!(to_vmu = find_user(&to_vmus, to_context, to_mailbox))) {
15972 ast_log(LOG_WARNING3, "app_voicemail.c", 15972, __PRETTY_FUNCTION__, "Can't find voicemail user to forward to (%s@%s)\n", to_mailbox, to_context);
15973 free_user(vmu);
15974 return -1;
15975 }
15976
15977 ast_copy_string(from_vms.username, from_mailbox, sizeof(from_vms.username));
15978 from_vms.lastmsg = -1;
15979 open = 0;
15980
15981 /* open the mailbox state */
15982 if ((res = open_mailbox(&from_vms, vmu, from_folder_index)) < 0) {
15983 ast_log(LOG_WARNING3, "app_voicemail.c", 15983, __PRETTY_FUNCTION__, "Could not open mailbox %s\n", from_mailbox);
15984 res = -1;
15985 goto vm_forward_cleanup;
15986 }
15987
15988 open = 1;
15989
15990 if ((from_vms.lastmsg + 1) < num_msgs) {
15991 ast_log(LOG_WARNING3, "app_voicemail.c", 15991, __PRETTY_FUNCTION__, "Folder %s has less than %zu messages\n", from_folder, num_msgs);
15992 res = -1;
15993 goto vm_forward_cleanup;
15994 }
15995
15996 msg_nums = ast_alloca(sizeof(int) * num_msgs)__builtin_alloca(sizeof(int) * num_msgs);
15997
15998 if ((res = message_range_and_existence_check(&from_vms, msg_ids, num_msgs, msg_nums, vmu) < 0)) {
15999 goto vm_forward_cleanup;
16000 }
16001
16002 /* Now we actually forward the messages */
16003 for (i = 0; i < num_msgs; i++) {
16004 int cur_msg = msg_nums[i];
16005 int duration = 0;
16006 const char *value;
16007
16008 make_file(from_vms.fn, sizeof(from_vms.fn), from_vms.curdir, cur_msg);
16009 snprintf(filename, sizeof(filename), "%s.txt", from_vms.fn);
16010 RETRIEVE(from_vms.curdir, cur_msg, vmu->mailbox, vmu->context);
16011 msg_cfg = ast_config_load(filename, config_flags)ast_config_load2(filename, "app_voicemail", config_flags);
16012 /* XXX This likely will not fail since we previously ensured that the
16013 * message we are looking for exists. However, there still could be some
16014 * circumstance where this fails, so atomicity is not guaranteed.
16015 */
16016 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID(void *)-2) {
16017 DISPOSE(from_vms.curdir, cur_msg);
16018 continue;
16019 }
16020 if ((value = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
16021 duration = atoi(value);
16022 }
16023
16024 copy_message(NULL((void*)0), vmu, from_folder_index, cur_msg, duration, to_vmu, vmfmts, from_vms.curdir, "", to_folder);
16025
16026 if (delete_old) {
16027 from_vms.deleted[cur_msg] = 1;
16028 }
16029 ast_config_destroy(msg_cfg);
16030 DISPOSE(from_vms.curdir, cur_msg);
16031 }
16032
16033 /* close mailbox */
16034 if ((res = close_mailbox(&from_vms, vmu) == ERROR_LOCK_PATH-100)) {
16035 res = -1;
16036 goto vm_forward_cleanup;
16037 }
16038 open = 0;
16039
16040vm_forward_cleanup:
16041 if (vmu && open) {
16042 close_mailbox(&from_vms, vmu);
16043 }
16044#ifdef IMAP_STORAGE
16045 if (vmu) {
16046 vmstate_delete(&from_vms);
16047 }
16048#endif
16049
16050 if (!res) {
16051 notify_new_state(to_vmu);
16052 }
16053
16054 free_user(vmu);
16055 free_user(to_vmu);
16056 return res;
16057}
16058
16059static int vm_msg_move(const char *mailbox,
16060 const char *context,
16061 size_t num_msgs,
16062 const char *oldfolder,
16063 const char *old_msg_ids [],
16064 const char *newfolder)
16065{
16066 struct vm_state vms;
16067 struct ast_vm_user *vmu = NULL((void*)0), vmus;
16068 int old_folder_index;
16069 int new_folder_index;
16070 int open = 0;
16071 int res = 0;
16072 int i;
16073 int *old_msg_nums;
16074
16075 if (ast_strlen_zero(mailbox)_ast_strlen_zero(mailbox, "app_voicemail.c", __PRETTY_FUNCTION__
, 16075)
) {
16076 ast_log(LOG_WARNING3, "app_voicemail.c", 16076, __PRETTY_FUNCTION__, "Cannot move message because no mailbox was specified\n");
16077 return -1;
16078 }
16079
16080 if (!num_msgs) {
16081 ast_log(LOG_WARNING3, "app_voicemail.c", 16081, __PRETTY_FUNCTION__, "Invalid number of messages specified to move: %zu\n", num_msgs);
16082 return -1;
16083 }
16084
16085 if (ast_strlen_zero(oldfolder)_ast_strlen_zero(oldfolder, "app_voicemail.c", __PRETTY_FUNCTION__
, 16085)
|| ast_strlen_zero(newfolder)_ast_strlen_zero(newfolder, "app_voicemail.c", __PRETTY_FUNCTION__
, 16085)
) {
16086 ast_log(LOG_WARNING3, "app_voicemail.c", 16086, __PRETTY_FUNCTION__, "Cannot move message because either oldfolder or newfolder was not specified\n");
16087 return -1;
16088 }
16089
16090 old_folder_index = get_folder_by_name(oldfolder);
16091 new_folder_index = get_folder_by_name(newfolder);
16092
16093 memset(&vmus, 0, sizeof(vmus));
16094 memset(&vms, 0, sizeof(vms));
16095
16096 if (old_folder_index == -1 || new_folder_index == -1) {
16097 return -1;
16098 }
16099
16100 if (!(vmu = find_user(&vmus, context, mailbox))) {
16101 return -1;
16102 }
16103
16104 ast_copy_string(vms.username, mailbox, sizeof(vms.username));
16105 vms.lastmsg = -1;
16106 open = 0;
16107
16108 /* open the mailbox state */
16109 if ((res = open_mailbox(&vms, vmu, old_folder_index)) < 0) {
16110 ast_log(LOG_WARNING3, "app_voicemail.c", 16110, __PRETTY_FUNCTION__, "Could not open mailbox %s\n", mailbox);
16111 res = -1;
16112 goto vm_move_cleanup;
16113 }
16114
16115 open = 1;
16116
16117 if ((vms.lastmsg + 1) < num_msgs) {
16118 ast_log(LOG_WARNING3, "app_voicemail.c", 16118, __PRETTY_FUNCTION__, "Folder %s has less than %zu messages\n", oldfolder, num_msgs);
16119 res = -1;
16120 goto vm_move_cleanup;
16121 }
16122
16123 old_msg_nums = ast_alloca(sizeof(int) * num_msgs)__builtin_alloca(sizeof(int) * num_msgs);
16124
16125 if ((res = message_range_and_existence_check(&vms, old_msg_ids, num_msgs, old_msg_nums, vmu)) < 0) {
16126 goto vm_move_cleanup;
16127 }
16128
16129 /* Now actually move the message */
16130 for (i = 0; i < num_msgs; ++i) {
16131 if (save_to_folder(vmu, &vms, old_msg_nums[i], new_folder_index, NULL((void*)0), 0)) {
16132 res = -1;
16133 goto vm_move_cleanup;
16134 }
16135 vms.deleted[old_msg_nums[i]] = 1;
16136 }
16137
16138 /* close mailbox */
16139 if ((res = close_mailbox(&vms, vmu) == ERROR_LOCK_PATH-100)) {
16140 res = -1;
16141 goto vm_move_cleanup;
16142 }
16143 open = 0;
16144
16145vm_move_cleanup:
16146 if (vmu && open) {
16147 close_mailbox(&vms, vmu);
16148 }
16149#ifdef IMAP_STORAGE
16150 if (vmu) {
16151 vmstate_delete(&vms);
16152 }
16153#endif
16154
16155 if (!res) {
16156 notify_new_state(vmu);
16157 }
16158
16159 free_user(vmu);
16160 return res;
16161}
16162
16163static int vm_msg_remove(const char *mailbox,
16164 const char *context,
16165 size_t num_msgs,
16166 const char *folder,
16167 const char *msgs[])
16168{
16169 struct vm_state vms;
16170 struct ast_vm_user *vmu = NULL((void*)0), vmus;
16171 int folder_index;
16172 int open = 0;
16173 int res = 0;
16174 int i;
16175 int *msg_nums;
16176
16177 if (ast_strlen_zero(mailbox)_ast_strlen_zero(mailbox, "app_voicemail.c", __PRETTY_FUNCTION__
, 16177)
) {
16178 ast_log(LOG_WARNING3, "app_voicemail.c", 16178, __PRETTY_FUNCTION__, "Cannot remove message because no mailbox was specified\n");
16179 return -1;
16180 }
16181
16182 if (!num_msgs) {
16183 ast_log(LOG_WARNING3, "app_voicemail.c", 16183, __PRETTY_FUNCTION__, "Invalid number of messages specified to remove: %zu\n", num_msgs);
16184 return -1;
16185 }
16186
16187 if (ast_strlen_zero(folder)_ast_strlen_zero(folder, "app_voicemail.c", __PRETTY_FUNCTION__
, 16187)
) {
16188 ast_log(LOG_WARNING3, "app_voicemail.c", 16188, __PRETTY_FUNCTION__, "Cannot remove message because no folder was specified\n");
16189 return -1;
16190 }
16191
16192 memset(&vmus, 0, sizeof(vmus));
16193 memset(&vms, 0, sizeof(vms));
16194
16195 folder_index = get_folder_by_name(folder);
16196 if (folder_index == -1) {
16197 ast_log(LOG_WARNING3, "app_voicemail.c", 16197, __PRETTY_FUNCTION__, "Could not remove msgs from unknown folder %s\n", folder);
16198 return -1;
16199 }
16200
16201 if (!(vmu = find_user(&vmus, context, mailbox))) {
16202 ast_log(LOG_WARNING3, "app_voicemail.c", 16202, __PRETTY_FUNCTION__, "Can't find voicemail user to remove msg from (%s@%s)\n", mailbox, context);
16203 return -1;
16204 }
16205
16206 ast_copy_string(vms.username, mailbox, sizeof(vms.username));
16207 vms.lastmsg = -1;
16208 open = 0;
16209
16210 /* open the mailbox state */
16211 if ((res = open_mailbox(&vms, vmu, folder_index)) < 0) {
16212 ast_log(LOG_WARNING3, "app_voicemail.c", 16212, __PRETTY_FUNCTION__, "Could not open mailbox %s\n", mailbox);
16213 res = -1;
16214 goto vm_remove_cleanup;
16215 }
16216
16217 open = 1;
16218
16219 if ((vms.lastmsg + 1) < num_msgs) {
16220 ast_log(LOG_WARNING3, "app_voicemail.c", 16220, __PRETTY_FUNCTION__, "Folder %s has less than %zu messages\n", folder, num_msgs);
16221 res = -1;
16222 goto vm_remove_cleanup;
16223 }
16224
16225 msg_nums = ast_alloca(sizeof(int) * num_msgs)__builtin_alloca(sizeof(int) * num_msgs);
16226
16227 if ((res = message_range_and_existence_check(&vms, msgs, num_msgs, msg_nums, vmu)) < 0) {
16228 goto vm_remove_cleanup;
16229 }
16230
16231 for (i = 0; i < num_msgs; i++) {
16232 vms.deleted[msg_nums[i]] = 1;
16233 }
16234
16235 /* close mailbox */
16236 if ((res = close_mailbox(&vms, vmu) == ERROR_LOCK_PATH-100)) {
16237 res = -1;
16238 ast_log(AST_LOG_ERROR4, "app_voicemail.c", 16238, __PRETTY_FUNCTION__, "Failed to close mailbox folder %s while removing msgs\n", folder);
16239 goto vm_remove_cleanup;
16240 }
16241 open = 0;
16242
16243vm_remove_cleanup:
16244 if (vmu && open) {
16245 close_mailbox(&vms, vmu);
16246 }
16247#ifdef IMAP_STORAGE
16248 if (vmu) {
16249 vmstate_delete(&vms);
16250 }
16251#endif
16252
16253 if (!res) {
16254 notify_new_state(vmu);
16255 }
16256
16257 free_user(vmu);
16258 return res;
16259}
16260
16261static int vm_msg_play(struct ast_channel *chan,
16262 const char *mailbox,
16263 const char *context,
16264 const char *folder,
16265 const char *msg_id,
16266 ast_vm_msg_play_cb cb)
16267{
16268 struct vm_state vms;
16269 struct ast_vm_user *vmu = NULL((void*)0), vmus;
16270 int res = 0;
16271 int open = 0;
16272 int i;
16273 char filename[PATH_MAX4096];
16274 struct ast_config *msg_cfg;
16275 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
16276 int duration = 0;
16277 const char *value;
16278
16279 if (ast_strlen_zero(mailbox)_ast_strlen_zero(mailbox, "app_voicemail.c", __PRETTY_FUNCTION__
, 16279)
) {
16280 ast_log(LOG_WARNING3, "app_voicemail.c", 16280, __PRETTY_FUNCTION__, "Cannot play message because no mailbox was specified\n");
16281 return -1;
16282 }
16283
16284 if (ast_strlen_zero(folder)_ast_strlen_zero(folder, "app_voicemail.c", __PRETTY_FUNCTION__
, 16284)
) {
16285 ast_log(LOG_WARNING3, "app_voicemail.c", 16285, __PRETTY_FUNCTION__, "Cannot play message because no folder was specified\n");
16286 return -1;
16287 }
16288
16289 if (ast_strlen_zero(msg_id)_ast_strlen_zero(msg_id, "app_voicemail.c", __PRETTY_FUNCTION__
, 16289)
) {
16290 ast_log(LOG_WARNING3, "app_voicemail.c", 16290, __PRETTY_FUNCTION__, "Cannot play message because no message number was specified\n");
16291 return -1;
16292 }
16293
16294 memset(&vmus, 0, sizeof(vmus));
16295 memset(&vms, 0, sizeof(vms));
16296
16297 if (ast_strlen_zero(context)_ast_strlen_zero(context, "app_voicemail.c", __PRETTY_FUNCTION__
, 16297)
) {
16298 context = "default";
16299 }
16300
16301 if (!(vmu = find_user(&vmus, context, mailbox))) {
16302 return -1;
16303 }
16304
16305 i = get_folder_by_name(folder);
16306 ast_copy_string(vms.username, mailbox, sizeof(vms.username));
16307 vms.lastmsg = -1;
16308 if ((res = open_mailbox(&vms, vmu, i)) < 0) {
16309 ast_log(LOG_WARNING3, "app_voicemail.c", 16309, __PRETTY_FUNCTION__, "Could not open mailbox %s\n", mailbox);
16310 goto play2_msg_cleanup;
16311 }
16312 open = 1;
16313
16314 if (message_range_and_existence_check(&vms, &msg_id, 1, &vms.curmsg, vmu)) {
16315 res = -1;
16316 goto play2_msg_cleanup;
16317 }
16318
16319 /* Find the msg */
16320 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
16321 snprintf(filename, sizeof(filename), "%s.txt", vms.fn);
16322 RETRIEVE(vms.curdir, vms.curmsg, vmu->mailbox, vmu->context);
16323
16324 msg_cfg = ast_config_load(filename, config_flags)ast_config_load2(filename, "app_voicemail", config_flags);
16325 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID(void *)-2) {
16326 DISPOSE(vms.curdir, vms.curmsg);
16327 res = -1;
16328 goto play2_msg_cleanup;
16329 }
16330 if ((value = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
16331 duration = atoi(value);
16332 }
16333 ast_config_destroy(msg_cfg);
16334
16335#ifdef IMAP_STORAGE
16336 /*IMAP storage stores any prepended message from a forward
16337 * as a separate file from the rest of the message
16338 */
16339 if (!ast_strlen_zero(vms.introfn)_ast_strlen_zero(vms.introfn, "app_voicemail.c", __PRETTY_FUNCTION__
, 16339)
&& ast_fileexists(vms.introfn, NULL((void*)0), NULL((void*)0)) > 0) {
16340 wait_file(chan, &vms, vms.introfn);
16341 }
16342#endif
16343 if (cb) {
16344 cb(chan, vms.fn, duration);
16345 } else if ((wait_file(chan, &vms, vms.fn)) < 0) {
16346 ast_log(AST_LOG_WARNING3, "app_voicemail.c", 16346, __PRETTY_FUNCTION__, "Playback of message %s failed\n", vms.fn);
16347 } else {
16348 res = 0;
16349 }
16350
16351 vms.heard[vms.curmsg] = 1;
16352
16353 /* cleanup configs and msg */
16354 DISPOSE(vms.curdir, vms.curmsg);
16355
16356play2_msg_cleanup:
16357 if (vmu && open) {
16358 close_mailbox(&vms, vmu);
16359 }
16360
16361#ifdef IMAP_STORAGE
16362 if (vmu) {
16363 vmstate_delete(&vms);
16364 }
16365#endif
16366
16367 if (!res) {
16368 notify_new_state(vmu);
16369 }
16370
16371 free_user(vmu);
16372 return res;
16373}
16374
16375/* This is a workaround so that menuselect displays a proper description
16376 * AST_MODULE_INFO(, , "Comedian Mail (Voicemail System)"
16377 */
16378
16379AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,static struct ast_module_info __mod_info = { .name = "app_voicemail"
, .flags = AST_MODFLAG_DEFAULT, .description = "Comedian Mail (Voicemail System)"
, .key = "This paragraph is copyright (c) 2006 by Digium, Inc. In order for your module to load, it must return this key via a function called \"key\". Any code which includes this paragraph must be licensed under the GNU General Public License version 2 or later (at your option). In addition to Digium's general reservations of rights, Digium expressly reserves the right to allow other parties to license this paragraph under different terms. Any use of Digium, Inc. trademarks or logos (including \"Asterisk\" or \"Digium\") without express written permission of Digium, Inc. is prohibited.\n"
, .buildopt_sum = "f65def77ea85e1c34b1f93e36ad54ae6", .support_level
= AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module
, .reload = reload, .nonoptreq = "res_adsi,res_smdi", }; static
void __attribute__((constructor)) __reg_module(void) { ast_module_register
(&__mod_info); } static void __attribute__((destructor)) __unreg_module
(void) { ast_module_unregister(&__mod_info); } struct ast_module
*__internal_app_voicemail_self(void) { return __mod_info.self
; } static const struct ast_module_info *ast_module_info = &
__mod_info
16380 .support_level = AST_MODULE_SUPPORT_CORE,static struct ast_module_info __mod_info = { .name = "app_voicemail"
, .flags = AST_MODFLAG_DEFAULT, .description = "Comedian Mail (Voicemail System)"
, .key = "This paragraph is copyright (c) 2006 by Digium, Inc. In order for your module to load, it must return this key via a function called \"key\". Any code which includes this paragraph must be licensed under the GNU General Public License version 2 or later (at your option). In addition to Digium's general reservations of rights, Digium expressly reserves the right to allow other parties to license this paragraph under different terms. Any use of Digium, Inc. trademarks or logos (including \"Asterisk\" or \"Digium\") without express written permission of Digium, Inc. is prohibited.\n"
, .buildopt_sum = "f65def77ea85e1c34b1f93e36ad54ae6", .support_level
= AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module
, .reload = reload, .nonoptreq = "res_adsi,res_smdi", }; static
void __attribute__((constructor)) __reg_module(void) { ast_module_register
(&__mod_info); } static void __attribute__((destructor)) __unreg_module
(void) { ast_module_unregister(&__mod_info); } struct ast_module
*__internal_app_voicemail_self(void) { return __mod_info.self
; } static const struct ast_module_info *ast_module_info = &
__mod_info
16381 .load = load_module,static struct ast_module_info __mod_info = { .name = "app_voicemail"
, .flags = AST_MODFLAG_DEFAULT, .description = "Comedian Mail (Voicemail System)"
, .key = "This paragraph is copyright (c) 2006 by Digium, Inc. In order for your module to load, it must return this key via a function called \"key\". Any code which includes this paragraph must be licensed under the GNU General Public License version 2 or later (at your option). In addition to Digium's general reservations of rights, Digium expressly reserves the right to allow other parties to license this paragraph under different terms. Any use of Digium, Inc. trademarks or logos (including \"Asterisk\" or \"Digium\") without express written permission of Digium, Inc. is prohibited.\n"
, .buildopt_sum = "f65def77ea85e1c34b1f93e36ad54ae6", .support_level
= AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module
, .reload = reload, .nonoptreq = "res_adsi,res_smdi", }; static
void __attribute__((constructor)) __reg_module(void) { ast_module_register
(&__mod_info); } static void __attribute__((destructor)) __unreg_module
(void) { ast_module_unregister(&__mod_info); } struct ast_module
*__internal_app_voicemail_self(void) { return __mod_info.self
; } static const struct ast_module_info *ast_module_info = &
__mod_info
16382 .unload = unload_module,static struct ast_module_info __mod_info = { .name = "app_voicemail"
, .flags = AST_MODFLAG_DEFAULT, .description = "Comedian Mail (Voicemail System)"
, .key = "This paragraph is copyright (c) 2006 by Digium, Inc. In order for your module to load, it must return this key via a function called \"key\". Any code which includes this paragraph must be licensed under the GNU General Public License version 2 or later (at your option). In addition to Digium's general reservations of rights, Digium expressly reserves the right to allow other parties to license this paragraph under different terms. Any use of Digium, Inc. trademarks or logos (including \"Asterisk\" or \"Digium\") without express written permission of Digium, Inc. is prohibited.\n"
, .buildopt_sum = "f65def77ea85e1c34b1f93e36ad54ae6", .support_level
= AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module
, .reload = reload, .nonoptreq = "res_adsi,res_smdi", }; static
void __attribute__((constructor)) __reg_module(void) { ast_module_register
(&__mod_info); } static void __attribute__((destructor)) __unreg_module
(void) { ast_module_unregister(&__mod_info); } struct ast_module
*__internal_app_voicemail_self(void) { return __mod_info.self
; } static const struct ast_module_info *ast_module_info = &
__mod_info
16383 .reload = reload,static struct ast_module_info __mod_info = { .name = "app_voicemail"
, .flags = AST_MODFLAG_DEFAULT, .description = "Comedian Mail (Voicemail System)"
, .key = "This paragraph is copyright (c) 2006 by Digium, Inc. In order for your module to load, it must return this key via a function called \"key\". Any code which includes this paragraph must be licensed under the GNU General Public License version 2 or later (at your option). In addition to Digium's general reservations of rights, Digium expressly reserves the right to allow other parties to license this paragraph under different terms. Any use of Digium, Inc. trademarks or logos (including \"Asterisk\" or \"Digium\") without express written permission of Digium, Inc. is prohibited.\n"
, .buildopt_sum = "f65def77ea85e1c34b1f93e36ad54ae6", .support_level
= AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module
, .reload = reload, .nonoptreq = "res_adsi,res_smdi", }; static
void __attribute__((constructor)) __reg_module(void) { ast_module_register
(&__mod_info); } static void __attribute__((destructor)) __unreg_module
(void) { ast_module_unregister(&__mod_info); } struct ast_module
*__internal_app_voicemail_self(void) { return __mod_info.self
; } static const struct ast_module_info *ast_module_info = &
__mod_info
16384 .nonoptreq = "res_adsi,res_smdi",static struct ast_module_info __mod_info = { .name = "app_voicemail"
, .flags = AST_MODFLAG_DEFAULT, .description = "Comedian Mail (Voicemail System)"
, .key = "This paragraph is copyright (c) 2006 by Digium, Inc. In order for your module to load, it must return this key via a function called \"key\". Any code which includes this paragraph must be licensed under the GNU General Public License version 2 or later (at your option). In addition to Digium's general reservations of rights, Digium expressly reserves the right to allow other parties to license this paragraph under different terms. Any use of Digium, Inc. trademarks or logos (including \"Asterisk\" or \"Digium\") without express written permission of Digium, Inc. is prohibited.\n"
, .buildopt_sum = "f65def77ea85e1c34b1f93e36ad54ae6", .support_level
= AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module
, .reload = reload, .nonoptreq = "res_adsi,res_smdi", }; static
void __attribute__((constructor)) __reg_module(void) { ast_module_register
(&__mod_info); } static void __attribute__((destructor)) __unreg_module
(void) { ast_module_unregister(&__mod_info); } struct ast_module
*__internal_app_voicemail_self(void) { return __mod_info.self
; } static const struct ast_module_info *ast_module_info = &
__mod_info
16385)static struct ast_module_info __mod_info = { .name = "app_voicemail"
, .flags = AST_MODFLAG_DEFAULT, .description = "Comedian Mail (Voicemail System)"
, .key = "This paragraph is copyright (c) 2006 by Digium, Inc. In order for your module to load, it must return this key via a function called \"key\". Any code which includes this paragraph must be licensed under the GNU General Public License version 2 or later (at your option). In addition to Digium's general reservations of rights, Digium expressly reserves the right to allow other parties to license this paragraph under different terms. Any use of Digium, Inc. trademarks or logos (including \"Asterisk\" or \"Digium\") without express written permission of Digium, Inc. is prohibited.\n"
, .buildopt_sum = "f65def77ea85e1c34b1f93e36ad54ae6", .support_level
= AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module
, .reload = reload, .nonoptreq = "res_adsi,res_smdi", }; static
void __attribute__((constructor)) __reg_module(void) { ast_module_register
(&__mod_info); } static void __attribute__((destructor)) __unreg_module
(void) { ast_module_unregister(&__mod_info); } struct ast_module
*__internal_app_voicemail_self(void) { return __mod_info.self
; } static const struct ast_module_info *ast_module_info = &
__mod_info
;