[Asterisk-code-review] app_voicemail: Refactor email generation functions (asterisk[18])
N A
asteriskteam at digium.com
Fri Nov 19 10:51:04 CST 2021
N A has uploaded this change for review. ( https://gerrit.asterisk.org/c/asterisk/+/17564 )
Change subject: app_voicemail: Refactor email generation functions
......................................................................
app_voicemail: Refactor email generation functions
Refactors generic functions used for email generation
into utils.c so that they can be used by multiple
modules, including app_voicemail and app_minivm,
to avoid code duplication.
ASTERISK-29715 #close
Change-Id: I1de0ed3483623e9599711129edc817c45ad237ee
---
M apps/app_minivm.c
M apps/app_voicemail.c
M include/asterisk/file.h
M include/asterisk/utils.h
M main/file.c
M main/utils.c
6 files changed, 193 insertions(+), 300 deletions(-)
git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/64/17564/1
diff --git a/apps/app_minivm.c b/apps/app_minivm.c
index 8f1064e..69370ef 100644
--- a/apps/app_minivm.c
+++ b/apps/app_minivm.c
@@ -161,7 +161,6 @@
#include <dirent.h>
#include <locale.h>
-
#include "asterisk/paths.h" /* use various paths */
#include "asterisk/lock.h"
#include "asterisk/file.h"
@@ -542,8 +541,6 @@
#define SENDMAIL "/usr/sbin/sendmail -t"
#define SOUND_INTRO "vm-intro"
-#define B64_BASEMAXINLINE 256 /*!< Buffer size for Base 64 attachment encoding */
-#define B64_BASELINELEN 72 /*!< Line length for Base 64 encoded messages */
#define EOL "\r\n"
#define MAX_DATETIME_FORMAT 512
@@ -659,15 +656,6 @@
signed char record_gain;
};
-/*! \brief Structure for base64 encoding */
-struct b64_baseio {
- int iocp;
- int iolen;
- int linelength;
- int ateof;
- unsigned char iobuf[B64_BASEMAXINLINE];
-};
-
/*! \brief Voicemail time zones */
struct minivm_zone {
char name[80]; /*!< Name of this time zone */
@@ -853,134 +841,6 @@
AST_LIST_UNLOCK(&message_templates);
}
-/*!\internal
- * \brief read buffer from file (base64 conversion) */
-static int b64_inbuf(struct b64_baseio *bio, FILE *fi)
-{
- int l;
-
- if (bio->ateof)
- return 0;
-
- if ((l = fread(bio->iobuf, 1, B64_BASEMAXINLINE, fi)) != B64_BASEMAXINLINE) {
- bio->ateof = 1;
- if (l == 0) {
- /* Assume EOF */
- return 0;
- }
- }
-
- bio->iolen = l;
- bio->iocp = 0;
-
- return 1;
-}
-
-/*!\internal
- * \brief read character from file to buffer (base64 conversion) */
-static int b64_inchar(struct b64_baseio *bio, FILE *fi)
-{
- if (bio->iocp >= bio->iolen) {
- if (!b64_inbuf(bio, fi))
- return EOF;
- }
-
- return bio->iobuf[bio->iocp++];
-}
-
-/*!\internal
- * \brief write buffer to file (base64 conversion) */
-static int b64_ochar(struct b64_baseio *bio, int c, FILE *so)
-{
- if (bio->linelength >= B64_BASELINELEN) {
- if (fputs(EOL,so) == EOF)
- return -1;
-
- bio->linelength= 0;
- }
-
- if (putc(((unsigned char) c), so) == EOF)
- return -1;
-
- bio->linelength++;
-
- return 1;
-}
-
-/*!\internal
- * \brief Encode file to base64 encoding for email attachment (base64 conversion) */
-static int base_encode(char *filename, FILE *so)
-{
- unsigned char dtable[B64_BASEMAXINLINE];
- int i,hiteof= 0;
- FILE *fi;
- struct b64_baseio bio;
-
- memset(&bio, 0, sizeof(bio));
- bio.iocp = B64_BASEMAXINLINE;
-
- if (!(fi = fopen(filename, "rb"))) {
- ast_log(LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
- return -1;
- }
-
- for (i= 0; i<9; i++) {
- dtable[i]= 'A'+i;
- dtable[i+9]= 'J'+i;
- dtable[26+i]= 'a'+i;
- dtable[26+i+9]= 'j'+i;
- }
- for (i= 0; i < 8; i++) {
- dtable[i+18]= 'S'+i;
- dtable[26+i+18]= 's'+i;
- }
- for (i= 0; i < 10; i++) {
- dtable[52+i]= '0'+i;
- }
- dtable[62]= '+';
- dtable[63]= '/';
-
- while (!hiteof){
- unsigned char igroup[3], ogroup[4];
- int c,n;
-
- igroup[0]= igroup[1]= igroup[2]= 0;
-
- for (n= 0; n < 3; n++) {
- if ((c = b64_inchar(&bio, fi)) == EOF) {
- hiteof= 1;
- break;
- }
- igroup[n]= (unsigned char)c;
- }
-
- if (n> 0) {
- ogroup[0]= dtable[igroup[0]>>2];
- ogroup[1]= dtable[((igroup[0]&3)<<4) | (igroup[1]>>4)];
- ogroup[2]= dtable[((igroup[1]&0xF)<<2) | (igroup[2]>>6)];
- ogroup[3]= dtable[igroup[2]&0x3F];
-
- if (n<3) {
- ogroup[3]= '=';
-
- if (n<2)
- ogroup[2]= '=';
- }
-
- for (i= 0;i<4;i++)
- b64_ochar(&bio, ogroup[i], so);
- }
- }
-
- /* Put end of line - line feed */
- if (fputs(EOL, so) == EOF)
- return 0;
-
- fclose(fi);
-
- return 1;
-}
-
static int get_date(char *s, int len)
{
struct ast_tm tm;
@@ -1481,7 +1341,7 @@
fprintf(p, "Content-Description: Voicemail sound attachment.\n");
fprintf(p, "Content-Disposition: attachment; filename=\"voicemail%s.%s\"\n\n", counter ? counter : "", format);
- base_encode(fname, p);
+ ast_base64_encode_file_path(fname, p, EOL);
fprintf(p, "\n\n--%s--\n.\n", bound);
}
fclose(p);
diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c
index ee7752d..6f909d4 100644
--- a/apps/app_voicemail.c
+++ b/apps/app_voicemail.c
@@ -529,7 +529,6 @@
/* Default mail command to mail voicemail. Change it with the
* mailcmd= command in voicemail.conf */
#define SENDMAIL "/usr/sbin/sendmail -t"
-
#define INTRO "vm-intro"
#define MAX_MAIL_BODY_CONTENT_SIZE 134217728L // 128 Mbyte
@@ -539,8 +538,6 @@
#define MINPASSWORD 0 /*!< Default minimum mailbox password length */
-#define BASELINELEN 72
-#define BASEMAXINLINE 256
#ifdef IMAP_STORAGE
#define ENDL "\r\n"
#else
@@ -744,14 +741,6 @@
*/
-struct baseio {
- int iocp;
- int iolen;
- int linelength;
- int ateof;
- unsigned char iobuf[BASEMAXINLINE];
-};
-
#define MAX_VM_MBOX_ID_LEN (AST_MAX_EXTENSION)
#define MAX_VM_CONTEXT_LEN (AST_MAX_CONTEXT)
/* MAX_VM_MAILBOX_LEN allows enough room for the '@' and NULL terminator */
@@ -1928,22 +1917,6 @@
return snprintf(dest, len, "%s/msg%04d", dir, num);
}
-/* same as mkstemp, but return a FILE * */
-static FILE *vm_mkftemp(char *template)
-{
- FILE *p = NULL;
- int pfd = mkstemp(template);
- chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
- if (pfd > -1) {
- p = fdopen(pfd, "w+");
- if (!p) {
- close(pfd);
- pfd = -1;
- }
- }
- return p;
-}
-
/*! \brief basically mkdir -p $dest/$context/$ext/$folder
* \param dest String. base directory.
* \param len Length of dest.
@@ -2697,7 +2670,7 @@
/* Make a temporary file instead of piping directly to sendmail, in case the mail
command hangs. */
- if (!(p = vm_mkftemp(tmp))) {
+ if (!(p = ast_file_mkftemp(tmp, VOICEMAIL_FILE_MODE & ~my_umask))) {
ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
if (tempcopy) {
ast_free(vmu->email);
@@ -4771,134 +4744,6 @@
return ast_filedelete(file, NULL);
}
-/*!
- * \brief utility used by inchar(), for base_encode()
- */
-static int inbuf(struct baseio *bio, FILE *fi)
-{
- int l;
-
- if (bio->ateof)
- return 0;
-
- if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) != BASEMAXINLINE) {
- bio->ateof = 1;
- if (l == 0) {
- /* Assume EOF */
- return 0;
- }
- }
-
- bio->iolen = l;
- bio->iocp = 0;
-
- return 1;
-}
-
-/*!
- * \brief utility used by base_encode()
- */
-static int inchar(struct baseio *bio, FILE *fi)
-{
- if (bio->iocp>=bio->iolen) {
- if (!inbuf(bio, fi))
- return EOF;
- }
-
- return bio->iobuf[bio->iocp++];
-}
-
-/*!
- * \brief utility used by base_encode()
- */
-static int ochar(struct baseio *bio, int c, FILE *so)
-{
- if (bio->linelength >= BASELINELEN) {
- if (fputs(ENDL, so) == EOF) {
- return -1;
- }
-
- bio->linelength = 0;
- }
-
- if (putc(((unsigned char) c), so) == EOF) {
- return -1;
- }
-
- bio->linelength++;
-
- return 1;
-}
-
-/*!
- * \brief Performs a base 64 encode algorithm on the contents of a File
- * \param filename The path to the file to be encoded. Must be readable, file is opened in read mode.
- * \param so A FILE handle to the output file to receive the base 64 encoded contents of the input file, identified by filename.
- *
- * 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 ?
- *
- * \return zero on success, -1 on error.
- */
-static int base_encode(char *filename, FILE *so)
-{
- static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
- 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
- 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
- '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
- int i, hiteof = 0;
- FILE *fi;
- struct baseio bio;
-
- memset(&bio, 0, sizeof(bio));
- bio.iocp = BASEMAXINLINE;
-
- if (!(fi = fopen(filename, "rb"))) {
- ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
- return -1;
- }
-
- while (!hiteof){
- unsigned char igroup[3], ogroup[4];
- int c, n;
-
- memset(igroup, 0, sizeof(igroup));
-
- for (n = 0; n < 3; n++) {
- if ((c = inchar(&bio, fi)) == EOF) {
- hiteof = 1;
- break;
- }
-
- igroup[n] = (unsigned char) c;
- }
-
- if (n > 0) {
- ogroup[0]= dtable[igroup[0] >> 2];
- ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
- ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
- ogroup[3]= dtable[igroup[2] & 0x3F];
-
- if (n < 3) {
- ogroup[3] = '=';
-
- if (n < 2)
- ogroup[2] = '=';
- }
-
- for (i = 0; i < 4; i++)
- ochar(&bio, ogroup[i], so);
- }
- }
-
- fclose(fi);
-
- if (fputs(ENDL, so) == EOF) {
- return 0;
- }
-
- return 1;
-}
-
static void prep_email_sub_vars(struct ast_channel *ast, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *dur, char *date, const char *category, const char *flag)
{
char callerid[256];
@@ -5509,7 +5354,7 @@
fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
else
fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
- base_encode(fname, p);
+ ast_base64_encode_file_path(fname, p, ENDL);
if (last)
fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
@@ -5562,7 +5407,7 @@
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));
/* Make a temporary file instead of piping directly to sendmail, in case the mail
command hangs */
- if ((p = vm_mkftemp(tmp)) == NULL) {
+ if ((p = ast_file_mkftemp(tmp, VOICEMAIL_FILE_MODE & ~my_umask)) == NULL) {
ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
return -1;
} else {
@@ -5601,7 +5446,7 @@
strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
}
- if ((p = vm_mkftemp(tmp)) == NULL) {
+ if ((p = ast_file_mkftemp(tmp, VOICEMAIL_FILE_MODE & ~my_umask)) == NULL) {
ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
ast_free(str1);
ast_free(str2);
diff --git a/include/asterisk/file.h b/include/asterisk/file.h
index 7e54426..04fc5bb 100644
--- a/include/asterisk/file.h
+++ b/include/asterisk/file.h
@@ -138,6 +138,15 @@
int ast_filecopy(const char *oldname, const char *newname, const char *fmt);
/*!
+ * \brief same as mkstemp, but return a FILE
+ * \param template The template for the unique file name to generate. Modified in place to return the file name.
+ * \param mode The mode for file permissions
+ *
+ * \return FILE handle to the temporary file on success or NULL if creation failed
+ */
+FILE *ast_file_mkftemp(char *template, mode_t mode);
+
+/*!
* \brief Callback called for each file found when reading directories
* \param dir_name the name of the directory
* \param filename the name of the file
diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h
index 08120bf..024b6c7 100644
--- a/include/asterisk/utils.h
+++ b/include/asterisk/utils.h
@@ -336,6 +336,26 @@
*/
char *ast_base64url_encode_string(const char *src);
+/*!
+ * \brief Performs a base 64 encode algorithm on the contents of a File
+ * \param inputfile A FILE handle to the input file to be encoded. Must be readable. This handle is not automatically closed.
+ * \param outputfile A FILE handle to the output file to receive the base 64 encoded contents of the input file, identified by filename.
+ * \param endl The line ending to use (e.g. either "\n" or "\r\n")
+ *
+ * \return zero on success, -1 on error.
+ */
+int ast_base64_encode_file(FILE *inputfile, FILE *outputfile, const char *endl);
+
+/*!
+ * \brief Performs a base 64 encode algorithm on the contents of a File
+ * \param filename The path to the file to be encoded. Must be readable, file is opened in read mode.
+ * \param outputfile A FILE handle to the output file to receive the base 64 encoded contents of the input file, identified by filename.
+ * \param endl The line ending to use (e.g. either "\n" or "\r\n")
+ *
+ * \return zero on success, -1 on error.
+ */
+int ast_base64_encode_file_path(const char *filename, FILE *outputfile, const char *endl);
+
#define AST_URI_ALPHANUM (1 << 0)
#define AST_URI_MARK (1 << 1)
#define AST_URI_UNRESERVED (AST_URI_ALPHANUM | AST_URI_MARK)
diff --git a/main/file.c b/main/file.c
index a16b6dd..89fcd14 100644
--- a/main/file.c
+++ b/main/file.c
@@ -184,6 +184,21 @@
return res;
}
+FILE *ast_file_mkftemp(char *template, mode_t mode)
+{
+ FILE *p = NULL;
+ int pfd = mkstemp(template);
+ chmod(template, mode);
+ if (pfd > -1) {
+ p = fdopen(pfd, "w+");
+ if (!p) {
+ close(pfd);
+ pfd = -1;
+ }
+ }
+ return p;
+}
+
int ast_stopstream(struct ast_channel *tmp)
{
ast_channel_lock(tmp);
diff --git a/main/utils.c b/main/utils.c
index f4a026d..dc94c99 100644
--- a/main/utils.c
+++ b/main/utils.c
@@ -570,6 +570,150 @@
b2a_url[(int)'_'] = 63;
}
+#define BASELINELEN 72 /*!< Line length for Base 64 encoded messages */
+#define BASEMAXINLINE 256 /*!< Buffer size for Base 64 attachment encoding */
+
+/*! \brief Structure used for base64 encoding */
+struct baseio {
+ int iocp;
+ int iolen;
+ int linelength;
+ int ateof;
+ unsigned char iobuf[BASEMAXINLINE];
+};
+
+/*!
+ * \brief utility used by inchar(), for base_encode()
+ */
+static int inbuf(struct baseio *bio, FILE *fi)
+{
+ int l;
+
+ if (bio->ateof) {
+ return 0;
+ }
+
+ if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) != BASEMAXINLINE) {
+ bio->ateof = 1;
+ if (l == 0) {
+ /* Assume EOF */
+ return 0;
+ }
+ }
+
+ bio->iolen = l;
+ bio->iocp = 0;
+
+ return 1;
+}
+
+/*!
+ * \brief utility used by base_encode()
+ */
+static int inchar(struct baseio *bio, FILE *fi)
+{
+ if (bio->iocp >= bio->iolen) {
+ if (!inbuf(bio, fi)) {
+ return EOF;
+ }
+ }
+
+ return bio->iobuf[bio->iocp++];
+}
+
+/*!
+ * \brief utility used by base_encode()
+ */
+static int ochar(struct baseio *bio, int c, FILE *so, const char *endl)
+{
+ if (bio->linelength >= BASELINELEN) {
+ if (fputs(endl, so) == EOF) {
+ return -1;
+ }
+
+ bio->linelength = 0;
+ }
+
+ if (putc(((unsigned char) c), so) == EOF) {
+ return -1;
+ }
+
+ bio->linelength++;
+
+ return 1;
+}
+
+int ast_base64_encode_file(FILE *inputfile, FILE *outputfile, const char *endl)
+{
+ static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
+ 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
+ '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
+ int i, hiteof = 0;
+ struct baseio bio;
+
+ memset(&bio, 0, sizeof(bio));
+ bio.iocp = BASEMAXINLINE;
+
+ while (!hiteof){
+ unsigned char igroup[3], ogroup[4];
+ int c, n;
+
+ memset(igroup, 0, sizeof(igroup));
+
+ for (n = 0; n < 3; n++) {
+ if ((c = inchar(&bio, inputfile)) == EOF) {
+ hiteof = 1;
+ break;
+ }
+
+ igroup[n] = (unsigned char) c;
+ }
+
+ if (n > 0) {
+ ogroup[0]= dtable[igroup[0] >> 2];
+ ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
+ ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
+ ogroup[3]= dtable[igroup[2] & 0x3F];
+
+ if (n < 3) {
+ ogroup[3] = '=';
+
+ if (n < 2) {
+ ogroup[2] = '=';
+ }
+ }
+
+ for (i = 0; i < 4; i++) {
+ ochar(&bio, ogroup[i], outputfile, endl);
+ }
+ }
+ }
+
+ if (fputs(endl, outputfile) == EOF) {
+ return 0;
+ }
+
+ return 1;
+}
+
+int ast_base64_encode_file_path(const char *filename, FILE *outputfile, const char *endl)
+{
+ FILE *fi;
+ int res;
+
+ if (!(fi = fopen(filename, "rb"))) {
+ ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
+ return -1;
+ }
+
+ res = ast_base64_encode_file(fi, outputfile, endl);
+
+ fclose(fi);
+
+ return res;
+}
+
const struct ast_flags ast_uri_http = {AST_URI_UNRESERVED};
const struct ast_flags ast_uri_http_legacy = {AST_URI_LEGACY_SPACE | AST_URI_UNRESERVED};
const struct ast_flags ast_uri_sip_user = {AST_URI_UNRESERVED | AST_URI_SIP_USER_UNRESERVED};
--
To view, visit https://gerrit.asterisk.org/c/asterisk/+/17564
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings
Gerrit-Project: asterisk
Gerrit-Branch: 18
Gerrit-Change-Id: I1de0ed3483623e9599711129edc817c45ad237ee
Gerrit-Change-Number: 17564
Gerrit-PatchSet: 1
Gerrit-Owner: N A <mail at interlinked.x10host.com>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20211119/83fc5481/attachment-0001.html>
More information about the asterisk-code-review
mailing list