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