1 /*	$Id$ */
2 /*
3  * Copyright (c) 1994-1996 Sam Leffler
4  * Copyright (c) 1994-1996 Silicon Graphics, Inc.
5  * HylaFAX is a trademark of Silicon Graphics
6  *
7  * Permission to use, copy, modify, distribute, and sell this software and
8  * its documentation for any purpose is hereby granted without fee, provided
9  * that (i) the above copyright notices and this permission notice appear in
10  * all copies of the software and related documentation, and (ii) the names of
11  * Sam Leffler and Silicon Graphics may not be used in any advertising or
12  * publicity relating to the software without the specific, prior written
13  * permission of Sam Leffler and Silicon Graphics.
14  *
15  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
17  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
18  *
19  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
20  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
21  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
22  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
23  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
24  * OF THIS SOFTWARE.
25  */
26 #include "SNPPClient.h"
27 #include "Sys.h"
28 #include "NLS.h"
29 #include "config.h"
30 
31 #if HAS_LOCALE
32 extern "C" {
33 #include <locale.h>
34 }
35 #endif
36 
37 class sendPageApp : public SNPPClient {
38 public:
39 private:
40     fxStr	appName;		// for error messages
41     fxStr	msgFile;		// file containing any text
42 protected:
43     void copyToTemporary(int fin, fxStr& tmpl);
44 
45     void vprintError(const char* fmt, va_list ap);
46     void vprintWarning(const char* fmt, va_list ap);
47     void fatal(const char* fmt ...);
48     void usage();
49 public:
50     sendPageApp();
51     ~sendPageApp();
52 
53     bool run(int argc, char** argv);
54 };
55 
sendPageApp()56 sendPageApp::sendPageApp()
57 {
58     setupConfig();
59 }
60 
~sendPageApp()61 sendPageApp::~sendPageApp()
62 {
63     if (msgFile != "")
64 	Sys::unlink(msgFile);
65 }
66 
67 bool
run(int argc,char ** argv)68 sendPageApp::run(int argc, char** argv)
69 {
70     extern int optind;
71     extern char* optarg;
72     int c;
73 
74     appName = argv[0];
75     u_int l = appName.length();
76     appName = appName.tokenR(l, '/');
77 
78     resetConfig();
79     readConfig(FAX_SYSCONF);
80     readConfig(FAX_LIBDATA "/sendpage.conf");
81     readConfig(FAX_USERCONF);
82 
83     fxStr emsg;
84     bool noText = false;		// default is to assume message text
85     SNPPJob& proto = getProtoJob();
86     while ((c = Sys::getopt(argc, argv, "a:De:f:h:i:I:l:nNp:qRs:t:T:v")) != -1)
87 	switch (c) {
88 	case 'a':			// time at which to transmit page
89 	    if (!proto.setHoldTime(optarg, emsg)) {
90 		printError(_("Invalid hold time \"%s\": %s"),
91 		    optarg, (const char*) emsg);
92 		exit(-1);
93 	    }
94 	    break;
95 	case 'D':			// notify when done
96 	    proto.setNotification("when done");
97 	    break;
98 	case 'f':			// sender's identity
99 	    setFromIdentity(optarg);
100 	    break;
101 	case 'h':			// server's host
102 	    setHost(optarg);
103 	    break;
104 	case 's':			// user-specified job identifier
105 	    proto.setSubject(optarg);
106 	    break;
107 	case 'I':			// fixed retry time
108 	    proto.setRetryTime(atoi(optarg));
109 	    break;
110 	case 'l':			// service level
111 	    proto.setServiceLevel(atoi(optarg));
112 	    break;
113 	case 'n':			// numeric-only page, no message text
114 	    noText = true;
115 	    break;
116 	case 'N':			// no notification
117 	    proto.setNotification("none");
118 	    break;
119 	case 'p':			// PIN
120 	    addJob().setPIN(optarg);
121 	    break;
122 	case 'q':			// queue job and don't wait
123 	    proto.setQueued(true);
124 	    break;
125 	case 'R':			// notify when requeued or done
126 	    proto.setNotification("when requeued");
127 	    break;
128 	case 't':			// times to try sending
129 	    proto.setMaxTries(atoi(optarg));
130 	    break;
131 	case 'T':			// times to dial telephone
132 	    proto.setMaxDials(atoi(optarg));
133 	    break;
134 	case 'v':			// client-server protocol tracing
135 	    setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
136 	    setVerbose(true);
137 	    break;
138 	case '?':
139 	    usage();
140 	    /*NOTREACHED*/
141 	}
142 
143     if (getNumberOfJobs() == 0) {
144 	fprintf(stderr, _("%s: No pager identification number (PIN) specified.\n"),
145 	    (const char*) appName);
146 	usage();
147     }
148     if (!noText) {			// collect message text ...
149 	if (optind < argc) {		// ... from command line
150 	    fxStr msg;
151 	    for (; optind < argc; optind++) {
152 		if (msg.length() > 0)
153 		    msg.append(' ');
154 		msg.append(argv[optind]);
155 	    }
156 	    setPagerMsg(msg);
157 	} else {			// ... from standard input
158 	    copyToTemporary(fileno(stdin), msgFile);
159 	    setPagerMsgFile(msgFile);
160 	}
161     }
162     bool status = false;
163     if (callServer(emsg)) {
164 	status = login(NULL, emsg)
165 	      && prepareForJobSubmissions(emsg)
166 	      && submitJobs(emsg);
167 	hangupServer();
168     }
169     if (!status)
170 	printError("%s", (const char*) emsg);
171     return (status);
172 }
173 
174 void
usage()175 sendPageApp::usage()
176 {
177     fxFatal(_("usage: %s"
178 	" -p PIN [-p PIN ...]\n"
179 	" [-a time-to-send]"
180 	" [-l service-level]"
181 	" [-s message-subject]\n"
182 	"    "
183 	" [-h host[:modem]]"
184 	" [-f from]\n"
185 	"    "
186 	" [-I retry-time]"
187 	" [-t max-tries]"
188 	" [-T max-dials]"
189 	" [-nqvDNR]"
190 	" [msgs ...]"),
191 	(const char*) appName);
192 }
193 
194 /*
195  * Copy data from fin to a temporary file.
196  */
197 void
copyToTemporary(int fin,fxStr & tmpl)198 sendPageApp::copyToTemporary(int fin, fxStr& tmpl)
199 {
200     const char* templ = _PATH_TMP "/sndpageXXXXXX";
201     char* buff = strcpy(new char[strlen(templ) + 1], templ);
202     int fd = Sys::mkstemp(buff);
203     tmpl = buff;
204     delete [] buff;
205     if (fd >= 0) {
206 	int cc;
207 	char buf[16*1024];
208     while ((cc = Sys::read(fin, buf, sizeof (buf))) > 0) {
209         if (Sys::write(fd, buf, cc) != cc) {
210             Sys::unlink(tmpl);
211             fatal("%s: write error", (const char*) tmpl);
212         }
213     }
214 	Sys::close(fd);
215     } else
216 	fatal(_("%s: Can not create temporary file"), (const char*) tmpl);
217 }
218 
219 void
vprintError(const char * fmt,va_list ap)220 sendPageApp::vprintError(const char* fmt, va_list ap)
221 {
222     fprintf(stderr, "%s: ", (const char*) appName);
223     SNPPClient::vprintError(fmt, ap);
224 }
225 
226 void
vprintWarning(const char * fmt,va_list ap)227 sendPageApp::vprintWarning(const char* fmt, va_list ap)
228 {
229     fprintf(stderr, "%s: ", (const char*) appName);
230     SNPPClient::vprintWarning(fmt, ap);
231 }
232 
233 #include <signal.h>
234 
235 static	sendPageApp* app = NULL;
236 
237 static void
cleanup()238 cleanup()
239 {
240     sendPageApp* a = app;
241     app = NULL;
242     delete a;
243 }
244 
245 static void
sigDone(int)246 sigDone(int)
247 {
248     cleanup();
249     exit(-1);
250 }
251 
252 int
main(int argc,char ** argv)253 main(int argc, char** argv)
254 {
255 #ifdef LC_CTYPE
256     setlocale(LC_CTYPE, "");			// for <ctype.h> calls
257 #endif
258 #ifdef LC_TIME
259     setlocale(LC_TIME, "");			// for strftime calls
260 #endif
261     NLS::Setup("hylafax-client");
262     signal(SIGHUP, fxSIGHANDLER(sigDone));
263     signal(SIGINT, fxSIGHANDLER(sigDone));
264     signal(SIGTERM, fxSIGHANDLER(sigDone));
265     signal(SIGCHLD, fxSIGHANDLER(SIG_DFL));    // by YC
266     app = new sendPageApp;
267     if (!app->run(argc, argv))
268 	sigDone(0);
269     signal(SIGHUP, fxSIGHANDLER(SIG_IGN));
270     signal(SIGINT, fxSIGHANDLER(SIG_IGN));
271     signal(SIGTERM, fxSIGHANDLER(SIG_IGN));
272     cleanup();
273     return (0);
274 }
275 
276 static void
vfatal(FILE * fd,const char * fmt,va_list ap)277 vfatal(FILE* fd, const char* fmt, va_list ap)
278 {
279     vfprintf(fd, fmt, ap);
280     va_end(ap); //???
281     fputs(".\n", fd);
282     sigDone(0);
283 }
284 
285 void
fxFatal(const char * va_alist...)286 fxFatal(const char* va_alist ...)
287 #define	fmt va_alist
288 {
289     va_list ap;
290     va_start(ap, fmt);
291     vfatal(stderr, fmt, ap);
292     /*NOTREACHED*/
293 }
294 #undef fmt
295 
296 void
fatal(const char * va_alist...)297 sendPageApp::fatal(const char* va_alist ...)
298 #define	fmt va_alist
299 {
300     fprintf(stderr, "%s: ", (const char*) appName);
301     va_list ap;
302     va_start(ap, fmt);
303     vfatal(stderr, fmt, ap);
304     /*NOTREACHED*/
305 }
306 #undef fmt
307