You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
286 lines
9.1 KiB
286 lines
9.1 KiB
From: Sipwise Development Team <support@sipwise.com>
|
|
Date: Mon, 4 Nov 2024 15:37:29 +0100
|
|
Subject: sipwise_vm_add_pcre_support
|
|
|
|
---
|
|
Makefile | 2 +-
|
|
apps/app_voicemail.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
2 files changed, 169 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/Makefile b/Makefile
|
|
index 67ec08d..ad0c960 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -15,7 +15,7 @@ CC?=gcc
|
|
OPTIMIZE=-O2
|
|
DEBUG=-g
|
|
|
|
-LIBS+=
|
|
+LIBS+=-lpcre
|
|
CFLAGS+=-pipe -fPIC
|
|
CFLAGS+=-Wall -Wextra -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations
|
|
CFLAGS+=-D_REENTRANT -D_GNU_SOURCE -DODBC_STORAGE
|
|
diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c
|
|
index 8769654..692e796 100644
|
|
--- a/apps/app_voicemail.c
|
|
+++ b/apps/app_voicemail.c
|
|
@@ -50,6 +50,7 @@
|
|
<use type="module">res_adsi</use>
|
|
<use type="module">res_smdi</use>
|
|
<defaultenabled>yes</defaultenabled>
|
|
+ <depend>pcre</depend>
|
|
<support_level>core</support_level>
|
|
***/
|
|
|
|
@@ -144,6 +145,9 @@
|
|
#include "asterisk/threadstorage.h"
|
|
#endif
|
|
|
|
+#include <ctype.h>
|
|
+#include <pcre.h>
|
|
+
|
|
/*** DOCUMENTATION
|
|
<application name="VoiceMail" language="en_US">
|
|
<synopsis>
|
|
@@ -1024,6 +1028,8 @@ static int maxlogins = 3;
|
|
static int minpassword = MINPASSWORD;
|
|
static int passwordlocation;
|
|
static char aliasescontext[MAX_VM_CONTEXT_LEN];
|
|
+static char sw_normalize_user_match[256];
|
|
+static char sw_normalize_user_replace[256];
|
|
|
|
/*! Poll mailboxes for changes since there is something external to
|
|
* app_voicemail that may change them. */
|
|
@@ -1280,6 +1286,114 @@ static int inprocess_count(const char *context, const char *mailbox, int delta)
|
|
static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
|
|
#endif
|
|
|
|
+/* sipwise pcre helper functions taken from contrib of pcre:
|
|
+
|
|
+ Written by: Bert Driehuis <driehuis@playbeing.org>
|
|
+ Copyright (c) 2000 Bert Driehuis
|
|
+
|
|
+ Permission is granted to anyone to use this software for any purpose on any
|
|
+ computer system, and to redistribute it freely, subject to the following
|
|
+ restrictions:
|
|
+
|
|
+ 1. This software is distributed in the hope that it will be useful,
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
+
|
|
+ 2. The origin of this software must not be misrepresented, either by
|
|
+ explicit claim or by omission.
|
|
+
|
|
+ 3. Altered versions must be plainly marked as such, and must not be
|
|
+ misrepresented as being the original software.
|
|
+
|
|
+ 4. If PCRE is embedded in any software that is released under the GNU
|
|
+ General Purpose Licence (GPL), then the terms of that licence shall
|
|
+ supersede any condition above with which it is incompatible.
|
|
+*/
|
|
+#define MAXCAPTURE 50
|
|
+
|
|
+static int findreplen(const char *rep, int nmat, const int *replen)
|
|
+{
|
|
+ int len = 0;
|
|
+ int val;
|
|
+ char *cp = (char *)rep;
|
|
+ while(*cp) {
|
|
+ if (*cp == '$' && isdigit(cp[1])) {
|
|
+ val = strtoul(&cp[1], &cp, 10);
|
|
+ if (val && val <= nmat + 1)
|
|
+ len += replen[val -1];
|
|
+ else
|
|
+ fprintf(stderr, "repl %d out of range\n", val);
|
|
+ } else {
|
|
+ cp++;
|
|
+ len++;
|
|
+ }
|
|
+ }
|
|
+ return len;
|
|
+}
|
|
+
|
|
+static void doreplace(char *out, const char *rep,
|
|
+ int nmat, int *replen, const char **repstr)
|
|
+{
|
|
+ int val;
|
|
+ char *cp = (char *)rep;
|
|
+ while(*cp) {
|
|
+ if (*cp == '$' && isdigit(cp[1])) {
|
|
+ val = strtoul(&cp[1], &cp, 10);
|
|
+ if (val && val <= nmat + 1) {
|
|
+ strncpy(out, repstr[val - 1], replen[val - 1]);
|
|
+ out += replen[val -1];
|
|
+ }
|
|
+ } else {
|
|
+ *out++ = *cp++;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static char *edit(const char *str, int len, const char *rep,
|
|
+ int nmat, const int *ovec)
|
|
+{
|
|
+ int i, slen, rlen;
|
|
+ const int *mvec = ovec;
|
|
+ char *res, *cp;
|
|
+ int replen[MAXCAPTURE];
|
|
+ const char *repstr[MAXCAPTURE];
|
|
+ nmat--;
|
|
+ ovec += 2;
|
|
+ for (i = 0; i < nmat; i++) {
|
|
+ replen[i] = ovec[i * 2 + 1] - ovec[i * 2];
|
|
+ repstr[i] = &str[ovec[i * 2]];
|
|
+ }
|
|
+ slen = len;
|
|
+ len -= mvec[1] - mvec[0];
|
|
+ len += rlen = findreplen(rep, nmat, replen);
|
|
+ cp = res = pcre_malloc(len + 1);
|
|
+ if (mvec[0] > 0) {
|
|
+ strncpy(cp, str, mvec[0]);
|
|
+ cp += mvec[0];
|
|
+ }
|
|
+ doreplace(cp, rep, nmat, replen, repstr);
|
|
+ cp += rlen;
|
|
+ if (mvec[1] < slen)
|
|
+ strcpy(cp, &str[mvec[1]]);
|
|
+ res[len] = 0;
|
|
+ return res;
|
|
+}
|
|
+
|
|
+static char *pcre_subst(const pcre *ppat, const pcre_extra *extra,
|
|
+ const char *str, int len,
|
|
+ int offset, int options, const char *rep)
|
|
+{
|
|
+ int nmat;
|
|
+ int ovec[MAXCAPTURE * 3];
|
|
+ nmat = pcre_exec(ppat, extra, str, len, offset, options,
|
|
+ ovec, sizeof(ovec));
|
|
+ if (nmat <= 0)
|
|
+ return NULL;
|
|
+ return(edit(str, len, rep, nmat, ovec));
|
|
+}
|
|
+
|
|
+/* end of pcre helper functions */
|
|
+
|
|
/*!
|
|
* \brief Strips control and non 7-bit clean characters from input string.
|
|
*
|
|
@@ -8011,6 +8125,8 @@ static int get_folder2(struct ast_channel *chan, char *fn, int start)
|
|
* This is invoked from forward_message() when performing a forward operation (option 8 from main menu).
|
|
* \return zero on success, -1 on error.
|
|
*/
|
|
+
|
|
+#if 0
|
|
static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts,
|
|
char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
|
|
{
|
|
@@ -8172,6 +8288,7 @@ static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu,
|
|
cmd = 0;
|
|
return cmd;
|
|
}
|
|
+#endif
|
|
|
|
static void queue_mwi_event(const char *channel_id, const char *box, int urgent, int new, int old)
|
|
{
|
|
@@ -8332,6 +8449,8 @@ static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu,
|
|
*
|
|
* \return zero on success, -1 on error.
|
|
*/
|
|
+
|
|
+#if 0
|
|
static int forward_message(struct ast_channel *chan, char *context, struct vm_state *vms, struct ast_vm_user *sender, char *fmt, int is_new_message, signed char record_gain, int urgent)
|
|
{
|
|
#ifdef IMAP_STORAGE
|
|
@@ -8671,6 +8790,7 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st
|
|
}
|
|
return res ? res : cmd;
|
|
}
|
|
+#endif
|
|
|
|
static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
|
|
{
|
|
@@ -11421,6 +11541,11 @@ static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_
|
|
int useadsi = 0, valid = 0, logretries = 0;
|
|
char password[AST_MAX_EXTENSION], *passptr = NULL;
|
|
struct ast_vm_user vmus, *vmu = NULL;
|
|
+ const char *err;
|
|
+ int erroffset;
|
|
+ pcre_extra *extra = NULL;
|
|
+ pcre *ppat = NULL;
|
|
+ char *normalized_mailbox;
|
|
|
|
/* If ADSI is supported, setup login screen */
|
|
adsi_begin(chan, &useadsi);
|
|
@@ -11431,6 +11556,22 @@ static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_
|
|
return -1;
|
|
}
|
|
|
|
+ if(sw_normalize_user_match[0] != '\0' && sw_normalize_user_replace[0] != '\0') {
|
|
+ // TODO: could be done once on start
|
|
+ ppat = pcre_compile(sw_normalize_user_match, 0, &err, &erroffset, NULL);
|
|
+ if(ppat == NULL) {
|
|
+ ast_log(LOG_WARNING, "Couldn't compile user match regex '%s': %s at offset %d\n",
|
|
+ sw_normalize_user_match, err, erroffset);
|
|
+ return -1;
|
|
+ }
|
|
+ extra = pcre_study(ppat, 0, &err);
|
|
+ if(err) {
|
|
+ ast_log(LOG_WARNING, "Couldn't study regex '%s': %s\n",
|
|
+ sw_normalize_user_match, err);
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
/* Authenticate them and get their mailbox/password */
|
|
|
|
while (!valid && (logretries < max_logins)) {
|
|
@@ -11460,6 +11601,18 @@ static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_
|
|
if (useadsi)
|
|
adsi_password(chan);
|
|
|
|
+ if(ppat && extra) {
|
|
+ ast_log(LOG_NOTICE, "Trying to rewrite user input '%s' using s/%s/%s/\n",
|
|
+ mailbox, sw_normalize_user_match, sw_normalize_user_replace);
|
|
+ normalized_mailbox = pcre_subst(ppat, extra, mailbox, strlen(mailbox), 0, 0, sw_normalize_user_replace);
|
|
+ if(normalized_mailbox) {
|
|
+ ast_log(LOG_NOTICE, "Rewrote mailbox user input '%s' to %s\n",
|
|
+ mailbox, normalized_mailbox);
|
|
+ ast_copy_string(mailbox, normalized_mailbox, mailbox_size);
|
|
+ free(normalized_mailbox);
|
|
+ }
|
|
+ }
|
|
+
|
|
if (!ast_strlen_zero(prefix)) {
|
|
char fullusername[80];
|
|
|
|
@@ -14057,6 +14210,8 @@ static int actual_load_config(int reload, struct ast_config *cfg, struct ast_con
|
|
char secretfn[PATH_MAX] = "";
|
|
long tps_queue_low;
|
|
long tps_queue_high;
|
|
+ const char *ast_sw_normalize_user_match = NULL;
|
|
+ const char *ast_sw_normalize_user_replace = NULL;
|
|
|
|
#ifdef IMAP_STORAGE
|
|
ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
|
|
@@ -14121,6 +14276,19 @@ static int actual_load_config(int reload, struct ast_config *cfg, struct ast_con
|
|
ast_copy_string(odbc_table, val, sizeof(odbc_table));
|
|
}
|
|
#endif
|
|
+
|
|
+ /* sipwise sw_normalize_user_match/replace */
|
|
+ if ((ast_sw_normalize_user_match = ast_variable_retrieve(cfg, "general", "sw_normalize_user_match"))) {
|
|
+ ast_copy_string(sw_normalize_user_match, ast_sw_normalize_user_match, sizeof(sw_normalize_user_match));
|
|
+ } else {
|
|
+ sw_normalize_user_match[0] = '\0';
|
|
+ }
|
|
+ if ((ast_sw_normalize_user_replace = ast_variable_retrieve(cfg, "general", "sw_normalize_user_replace"))) {
|
|
+ ast_copy_string(sw_normalize_user_replace, ast_sw_normalize_user_replace, sizeof(sw_normalize_user_replace));
|
|
+ } else {
|
|
+ sw_normalize_user_replace[0] = '\0';
|
|
+ }
|
|
+
|
|
/* Mail command */
|
|
strcpy(mailcmd, SENDMAIL);
|
|
if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
|