[asterisk-commits] mnicholson: trunk r272558 - in /trunk: include/asterisk/res_fax.h res/res_fax.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Jun 25 14:42:57 CDT 2010


Author: mnicholson
Date: Fri Jun 25 14:42:54 2010
New Revision: 272558

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=272558
Log:
Implemement support for handling multiple documents when sending.

Modified:
    trunk/include/asterisk/res_fax.h
    trunk/res/res_fax.c

Modified: trunk/include/asterisk/res_fax.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/res_fax.h?view=diff&rev=272558&r1=272557&r2=272558
==============================================================================
--- trunk/include/asterisk/res_fax.h (original)
+++ trunk/include/asterisk/res_fax.h Fri Jun 25 14:42:54 2010
@@ -33,13 +33,15 @@
 /*! \brief capabilities for res_fax to locate a fax technology module */
 enum ast_fax_capabilities {
 	/*! SendFax is supported */
-	AST_FAX_TECH_SEND    = (1 << 0),
+	AST_FAX_TECH_SEND      = (1 << 0),
 	/*! ReceiveFax is supported */
-	AST_FAX_TECH_RECEIVE = (1 << 1),
+	AST_FAX_TECH_RECEIVE   = (1 << 1),
 	/*! Audio FAX session supported */
-	AST_FAX_TECH_AUDIO   = (1 << 2),
+	AST_FAX_TECH_AUDIO     = (1 << 2),
 	/*! T.38 FAX session supported */
-	AST_FAX_TECH_T38     = (1 << 3),
+	AST_FAX_TECH_T38       = (1 << 3),
+	/*! sending mulitple documents supported */
+	AST_FAX_TECH_MULTI_DOC = (1 << 4),
 };
 
 /*! \brief fax modem capabilities */

Modified: trunk/res/res_fax.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/res_fax.c?view=diff&rev=272558&r1=272557&r2=272558
==============================================================================
--- trunk/res/res_fax.c (original)
+++ trunk/res/res_fax.c Fri Jun 25 14:42:54 2010
@@ -75,8 +75,8 @@
 
 static const char app_sendfax[] = "SendFAX";
 static const char synopsis_sendfax[] = "Sends a specified TIFF/F file as a FAX.";
-static const char descrip_sendfax[] = "SendFAX(filename[,options]):\n"
- " The SendFAX() application sends the specified TIFF/F file as a FAX.\n"
+static const char descrip_sendfax[] = "SendFAX(filename[&filename[&filename]][,options]):\n"
+ " The SendFAX() application sends the specified TIFF/F file(s) as a FAX.\n"
  " The application arguments are:\n"
  "    'd' - enables FAX debugging\n"
  "    'f' - allow audio fallback FAX transfer on T.38 capable channels\n"
@@ -600,9 +600,62 @@
 	pbx_substitute_variables_helper(chan, "${CALLERID(num)}", info->cid, sizeof(info->cid));
 }
 
+
+/* \brief Generate a string of filenames using the given prefix and separator.
+ * \param details the fax session details
+ * \param prefix the prefix to each filename
+ * \param separator the separator between filenames
+ *
+ * This function generates a string of filenames from the given details
+ * structure and using the given prefix and separator.
+ *
+ * \retval NULL there was an error generating the string
+ * \return the string generated string
+ */
+static char *generate_filenames_string(struct ast_fax_session_details *details, char *prefix, char *separator)
+{
+	char *filenames, *c;
+	size_t size = 0;
+	int first = 1;
+	struct ast_fax_document *doc;
+
+	/* don't process empty lists */
+	if (AST_LIST_EMPTY(&details->documents)) {
+		return NULL;
+	}
+
+	/* Calculate the total length of all of the file names */
+	AST_LIST_TRAVERSE(&details->documents, doc, next) {
+		size += strlen(separator) + strlen(prefix) + strlen(doc->filename);
+	}
+	size += 1; /* add space for the terminating null */
+
+	if (!(filenames = ast_malloc(size))) {
+		return NULL;
+	}
+	c = filenames;
+
+	ast_build_string(&c, &size, "%s%s", prefix, AST_LIST_FIRST(&details->documents)->filename);
+	AST_LIST_TRAVERSE(&details->documents, doc, next) {
+		if (first) {
+			first = 0;
+			continue;
+		}
+
+		ast_build_string(&c, &size, "%s%s%s", separator, prefix, doc->filename);
+	}
+
+	return filenames;
+}
+
 /*! \brief send a FAX status manager event */
 static int report_fax_status(struct ast_channel *chan, struct ast_fax_session_details *details, const char *status)
 {
+	char *filenames = generate_filenames_string(details, "FileName: ", "\r\n");
+	if (!filenames) {
+		return 1;
+	}
+
 	ast_channel_lock(chan);
 	pbx_builtin_setvar_helper(chan, "FAXSTATUSSTRING", status);
 	if (details->option.statusevents) {
@@ -617,16 +670,17 @@
 			      "Exten: %s\r\n"
 			      "CallerID: %s\r\n"
 			      "LocalStationID: %s\r\n"
-			      "FileName: %s\r\n",
+			      "%s\r\n",
 			      status,
 			      chan->name,
 			      info.context,
 			      info.exten,
 			      info.cid,
 			      details->localstationid,
-			      AST_LIST_FIRST(&details->documents)->filename);
+			      filenames);
 	}
 	ast_channel_unlock(chan);
+	ast_free(filenames);
 
 	return 0;
 }
@@ -1545,19 +1599,19 @@
 /*! \brief initiate a send FAX session */
 static int sendfax_exec(struct ast_channel *chan, const char *data)
 {
-	char *parse;
-	int channel_alive;
+	char *parse, *filenames, *c;
+	int channel_alive, file_count;
 	struct ast_fax_session_details *details;
 	struct ast_fax_document *doc;
 	AST_DECLARE_APP_ARGS(args,
-		AST_APP_ARG(filename);
+		AST_APP_ARG(filenames);
 		AST_APP_ARG(options);
 	);
 	struct ast_flags opts = { 0, };
 	struct manager_event_info info;
 
 	if (ast_strlen_zero(data)) {
-		ast_log(LOG_WARNING, "%s requires an argument (filename[,options])\n", app_sendfax);
+		ast_log(LOG_WARNING, "%s requires an argument (filename[&filename[&filename]][,options])\n", app_sendfax);
 		return -1;
 	}
 	parse = ast_strdupa(data);
@@ -1576,8 +1630,8 @@
 	    ast_app_parse_options(fax_exec_options, &opts, NULL, args.options)) {
 		return -1;
 	}
-	if (ast_strlen_zero(args.filename)) {
-		ast_log(LOG_WARNING, "%s requires an argument (filename[,options])\n", app_sendfax);
+	if (ast_strlen_zero(args.filenames)) {
+		ast_log(LOG_WARNING, "%s requires an argument (filename[&filename[&filename]],options])\n", app_sendfax);
 		return -1;
 	}
 	
@@ -1587,11 +1641,6 @@
 		return -1;
 	}
 
-	if (access(args.filename, (F_OK | R_OK)) < 0) {
-		ast_log(LOG_ERROR, "access failure.  Verify '%s' exists and check permissions.\n", args.filename);
-		return -1;
-	}
-	
 	/* make sure the channel is up */
 	if (chan->_state != AST_STATE_UP) {
 		if (ast_answer(chan)) {
@@ -1612,17 +1661,35 @@
 		return -1;
 	}
 
-	if (!(doc = ast_calloc(1, sizeof(*doc) + strlen(args.filename) + 1))) {
-		ast_log(LOG_ERROR, "System cannot provide memory for session requirements.\n");
-		ao2_ref(details, -1);
-		return -1;
-	}
-
-	strcpy(doc->filename, args.filename);
-	AST_LIST_INSERT_TAIL(&details->documents, doc, next);
-
-	ast_verb(3, "Channel '%s' sending FAX '%s'\n", chan->name, args.filename);
-	
+	file_count = 0;
+	filenames = args.filenames;
+	while ((c = strsep(&filenames, "&"))) {
+		if (access(c, (F_OK | R_OK)) < 0) {
+			ast_log(LOG_ERROR, "access failure.  Verify '%s' exists and check permissions.\n", args.filenames);
+			ao2_ref(details, -1);
+			return -1;
+		}
+
+		if (!(doc = ast_calloc(1, sizeof(*doc) + strlen(c) + 1))) {
+			ast_log(LOG_ERROR, "System cannot provide memory for session requirements.\n");
+			ao2_ref(details, -1);
+			return -1;
+		}
+
+		strcpy(doc->filename, c);
+		AST_LIST_INSERT_TAIL(&details->documents, doc, next);
+		file_count++;
+	}
+
+	if (file_count > 1) {
+		details->caps |= AST_FAX_TECH_MULTI_DOC;
+	}
+
+	ast_verb(3, "Channel '%s' sending FAX:\n", chan->name);
+	AST_LIST_TRAVERSE(&details->documents, doc, next) {
+		ast_verb(3, "   %s\n", doc->filename);
+	}
+
 	details->caps = AST_FAX_TECH_SEND;
 
 	/* check for debug */
@@ -1667,6 +1734,12 @@
 		if (disable_t38(chan)) {
 			ast_log(LOG_WARNING, "error disabling T.38 mode on %s\n", chan->name);
 		}
+	}
+
+	if (!(filenames = generate_filenames_string(details, "FileName: ", "\r\n"))) {
+		ast_log(LOG_ERROR, "Error generating SendFAX manager event\n");
+		ao2_ref(details, -1);
+		return (!channel_alive) ? -1 : 0;
 	}
 
 	/* send out the AMI completion event */
@@ -1683,7 +1756,7 @@
 		      "PagesTransferred: %s\r\n"
 		      "Resolution: %s\r\n"
 		      "TransferRate: %s\r\n"
-		      "FileName: %s\r\n",
+		      "%s\r\n",
 		      chan->name,
 		      info.context,
 		      info.exten,
@@ -1693,8 +1766,10 @@
 		      pbx_builtin_getvar_helper(chan, "FAXPAGES"),
 		      pbx_builtin_getvar_helper(chan, "FAXRESOLUTION"),
 		      pbx_builtin_getvar_helper(chan, "FAXBITRATE"),
-		      args.filename);
+		      filenames);
 	ast_channel_unlock(chan);
+
+	ast_free(filenames);
 
 	ao2_ref(details, -1);
 
@@ -1954,6 +2029,7 @@
 	struct ast_fax_session *s;
 	struct ao2_iterator i;
 	int session_count;
+	char *filenames;
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -1968,15 +2044,28 @@
 
 	ast_cli(a->fd, "\nCurrent FAX Sessions:\n\n");
 	ast_cli(a->fd, "%-20.20s %-10.10s %-10.10s %-5.5s %-10.10s %-15.15s %-30.30s\n",
-		"Channel", "Tech", "FAXID", "Type", "Operation", "State", "File");
+		"Channel", "Tech", "FAXID", "Type", "Operation", "State", "File(s)");
 	i = ao2_iterator_init(faxregistry.container, 0);
 	while ((s = ao2_iterator_next(&i))) {
 		ao2_lock(s);
-		ast_cli(a->fd, "%-20.20s %-10.10s %-10d %-5.5s %-10.10s %-15.15s %-30.30s\n",
+
+		if (!(filenames = generate_filenames_string(s->details, "", ", "))) {
+			ast_log(LOG_ERROR, "error printing filenames for 'fax show sessions' command");
+			ao2_unlock(s);
+			ao2_ref(s, -1);
+			if (ao2_iterator_destroy != NULL) {
+				ao2_iterator_destroy(&i);
+			}
+			return CLI_FAILURE;
+		}
+
+		ast_cli(a->fd, "%-20.20s %-10.10s %-10d %-5.5s %-10.10s %-15.15s %-30s\n",
 			s->channame, s->tech->type, s->id,
 			(s->details->caps & AST_FAX_TECH_AUDIO) ? "G.711" : "T.38",
 			(s->details->caps & AST_FAX_TECH_SEND) ? "send" : "receive",
-			ast_fax_state_to_str(s->state), AST_LIST_FIRST(&s->details->documents)->filename);
+			ast_fax_state_to_str(s->state), filenames);
+
+		ast_free(filenames);
 		ao2_unlock(s);
 		ao2_ref(s, -1);
 	}
@@ -2063,6 +2152,7 @@
 {
 	struct ast_fax_session_details *details = find_details(chan);
 	int res = 0;
+	char *filenames;
 
 	if (!details) {
 		ast_log(LOG_ERROR, "channel '%s' can't read FAXOPT(%s) because it has never been written.\n", chan->name, data);
@@ -2078,6 +2168,17 @@
 			res = -1;
 		} else {
 			ast_copy_string(buf, AST_LIST_FIRST(&details->documents)->filename, len);
+		}
+	} else if (!strcasecmp(data, "filenames")) {
+		if (AST_LIST_EMPTY(&details->documents)) {
+			ast_log(LOG_ERROR, "channel '%s' can't read FAXOPT(%s) because it has never been written.\n", chan->name, data);
+			res = -1;
+		} else if ((filenames = generate_filenames_string(details, "", ","))) {
+			ast_copy_string(buf, filenames, len);
+			ast_free(filenames);
+		} else {
+			ast_log(LOG_ERROR, "channel '%s' can't read FAXOPT(%s), there was an error generating the filenames list.\n", chan->name, data);
+			res = -1;
 		}
 	} else if (!strcasecmp(data, "headerinfo")) {
 		ast_copy_string(buf, details->headerinfo, len);
@@ -2169,7 +2270,8 @@
 "  ------             ----     -----------\n"
 "  ecm                 RW      Specify Error Correction Mode (ECM) with 'yes', disable with 'no'.\n"
 "  error               RO      Read the FAX transmission error upon failure.\n"
-"  filename            RO      Read the filename of the FAX transmission.\n"
+"  filename            RO      Read the filename of the first file of the FAX transmission.\n"
+"  filenames           RO      Read the filenames of all of the files in the FAX transmission (comma separated).\n"
 "  headerinfo          RW      Specify or read the FAX header.\n"
 "  localstationid      RW      Specify or read the local station identification\n"
 "  maxrate             RW      Specify or read the maximum transfer rate before transmission\n"




More information about the asterisk-commits mailing list