dtprintinfo: correct another possible buffer overflow
[oweals/cde.git] / cde / programs / dtprintinfo / objects / PrintObj / Queue.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: Queue.C /main/4 1998/07/24 16:17:58 mgreess $ */
24 /*                                                                      *
25  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
26  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
27  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
28  * (c) Copyright 1993, 1994 Novell, Inc.                                *
29  */
30
31 #include "Queue.h"
32 #include "PrintJob.h"
33 #include "ParseJobs.h"
34 #include <stdlib.h>
35
36 extern "C" {
37 #include <Dt/DtNlUtils.h>
38 }
39
40 #ifdef aix
41 const char *GET_ATTRS = "lsque -cq%s |awk -F: 'NR == 2 {print $2,$6,$9}' OFS=:";
42 const char *GET_QUEUE_STATUS = "LANG=C enq -As -P%s | "
43                                "egrep 'READY|RUNNING' > /dev/null";
44 const char *GET_DEVICE_STATUS = "LANG=C enq -As -P%s | "
45                                 "egrep 'READY|RUNNING' > /dev/null";
46 const char *START_QUEUE_CMD = "enq -U -P%s";
47 const char *STOP_QUEUE_CMD = "enq -D -P%s";
48 #else
49 #ifdef hpux
50 const char *GET_ATTRS = "LANG=C lpstat -v%s 2>&1 | awk '"
51                             "BEGIN { device=\"\"; rhost=\"\"; rp=\"\" } "
52                             "/device for/ { device = $4 } "
53                             "/remote to/ { rhost = $5; rp = $3 } "
54                             "END { print device,rhost,rp }' OFS=:";
55 const char *GET_QUEUE_STATUS = "LANG=C lpstat -i -a%s | awk '"
56                                "{if ($2 == \"not\") {exit 1} else {exit 0}}'";
57 const char *GET_DEVICE_STATUS = "LANG=C lpstat -i -p%s | "
58                                 "awk '/disabled/ {exit 1}'";
59 const char *START_QUEUE_CMD = "/usr/lib/accept %s";
60 const char *STOP_QUEUE_CMD = "/usr/lib/reject %s";
61 const char *START_PRINTING_CMD = "enable %s";
62 const char *STOP_PRINTING_CMD = "disable %s";
63 #else
64 const char *GET_ATTRS = "LANG=C lpstat -v %s 2>&1 | nawk '"
65                             "BEGIN { device=\"\"; rhost=\"\"; rp=\"\" } "
66                             "/device for/ { device = $4 } "
67                             "/system for/ { rhost = $4; x = match($7, /\\)/); "
68                             "               if (x == 0) "
69                             "                  rp = substr($3, 1, match($3, /:/) - 1); "
70                             "               else "
71                             "                  rp = substr($7, 1, x - 1) } "
72                             "END { print device,rhost,rp }' OFS=:";
73 const char *GET_QUEUE_STATUS = "LANG=C lpstat -a%s | awk '"
74                                "{if ($2 == \"not\") {exit 1} else {exit 0}}'";
75 const char *GET_DEVICE_STATUS = "LANG=C lpstat -p%s | "
76                                 "awk '/disabled/ {exit 1}'";
77 const char *START_QUEUE_CMD = "/usr/sbin/accept %s";
78 const char *STOP_QUEUE_CMD = "/usr/sbin/reject %s";
79 const char *START_PRINTING_CMD = "enable %s";
80 const char *STOP_PRINTING_CMD = "disable %s";
81 #endif
82 #endif
83
84 // Object Class Name
85 const char *QUEUE = "Queue";
86
87 // Actions
88 const char *START_QUEUE            = "StartQueue";
89 const char *STOP_QUEUE             = "StopQueue";
90 #ifndef aix
91 const char *START_PRINTING         = "StartPrinting";
92 const char *STOP_PRINTING          = "StopPrinting";
93 #endif
94
95 // Attributes
96 const char *ICON_NAME              = "IconName";
97 const char *PRINTER_QUEUE          = "PrinterQueue";
98 const char *QUEUE_DEVICE           = "QueueDevice";
99
100 Queue::Queue(BaseObj *parent,
101              char *_name)
102         : BaseObj(parent, _name)
103 {
104  if (getenv("DO_ADMIN"))
105   {
106    AddAction(&Queue::Start, START_QUEUE, MESSAGE(StartChoiceL),
107              MESSAGE(StartMnemonicL));
108    AddAction(&Queue::Stop, STOP_QUEUE, MESSAGE(StopChoiceL),
109              MESSAGE(StopMnemonicL));
110 #ifndef aix
111    AddAction(&Queue::StartPrint, START_PRINTING, MESSAGE(EnableChoiceL),
112              MESSAGE(EnableMnemonicL));
113    AddAction(&Queue::StopPrint, STOP_PRINTING, MESSAGE(DisableChoiceL),
114              MESSAGE(DisableMnemonicL));
115 #endif
116   }
117
118 #ifdef aix
119    local_devices = NULL;
120    n_devices = 0;
121 #endif
122    remote_server = NULL;
123    remote_printer = NULL;
124    is_remote = false;
125    _loaded_attributes = false;
126
127    char *Help = NULL, *ContextualHelp = NULL, *Listing = NULL;
128    Characteristics Mask = EDITABLE_AFTER_CREATE;
129    ValueList ValueListType = NO_LIST;
130
131    // AddAttribute(ICON_NAME, MESSAGE(IconNameL),
132                 // Help, ContextualHelp, Mask, ValueListType, Listing);
133
134    Mask = OPTIONAL;
135    AddAttribute(PRINTER_QUEUE, MESSAGE(PrintQueueL),
136                 Help, ContextualHelp, Mask, ValueListType, Listing);
137    AddAttribute(QUEUE_DEVICE, MESSAGE(DeviceL), 
138                 Help, ContextualHelp, Mask, ValueListType, Listing);
139 }
140
141 Queue::~Queue()
142 {
143 #ifdef aix
144    int i;
145    for (i = 0; i < n_devices; i++)
146       delete local_devices[i];
147    delete local_devices;
148 #endif
149    delete remote_server;
150    delete remote_printer;
151 }
152
153 void Queue::LoadAttributes(int /*n_attrs*/, Attribute **attrs)
154 {
155    char *command = new char[500];
156    sprintf(command, GET_ATTRS, Name());
157    char *output;
158    RunCommand(command, &output);
159    delete [] command;
160
161    char *s = output, *s1;
162    char *dollar[3];
163    int i;
164    for (i = 0; i < 3; i++)
165     {
166       if (s1 = strchr(s, ':'))
167          *s1++ = '\0';
168       else if (s1 = strchr(s, '\n'))
169          *s1++ = '\0';
170       dollar[i] = s;
171       s = s1;
172     }
173    i = 0;
174    attrs[i]->Value = strdup(Name());
175    attrs[i]->DisplayValue = strdup(Name());
176    i++;
177    if (_loaded_attributes == false)
178     {
179       if (*dollar[2]) // It's a remote printer
180        {
181 #ifdef aix
182          n_devices = 1;
183          local_devices = new char *[1];
184          local_devices[0] = new char[strlen(Name()) + strlen(dollar[0]) + 2];
185          sprintf(local_devices[0], "%s:%s", Name(), dollar[0]);
186 #endif
187          is_remote = true;
188          char *new_value = new char [strlen(MESSAGE(PrinterOnServerL)) + 
189                                      strlen(dollar[1]) + strlen(dollar[2])];
190          remote_server = strdup(dollar[1]);
191          remote_printer = strdup(dollar[2]);
192          sprintf(new_value, MESSAGE(PrinterOnServerL), remote_printer, 
193                  remote_server);
194          attrs[i]->Value = strdup(new_value);
195          attrs[i]->DisplayValue = strdup(new_value);
196          delete [] new_value;
197        }
198       else // It's a local printer
199        {
200 #ifdef aix
201          if (strchr(dollar[0], ',')) // AIX can have multiple devices per queue
202           {
203             DeleteAttribute(QUEUE_DEVICE);
204             char *device = new char [strlen(MESSAGE(DeviceNL)) + 4];
205             s = dollar[0];
206             while (s && *s)
207              {
208                if (s1 = strchr(s, ','))
209                   s1++;
210                s = s1;
211                n_devices++;
212              }
213             local_devices = new char *[n_devices];
214             n_devices = 0;
215             s = dollar[0];
216             while (s && *s)
217              {
218                sprintf(device, MESSAGE(DeviceNL), n_devices + 1);
219                AddAttribute(QUEUE_DEVICE, device,
220                             NULL, NULL, OPTIONAL, NO_LIST, NULL);
221                if (s1 = strchr(s, ','))
222                   *s1++ = '\0';
223                _attributes[i]->Value = strdup(s);
224                _attributes[i]->DisplayValue = strdup(s);
225                local_devices[n_devices] = new char[strlen(Name()) + strlen(s)+2];
226                sprintf(local_devices[n_devices], "%s:%s", Name(), s);
227                i++;
228                s = s1;
229                n_devices++;
230              }
231             delete [] device;
232           }
233          else
234 #endif
235           {
236 #ifdef aix
237             n_devices = 1;
238             local_devices = new char *[1];
239             local_devices[0] = new char[strlen(Name()) + strlen(dollar[0]) + 2];
240             sprintf(local_devices[0], "%s:%s", Name(), dollar[0]);
241
242 #endif
243             attrs[i]->Value = strdup(dollar[0]);
244             attrs[i]->DisplayValue = strdup(dollar[0]);
245           }
246        }
247       _loaded_attributes = true;
248     }
249    delete output;
250 }
251
252 #ifdef aix
253 char *Queue::Device(int index)
254 {
255    if (_loaded_attributes == false)
256       ReadAttributes();
257    if (index >= 0 && index <= n_devices)
258       return local_devices[index];
259    else
260       return NULL;
261 }
262
263 int Queue::NumberDevices()
264 {
265    if (_loaded_attributes == false)
266       ReadAttributes();
267    return n_devices;
268 }
269
270 #endif
271
272 int Queue::Start(BaseObj *obj, char **output, BaseObj * /*requestor*/)
273 {
274    Queue *queue = (Queue *)obj;
275    int rc;
276    char *command = new char[100];
277
278 #ifdef aix
279    if (queue->n_devices > 1)
280     {
281       sprintf(command, START_QUEUE_CMD, "$d");
282       int i, len;
283       len = 30 + strlen(command) + queue->n_devices;
284       for (i = 0; i < queue->n_devices; i++)
285          len += strlen(queue->local_devices[i]);
286       char *cmd = new char[len];
287       strcpy(cmd, "for d in");
288       for (i = 0; i < queue->n_devices; i++)
289        {
290          strcat(cmd, " ");
291          strcat(cmd, queue->local_devices[i]);
292        }
293       strcat(cmd, " ; do ");
294       strcat(cmd, command);
295       strcat(cmd, "; done");
296       rc = queue->RunCommand(cmd, NULL, output);
297       delete [] cmd;
298     }
299    else
300 #endif
301     {
302       sprintf(command, START_QUEUE_CMD, queue->Name());
303       rc = queue->RunCommand(command, NULL, output);
304     }
305     delete [] command;
306     return rc;
307 }
308
309 int Queue::Stop(BaseObj *obj, char **output, BaseObj * /*requestor*/)
310 {
311    Queue *queue = (Queue *)obj;
312    char *command = new char[100];
313    int rc;
314
315 #ifdef aix
316    if (queue->n_devices > 1)
317     {
318       sprintf(command, STOP_QUEUE_CMD, "$d");
319       int i, len;
320       len = 30 + strlen(command) + queue->n_devices;
321       for (i = 0; i < queue->n_devices; i++)
322          len += strlen(queue->local_devices[i]);
323       char *cmd = new char[len];
324       strcpy(cmd, "for d in");
325       for (i = 0; i < queue->n_devices; i++)
326        {
327          strcat(cmd, " ");
328          strcat(cmd, queue->local_devices[i]);
329        }
330       strcat(cmd, " ; do ");
331       strcat(cmd, command);
332       strcat(cmd, "; done");
333       rc = queue->RunCommand(cmd, NULL, output);
334       delete [] cmd;
335     }
336    else
337 #endif
338     {
339         snprintf(command, 100, STOP_QUEUE_CMD, queue->Name());
340       rc = queue->RunCommand(command, NULL, output);
341     }
342     delete [] command;
343     return rc;
344 }
345
346 #ifndef aix
347 int Queue::StartPrint(BaseObj *obj, char **output, BaseObj * /*requestor*/)
348 {
349    Queue *queue = (Queue *)obj;
350    char *command = new char[100];
351    int rc;
352
353    sprintf(command, STOP_PRINTING_CMD, queue->Name());
354    rc = queue->RunCommand(command, NULL, output);
355    delete [] command;
356    return rc;
357 }
358
359 int Queue::StopPrint(BaseObj *obj, char **output, BaseObj * /*requestor*/)
360 {
361    Queue *queue = (Queue *)obj;
362    char *command = new char[100];
363    int rc;
364
365    sprintf(command, STOP_PRINTING_CMD, queue->Name());
366    rc = queue->RunCommand(command, NULL, output);
367    delete [] command;
368    return rc;
369 }
370 #endif
371
372 void Queue::InitChildren()
373 {
374    if (_loaded_attributes == false)
375       ReadAttributes();
376    ProcessJobs();
377 }
378
379 void Queue::ProcessJobs(char *jobs)
380 {
381    char *job_list;
382    int n_jobs;
383
384    // Get remote jobs first
385    if (is_remote)
386     {
387       int rc;
388       if (jobs)
389          rc = ParseRemotePrintJobs(remote_printer, jobs, &job_list, &n_jobs);
390       else
391          rc = RemotePrintJobs(remote_server, remote_printer, &job_list,
392                               &n_jobs);
393       remote_up = rc ? true : false;
394
395       ParseOutput(job_list, n_jobs);
396 #ifdef sun
397       return;
398 #endif
399     }
400
401    // Get local jobs next
402 #ifdef aix
403    if (is_remote)
404       LocalPrintJobs(local_devices[0], &job_list, &n_jobs);
405    else
406       LocalPrintJobs((char*)Name(), &job_list, &n_jobs);
407 #else
408    LocalPrintJobs((char*)Name(), &job_list, &n_jobs);
409 #endif
410    ParseOutput(job_list, n_jobs);
411 }
412
413 void Queue::ParseOutput(char *job_list, int n_jobs)
414 {
415    int i;
416    char *printer = DtStrtok(job_list, "|");
417    for (i = 0; i < n_jobs; i++)
418     {
419       char *JobName = DtStrtok(NULL, "|");
420       char *JobNumber = DtStrtok(NULL, "|");
421       char *Owner = DtStrtok(NULL, "|");
422       char *Date = DtStrtok(NULL, "|");
423       char *Time = DtStrtok(NULL, "|");
424       char *tmp = DtStrtok(NULL, "\n");
425       char *Size = new char [strlen(tmp) + strlen(MESSAGE(BytesL)) + 2];
426       sprintf(Size, "%s %s", tmp, MESSAGE(BytesL));
427
428       new PrintJob(this, JobName, JobNumber, Owner, Date, Time, Size);
429       delete [] Size;
430       printer = DtStrtok(NULL, "|");
431     }
432 }
433
434 void Queue::ParseRemoteStatus(char *output)
435 {
436    SetInitChildren();
437    DeleteChildren();
438    if (_loaded_attributes == false)
439       ReadAttributes();
440    ProcessJobs(output);
441 }
442
443 boolean Queue::IsRemote()
444 {
445    if (_loaded_attributes == false)
446       ReadAttributes();
447    return is_remote;
448 }
449
450 const char *Queue::RemotePrinter()
451 {
452    if (_loaded_attributes == false)
453       ReadAttributes();
454    return remote_printer;
455 }
456
457 const char *Queue::Server()
458 {
459    if (_loaded_attributes == false)
460       ReadAttributes();
461    return remote_server;
462 }