]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_select.c
f0917070932c192e7f6fb969d52401e52aecf72d
[bacula/bacula] / bacula / src / dird / ua_select.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2015 Kern Sibbald
5
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    This notice must be preserved when any source code is 
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  *
21  *   Bacula Director -- User Agent Prompt and Selection code
22  *
23  *     Kern Sibbald, October MMI
24  *
25  */
26
27 #include "bacula.h"
28 #include "dird.h"
29
30 /* Imported variables */
31 extern struct s_jl joblevels[];
32
33 int confirm_retention_yesno(UAContext *ua, utime_t ret, const char *msg)
34 {
35    char ed1[100];
36    int val;
37
38    /* Look for "yes" in command line */
39    if (find_arg(ua, NT_("yes")) != -1) {
40       return 1;
41    }
42
43    for ( ;; ) {
44        ua->info_msg(_("The current %s retention period is: %s\n"),
45           msg, edit_utime(ret, ed1, sizeof(ed1)));
46        if (!get_cmd(ua, _("Continue? (yes/no): "))) {
47           return 0;
48        }
49        if (is_yesno(ua->cmd, &val)) {
50           return val;           /* is 1 for yes, 0 for no */
51        }
52     }
53     return 1;
54 }
55
56 /*
57  * Confirm a retention period
58  */
59 int confirm_retention(UAContext *ua, utime_t *ret, const char *msg)
60 {
61    char ed1[100];
62    int val;
63
64    /* Look for "yes" in command line */
65    if (find_arg(ua, NT_("yes")) != -1) {
66       return 1;
67    }
68
69    for ( ;; ) {
70        ua->info_msg(_("The current %s retention period is: %s\n"),
71           msg, edit_utime(*ret, ed1, sizeof(ed1)));
72
73        if (!get_cmd(ua, _("Continue? (yes/mod/no): "))) {
74           return 0;
75        }
76        if (strcasecmp(ua->cmd, _("mod")) == 0) {
77           if (!get_cmd(ua, _("Enter new retention period: "))) {
78              return 0;
79           }
80           if (!duration_to_utime(ua->cmd, ret)) {
81              ua->error_msg(_("Invalid period.\n"));
82              continue;
83           }
84           continue;
85        }
86        if (is_yesno(ua->cmd, &val)) {
87           return val;           /* is 1 for yes, 0 for no */
88        }
89     }
90     return 1;
91 }
92
93 /*
94  * Given a list of keywords, find the first one
95  *  that is in the argument list.
96  * Returns: -1 if not found
97  *          index into list (base 0) on success
98  */
99 int find_arg_keyword(UAContext *ua, const char **list)
100 {
101    for (int i=1; i<ua->argc; i++) {
102       for(int j=0; list[j]; j++) {
103          if (strcasecmp(list[j], ua->argk[i]) == 0) {
104             return j;
105          }
106       }
107    }
108    return -1;
109 }
110
111 /*
112  * Given one keyword, find the first one that
113  *   is in the argument list.
114  * Returns: argk index (always gt 0)
115  *          -1 if not found
116  */
117 int find_arg(UAContext *ua, const char *keyword)
118 {
119    for (int i=1; i<ua->argc; i++) {
120       if (strcasecmp(keyword, ua->argk[i]) == 0) {
121          return i;
122       }
123    }
124    return -1;
125 }
126
127 /*
128  * Given a single keyword, find it in the argument list, but
129  *   it must have a value
130  * Returns: -1 if not found or no value
131  *           list index (base 0) on success
132  */
133 int find_arg_with_value(UAContext *ua, const char *keyword)
134 {
135    for (int i=1; i<ua->argc; i++) {
136       if (strcasecmp(keyword, ua->argk[i]) == 0) {
137          if (ua->argv[i]) {
138             return i;
139          } else {
140             return -1;
141          }
142       }
143    }
144    return -1;
145 }
146
147 /*
148  * Given a list of keywords, prompt the user
149  * to choose one.
150  *
151  * Returns: -1 on failure
152  *          index into list (base 0) on success
153  */
154 int do_keyword_prompt(UAContext *ua, const char *msg, const char **list)
155 {
156    int i;
157    start_prompt(ua, _("You have the following choices:\n"));
158    for (i=0; list[i]; i++) {
159       add_prompt(ua, list[i]);
160    }
161    return do_prompt(ua, "", msg, NULL, 0);
162 }
163
164
165 /*
166  * Select a Storage resource from prompt list
167  *  If unique is set storage resources that have the main address are
168  *   combined into one (i.e. they are all part of the same)
169  *   storage.  Note, not all commands want this.
170  */
171 STORE *select_storage_resource(UAContext *ua, bool unique)
172 {
173    char name[MAX_NAME_LENGTH];
174    STORE *store;
175
176    /* Does user want a full selection? */
177    if (unique && find_arg(ua, NT_("select")) > 0) {
178       unique = false;
179    }
180    start_prompt(ua, _("The defined Storage resources are:\n"));
181    LockRes();
182    foreach_res(store, R_STORAGE) {
183       if (acl_access_ok(ua, Storage_ACL, store->name())) {
184          if (unique) {
185             add_prompt(ua, store->name(), store->address);
186          } else {
187             add_prompt(ua, store->name());
188          }
189       }
190    }
191    UnlockRes();
192    if (do_prompt(ua, _("Storage"),  _("Select Storage resource"), name, sizeof(name)) < 0) {
193       return NULL;
194    }
195    store = (STORE *)GetResWithName(R_STORAGE, name);
196    return store;
197 }
198
199 /*
200  * Select a FileSet resource from prompt list
201  */
202 FILESET *select_fileset_resource(UAContext *ua)
203 {
204    char name[MAX_NAME_LENGTH];
205    FILESET *fs;
206
207    start_prompt(ua, _("The defined FileSet resources are:\n"));
208    LockRes();
209    foreach_res(fs, R_FILESET) {
210       if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
211          add_prompt(ua, fs->name());
212       }
213    }
214    UnlockRes();
215    if (do_prompt(ua, _("FileSet"), _("Select FileSet resource"), name, sizeof(name)) < 0) {
216       return NULL;
217    }
218    fs = (FILESET *)GetResWithName(R_FILESET, name);
219    return fs;
220 }
221
222
223 /*
224  * Get a catalog resource from prompt list
225  */
226 CAT *get_catalog_resource(UAContext *ua)
227 {
228    char name[MAX_NAME_LENGTH];
229    CAT *catalog = NULL;
230    int i;
231
232    for (i=1; i<ua->argc; i++) {
233       if (strcasecmp(ua->argk[i], NT_("catalog")) == 0 && ua->argv[i]) {
234          if (acl_access_ok(ua, Catalog_ACL, ua->argv[i])) {
235             catalog = (CAT *)GetResWithName(R_CATALOG, ua->argv[i]);
236             break;
237          }
238       }
239    }
240    if (ua->gui && !catalog) {
241       LockRes();
242       catalog = (CAT *)GetNextRes(R_CATALOG, NULL);
243       UnlockRes();
244       if (!catalog) {
245          ua->error_msg(_("Could not find a Catalog resource\n"));
246          return NULL;
247       } else if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
248          ua->error_msg(_("You must specify a \"use <catalog-name>\" command before continuing.\n"));
249          return NULL;
250       }
251       return catalog;
252    }
253    if (!catalog) {
254       start_prompt(ua, _("The defined Catalog resources are:\n"));
255       LockRes();
256       foreach_res(catalog, R_CATALOG) {
257          if (acl_access_ok(ua, Catalog_ACL, catalog->name())) {
258             add_prompt(ua, catalog->name());
259          }
260       }
261       UnlockRes();
262       if (do_prompt(ua, _("Catalog"),  _("Select Catalog resource"), name, sizeof(name)) < 0) {
263          return NULL;
264       }
265       catalog = (CAT *)GetResWithName(R_CATALOG, name);
266    }
267    return catalog;
268 }
269
270
271 /*
272  * Select a job to enable or disable
273  */
274 JOB *select_enable_disable_job_resource(UAContext *ua, bool enable)
275 {
276    char name[MAX_NAME_LENGTH];
277    JOB *job;
278
279    LockRes();
280    if (enable) {
281       start_prompt(ua, _("The disabled Job resources are:\n"));
282    } else {
283       start_prompt(ua, _("The enabled Job resources are:\n"));
284    }
285    foreach_res(job, R_JOB) {
286       if (!acl_access_ok(ua, Job_ACL, job->name())) {
287          continue;
288       }
289       if (job->enabled == enable) {   /* Already enabled/disabled? */
290          continue;                    /* yes, skip */
291       }
292       add_prompt(ua, job->name());
293    }
294    UnlockRes();
295    if (do_prompt(ua, _("Job"), _("Select Job resource"), name, sizeof(name)) < 0) {
296       return NULL;
297    }
298    job = (JOB *)GetResWithName(R_JOB, name);
299    return job;
300 }
301
302 /*
303  * Select a Job resource from prompt list
304  */
305 JOB *select_job_resource(UAContext *ua)
306 {
307    char name[MAX_NAME_LENGTH];
308    JOB *job;
309
310    start_prompt(ua, _("The defined Job resources are:\n"));
311    LockRes();
312    foreach_res(job, R_JOB) {
313       if (acl_access_ok(ua, Job_ACL, job->name())) {
314          add_prompt(ua, job->name());
315       }
316    }
317    UnlockRes();
318    if (do_prompt(ua, _("Job"), _("Select Job resource"), name, sizeof(name)) < 0) {
319       return NULL;
320    }
321    job = (JOB *)GetResWithName(R_JOB, name);
322    return job;
323 }
324
325 /*
326  * Select a Restore Job resource from argument or prompt
327  */
328 JOB *get_restore_job(UAContext *ua)
329 {
330    JOB *job;
331    int i = find_arg_with_value(ua, "restorejob");
332    if (i >= 0 && acl_access_ok(ua, Job_ACL, ua->argv[i])) {
333       job = (JOB *)GetResWithName(R_JOB, ua->argv[i]);
334       if (job && job->JobType == JT_RESTORE) {
335          return job;
336       }
337       ua->error_msg(_("Error: Restore Job resource \"%s\" does not exist.\n"),
338                     ua->argv[i]);
339    }
340    return select_restore_job_resource(ua);
341 }
342
343 /*
344  * Select a Restore Job resource from prompt list
345  */
346 JOB *select_restore_job_resource(UAContext *ua)
347 {
348    char name[MAX_NAME_LENGTH];
349    JOB *job;
350
351    start_prompt(ua, _("The defined Restore Job resources are:\n"));
352    LockRes();
353    foreach_res(job, R_JOB) {
354       if (job->JobType == JT_RESTORE && acl_access_ok(ua, Job_ACL, job->name())) {
355          add_prompt(ua, job->name());
356       }
357    }
358    UnlockRes();
359    if (do_prompt(ua, _("Job"), _("Select Restore Job"), name, sizeof(name)) < 0) {
360       return NULL;
361    }
362    job = (JOB *)GetResWithName(R_JOB, name);
363    return job;
364 }
365
366 /*
367  * Select a client to enable or disable
368  */
369 CLIENT *select_enable_disable_client_resource(UAContext *ua, bool enable)
370 {
371    char name[MAX_NAME_LENGTH];
372    CLIENT *client;
373
374    LockRes();
375    start_prompt(ua, _("The defined Client resources are:\n"));
376    foreach_res(client, R_CLIENT) {
377       if (!acl_access_ok(ua, Client_ACL, client->name())) {
378          continue;
379       }
380       if (client->enabled == enable) {   /* Already enabled/disabled? */
381          continue;                       /* yes, skip */
382       }
383       add_prompt(ua, client->name());
384    }
385    UnlockRes();
386    if (do_prompt(ua, _("Client"), _("Select Client resource"), name, sizeof(name)) < 0) {
387       return NULL;
388    }
389    client = (CLIENT *)GetResWithName(R_CLIENT, name);
390    return client;
391 }
392
393
394 /*
395  * Select a client resource from prompt list
396  */
397 CLIENT *select_client_resource(UAContext *ua)
398 {
399    char name[MAX_NAME_LENGTH];
400    CLIENT *client;
401
402    start_prompt(ua, _("The defined Client resources are:\n"));
403    LockRes();
404    foreach_res(client, R_CLIENT) {
405       if (acl_access_ok(ua, Client_ACL, client->name())) {
406          add_prompt(ua, client->name());
407       }
408    }
409    UnlockRes();
410    if (do_prompt(ua, _("Client"),  _("Select Client (File daemon) resource"), name, sizeof(name)) < 0) {
411       return NULL;
412    }
413    client = (CLIENT *)GetResWithName(R_CLIENT, name);
414    return client;
415 }
416
417 /*
418  *  Get client resource, start by looking for
419  *   client=<client-name>
420  *  if we don't find the keyword, we prompt the user.
421  */
422 CLIENT *get_client_resource(UAContext *ua)
423 {
424    CLIENT *client = NULL;
425    int i;
426
427    for (i=1; i<ua->argc; i++) {
428       if ((strcasecmp(ua->argk[i], NT_("client")) == 0 ||
429            strcasecmp(ua->argk[i], NT_("fd")) == 0) && ua->argv[i]) {
430          if (!acl_access_ok(ua, Client_ACL, ua->argv[i])) {
431             break;
432          }
433          client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
434          if (client) {
435             return client;
436          }
437          ua->error_msg(_("Error: Client resource %s does not exist.\n"), ua->argv[i]);
438          break;
439       }
440    }
441    return select_client_resource(ua);
442 }
443
444 /*
445  * Select a schedule to enable or disable
446  */
447 SCHED *select_enable_disable_schedule_resource(UAContext *ua, bool enable)
448 {
449    char name[MAX_NAME_LENGTH];
450    SCHED *sched;
451
452    LockRes();
453    start_prompt(ua, _("The defined Schedule resources are:\n"));
454    foreach_res(sched, R_SCHEDULE) {
455       if (!acl_access_ok(ua, Schedule_ACL, sched->name())) {
456          continue;
457       }
458       if (sched->enabled == enable) {   /* Already enabled/disabled? */
459          continue;                      /* yes, skip */
460       }
461       add_prompt(ua, sched->name());
462    }
463    UnlockRes();
464    if (do_prompt(ua, _("Schedule"), _("Select Schedule resource"), name, sizeof(name)) < 0) {
465       return NULL;
466    }
467    sched = (SCHED *)GetResWithName(R_SCHEDULE, name);
468    return sched;
469 }
470
471
472 /* Scan what the user has entered looking for:
473  *
474  *  client=<client-name>
475  *
476  *  if error or not found, put up a list of client DBRs
477  *  to choose from.
478  *
479  *   returns: 0 on error
480  *            1 on success and fills in CLIENT_DBR
481  */
482 bool get_client_dbr(UAContext *ua, CLIENT_DBR *cr)
483 {
484    int i;
485
486    if (cr->Name[0]) {                 /* If name already supplied */
487       if (db_get_client_record(ua->jcr, ua->db, cr)) {
488          return 1;
489       }
490       ua->error_msg(_("Could not find Client %s: ERR=%s"), cr->Name, db_strerror(ua->db));
491    }
492    for (i=1; i<ua->argc; i++) {
493       if ((strcasecmp(ua->argk[i], NT_("client")) == 0 ||
494            strcasecmp(ua->argk[i], NT_("fd")) == 0) && ua->argv[i]) {
495          if (!acl_access_ok(ua, Client_ACL, ua->argv[i])) {
496             break;
497          }
498          bstrncpy(cr->Name, ua->argv[i], sizeof(cr->Name));
499          if (!db_get_client_record(ua->jcr, ua->db, cr)) {
500             ua->error_msg(_("Could not find Client \"%s\": ERR=%s"), ua->argv[i],
501                      db_strerror(ua->db));
502             cr->ClientId = 0;
503             break;
504          }
505          return 1;
506       }
507    }
508    if (!select_client_dbr(ua, cr)) {  /* try once more by proposing a list */
509       return 0;
510    }
511    return 1;
512 }
513
514 /*
515  * Select a Client record from the catalog
516  *  Returns 1 on success
517  *          0 on failure
518  */
519 bool select_client_dbr(UAContext *ua, CLIENT_DBR *cr)
520 {
521    CLIENT_DBR ocr;
522    char name[MAX_NAME_LENGTH];
523    int num_clients, i;
524    uint32_t *ids;
525
526
527    cr->ClientId = 0;
528    if (!db_get_client_ids(ua->jcr, ua->db, &num_clients, &ids)) {
529       ua->error_msg(_("Error obtaining client ids. ERR=%s\n"), db_strerror(ua->db));
530       return 0;
531    }
532    if (num_clients <= 0) {
533       ua->error_msg(_("No clients defined. You must run a job before using this command.\n"));
534       return 0;
535    }
536
537    start_prompt(ua, _("Defined Clients:\n"));
538    for (i=0; i < num_clients; i++) {
539       ocr.ClientId = ids[i];
540       if (!db_get_client_record(ua->jcr, ua->db, &ocr) ||
541           !acl_access_ok(ua, Client_ACL, ocr.Name)) {
542          continue;
543       }
544       add_prompt(ua, ocr.Name);
545    }
546    free(ids);
547    if (do_prompt(ua, _("Client"),  _("Select the Client"), name, sizeof(name)) < 0) {
548       return 0;
549    }
550    memset(&ocr, 0, sizeof(ocr));
551    bstrncpy(ocr.Name, name, sizeof(ocr.Name));
552
553    if (!db_get_client_record(ua->jcr, ua->db, &ocr)) {
554       ua->error_msg(_("Could not find Client \"%s\": ERR=%s"), name, db_strerror(ua->db));
555       return 0;
556    }
557    memcpy(cr, &ocr, sizeof(ocr));
558    return 1;
559 }
560
561 /* Scan what the user has entered looking for:
562  *
563  *  argk=<pool-name>
564  *
565  *  where argk can be : pool, recyclepool, scratchpool, nextpool etc..
566  *
567  *  if error or not found, put up a list of pool DBRs
568  *  to choose from.
569  *
570  *   returns: false on error
571  *            true  on success and fills in POOL_DBR
572  */
573 bool get_pool_dbr(UAContext *ua, POOL_DBR *pr, const char *argk)
574 {
575    if (pr->Name[0]) {                 /* If name already supplied */
576       if (db_get_pool_numvols(ua->jcr, ua->db, pr) &&
577           acl_access_ok(ua, Pool_ACL, pr->Name)) {
578          return true;
579       }
580       ua->error_msg(_("Could not find Pool \"%s\": ERR=%s"), pr->Name, db_strerror(ua->db));
581    }
582    if (!select_pool_dbr(ua, pr, argk)) {  /* try once more */
583       return false;
584    }
585    return true;
586 }
587
588 /*
589  * Select a Pool record from catalog
590  * argk can be pool, recyclepool, scratchpool etc..
591  */
592 bool select_pool_dbr(UAContext *ua, POOL_DBR *pr, const char *argk)
593 {
594    POOL_DBR opr;
595    char name[MAX_NAME_LENGTH];
596    int num_pools, i;
597    uint32_t *ids;
598
599    for (i=1; i<ua->argc; i++) {
600       if (strcasecmp(ua->argk[i], argk) == 0 && ua->argv[i] &&
601           acl_access_ok(ua, Pool_ACL, ua->argv[i])) {
602          bstrncpy(pr->Name, ua->argv[i], sizeof(pr->Name));
603          if (!db_get_pool_numvols(ua->jcr, ua->db, pr)) {
604             ua->error_msg(_("Could not find Pool \"%s\": ERR=%s"), ua->argv[i],
605                      db_strerror(ua->db));
606             pr->PoolId = 0;
607             break;
608          }
609          return true;
610       }
611    }
612
613    pr->PoolId = 0;
614    if (!db_get_pool_ids(ua->jcr, ua->db, &num_pools, &ids)) {
615       ua->error_msg(_("Error obtaining pool ids. ERR=%s\n"), db_strerror(ua->db));
616       return 0;
617    }
618    if (num_pools <= 0) {
619       ua->error_msg(_("No pools defined. Use the \"create\" command to create one.\n"));
620       return false;
621    }
622
623    start_prompt(ua, _("Defined Pools:\n"));
624    if (bstrcmp(argk, NT_("recyclepool"))) {
625       add_prompt(ua, _("*None*"));
626    }
627    for (i=0; i < num_pools; i++) {
628       opr.PoolId = ids[i];
629       if (!db_get_pool_numvols(ua->jcr, ua->db, &opr) ||
630           !acl_access_ok(ua, Pool_ACL, opr.Name)) {
631          continue;
632       }
633       add_prompt(ua, opr.Name);
634    }
635    free(ids);
636    if (do_prompt(ua, _("Pool"),  _("Select the Pool"), name, sizeof(name)) < 0) {
637       return false;
638    }
639
640    memset(&opr, 0, sizeof(opr));
641    /* *None* is only returned when selecting a recyclepool, and in that case
642     * the calling code is only interested in opr.Name, so then we can leave
643     * pr as all zero.
644     */
645    if (!bstrcmp(name, _("*None*"))) {
646      bstrncpy(opr.Name, name, sizeof(opr.Name));
647
648      if (!db_get_pool_numvols(ua->jcr, ua->db, &opr)) {
649         ua->error_msg(_("Could not find Pool \"%s\": ERR=%s"), name, db_strerror(ua->db));
650         return false;
651      }
652    }
653
654    memcpy(pr, &opr, sizeof(opr));
655    return true;
656 }
657
658 /*
659  * Select a Pool and a Media (Volume) record from the database
660  */
661 int select_pool_and_media_dbr(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr)
662 {
663
664    if (!select_media_dbr(ua, mr)) {
665       return 0;
666    }
667    memset(pr, 0, sizeof(POOL_DBR));
668    pr->PoolId = mr->PoolId;
669    if (!db_get_pool_record(ua->jcr, ua->db, pr)) {
670       ua->error_msg("%s", db_strerror(ua->db));
671       return 0;
672    }
673    if (!acl_access_ok(ua, Pool_ACL, pr->Name)) {
674       ua->error_msg(_("No access to Pool \"%s\"\n"), pr->Name);
675       return 0;
676    }
677    return 1;
678 }
679
680 /* Select a Media (Volume) record from the database */
681 int select_media_dbr(UAContext *ua, MEDIA_DBR *mr)
682 {
683    int i;
684    int ret = 0;
685    POOLMEM *err = get_pool_memory(PM_FNAME);
686    *err=0;
687
688    mr->clear();
689    i = find_arg_with_value(ua, "volume");
690    if (i >= 0) {
691       if (is_name_valid(ua->argv[i], &err)) {
692          bstrncpy(mr->VolumeName, ua->argv[i], sizeof(mr->VolumeName));
693       } else {
694          goto bail_out;
695       }
696    }
697    if (mr->VolumeName[0] == 0) {
698       POOL_DBR pr;
699       memset(&pr, 0, sizeof(pr));
700       /* Get the pool from pool=<pool-name> */
701       if (!get_pool_dbr(ua, &pr)) {
702          goto bail_out;
703       }
704       mr->PoolId = pr.PoolId;
705       db_list_media_records(ua->jcr, ua->db, mr, prtit, ua, HORZ_LIST);
706       if (!get_cmd(ua, _("Enter a Volume name or *MediaId: "))) {
707          goto bail_out;
708       }
709       if (ua->cmd[0] == '*' && is_a_number(ua->cmd+1)) {
710          mr->MediaId = str_to_int64(ua->cmd+1);
711       } else if (is_name_valid(ua->cmd, &err)) {
712          bstrncpy(mr->VolumeName, ua->cmd, sizeof(mr->VolumeName));
713       } else {
714          goto bail_out;
715       }
716    }
717
718    if (!db_get_media_record(ua->jcr, ua->db, mr)) {
719       pm_strcpy(err, db_strerror(ua->db));
720       goto bail_out;
721    }
722    ret = 1;
723
724 bail_out:
725    if (!ret && *err) {
726       ua->error_msg("%s", err);
727    }
728    free_pool_memory(err);
729    return ret;
730 }
731
732
733 /*
734  * Select a pool resource from prompt list
735  */
736 POOL *select_pool_resource(UAContext *ua)
737 {
738    char name[MAX_NAME_LENGTH];
739    POOL *pool;
740
741    start_prompt(ua, _("The defined Pool resources are:\n"));
742    LockRes();
743    foreach_res(pool, R_POOL) {
744       if (acl_access_ok(ua, Pool_ACL, pool->name())) {
745          add_prompt(ua, pool->name());
746       }
747    }
748    UnlockRes();
749    if (do_prompt(ua, _("Pool"), _("Select Pool resource"), name, sizeof(name)) < 0) {
750       return NULL;
751    }
752    pool = (POOL *)GetResWithName(R_POOL, name);
753    return pool;
754 }
755
756
757 /*
758  *  If you are thinking about using it, you
759  *  probably want to use select_pool_dbr()
760  *  or get_pool_dbr() above.
761  */
762 POOL *get_pool_resource(UAContext *ua)
763 {
764    POOL *pool = NULL;
765    int i;
766
767    i = find_arg_with_value(ua, "pool");
768    if (i >= 0 && acl_access_ok(ua, Pool_ACL, ua->argv[i])) {
769       pool = (POOL *)GetResWithName(R_POOL, ua->argv[i]);
770       if (pool) {
771          return pool;
772       }
773       ua->error_msg(_("Error: Pool resource \"%s\" does not exist.\n"), ua->argv[i]);
774    }
775    return select_pool_resource(ua);
776 }
777
778 /*
779  * List all jobs and ask user to select one
780  */
781 static int select_job_dbr(UAContext *ua, JOB_DBR *jr)
782 {
783    db_list_job_records(ua->jcr, ua->db, jr, prtit, ua, HORZ_LIST);
784    if (!get_pint(ua, _("Enter the JobId to select: "))) {
785       return 0;
786    }
787    jr->JobId = ua->int64_val;
788    if (!db_get_job_record(ua->jcr, ua->db, jr)) {
789       ua->error_msg("%s", db_strerror(ua->db));
790       return 0;
791    }
792    return jr->JobId;
793
794 }
795
796
797 /* Scan what the user has entered looking for:
798  *
799  *  jobid=nn
800  *
801  *  if error or not found, put up a list of Jobs
802  *  to choose from.
803  *
804  *   returns: 0 on error
805  *            JobId on success and fills in JOB_DBR
806  */
807 int get_job_dbr(UAContext *ua, JOB_DBR *jr)
808 {
809    int i;
810
811    for (i=1; i<ua->argc; i++) {
812       if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0 && ua->argv[i]) {
813          jr->JobId = 0;
814          bstrncpy(jr->Job, ua->argv[i], sizeof(jr->Job));
815       } else if (strcasecmp(ua->argk[i], NT_("jobid")) == 0 && ua->argv[i]) {
816          jr->JobId = str_to_int64(ua->argv[i]);
817          jr->Job[0] = 0;
818       } else {
819          continue;
820       }
821       if (!db_get_job_record(ua->jcr, ua->db, jr)) {
822          ua->error_msg(_("Could not find Job \"%s\": ERR=%s"), ua->argv[i],
823                   db_strerror(ua->db));
824          jr->JobId = 0;
825          break;
826       }
827       return jr->JobId;
828    }
829
830    jr->JobId = 0;
831    jr->Job[0] = 0;
832
833    for (i=1; i<ua->argc; i++) {
834       if ((strcasecmp(ua->argk[i], NT_("jobname")) == 0 ||
835            strcasecmp(ua->argk[i], NT_("job")) == 0) && ua->argv[i]) {
836          jr->JobId = 0;
837          bstrncpy(jr->Name, ua->argv[i], sizeof(jr->Name));
838          break;
839       }
840    }
841    if (!select_job_dbr(ua, jr)) {  /* try once more */
842       return 0;
843    }
844    return jr->JobId;
845 }
846
847 /*
848  * Implement unique set of prompts
849  */
850 void start_prompt(UAContext *ua, const char *msg)
851 {
852   if (ua->max_prompts == 0) {
853      ua->max_prompts = 10;
854      ua->prompt = (char **)bmalloc(sizeof(char *) * ua->max_prompts);
855      ua->unique = (char **)bmalloc(sizeof(char *) * ua->max_prompts);
856   }
857   ua->num_prompts = 1;
858   ua->prompt[0] = bstrdup(msg);
859   ua->unique[0] = NULL;
860 }
861
862 /*
863  * Add to prompts -- keeping them unique by name
864  */
865 void add_prompt(UAContext *ua, const char *prompt, char *unique)
866 {
867    int i;
868    if (ua->num_prompts == ua->max_prompts) {
869       ua->max_prompts *= 2;
870       ua->prompt = (char **)brealloc(ua->prompt, sizeof(char *) *
871          ua->max_prompts);
872       ua->unique = (char **)brealloc(ua->unique, sizeof(char *) *
873          ua->max_prompts);
874     }
875     for (i=1; i < ua->num_prompts; i++) {
876        if (strcmp(ua->prompt[i], prompt) == 0) {
877           return;
878        } else if (unique && strcmp(ua->unique[i], unique) == 0) {
879           return;
880        }
881     }
882     ua->prompt[ua->num_prompts] = bstrdup(prompt);
883     if (unique) {
884        ua->unique[ua->num_prompts++] = bstrdup(unique);
885     } else {
886        ua->unique[ua->num_prompts++] = NULL;
887     }
888 }
889
890 /*
891  * Display prompts and get user's choice
892  *
893  *  Returns: -1 on error
894  *            index base 0 on success, and choice
895  *               is copied to prompt if not NULL
896  *             prompt is set to the chosen prompt item string
897  */
898 int do_prompt(UAContext *ua, const char *automsg, const char *msg,
899               char *prompt, int max_prompt)
900 {
901    int i, item;
902    char pmsg[MAXSTRING];
903    BSOCK *user = ua->UA_sock;
904
905    if (prompt) {
906       *prompt = 0;
907    }
908    if (ua->num_prompts == 2) {
909       item = 1;
910       if (prompt) {
911          bstrncpy(prompt, ua->prompt[1], max_prompt);
912       }
913       ua->send_msg(_("Automatically selected %s: %s\n"), NPRTB(automsg), ua->prompt[1]);
914       goto done;
915    }
916    /* If running non-interactive, bail out */
917    if (ua->batch) {
918       /* First print the choices he wanted to make */
919       ua->send_msg(ua->prompt[0]);
920       for (i=1; i < ua->num_prompts; i++) {
921          ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
922       }
923       /* Now print error message */
924       ua->send_msg(_("Your request has multiple choices for \"%s\". Selection is not possible in batch mode.\n"), automsg);
925       item = -1;
926       goto done;
927    }
928    if (ua->api) user->signal(BNET_START_SELECT);
929    ua->send_msg(ua->prompt[0]);
930    for (i=1; i < ua->num_prompts; i++) {
931       if (ua->api) {
932          ua->send_msg("%s", ua->prompt[i]);
933       } else {
934          ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
935       }
936    }
937    if (ua->api) user->signal(BNET_END_SELECT);
938
939    for ( ;; ) {
940       /* First item is the prompt string, not the items */
941       if (ua->num_prompts == 1) {
942          ua->error_msg(_("Selection list for \"%s\" is empty!\n"), automsg);
943          item = -1;                    /* list is empty ! */
944          break;
945       }
946       if (ua->num_prompts == 2) {
947          item = 1;
948          ua->send_msg(_("Automatically selected: %s\n"), ua->prompt[1]);
949          if (prompt) {
950             bstrncpy(prompt, ua->prompt[1], max_prompt);
951          }
952          break;
953       } else {
954          sprintf(pmsg, "%s (1-%d): ", msg, ua->num_prompts-1);
955       }
956       /* Either a . or an @ will get you out of the loop */
957       if (ua->api) user->signal(BNET_SELECT_INPUT);
958       if (!get_pint(ua, pmsg)) {
959          item = -1;                   /* error */
960          ua->info_msg(_("Selection aborted, nothing done.\n"));
961          break;
962       }
963       item = ua->pint32_val;
964       if (item < 1 || item >= ua->num_prompts) {
965          ua->warning_msg(_("Please enter a number between 1 and %d\n"), ua->num_prompts-1);
966          continue;
967       }
968       if (prompt) {
969          bstrncpy(prompt, ua->prompt[item], max_prompt);
970       }
971       break;
972    }
973
974 done:
975    for (i=0; i < ua->num_prompts; i++) {
976       free(ua->prompt[i]);
977       if (ua->unique[i]) free(ua->unique[i]);
978    }
979    ua->num_prompts = 0;
980    return item>0 ? item-1 : item;
981 }
982
983 /*
984  * Display prompts and get user's choice
985  *
986  *  Returns: -1 on error
987  *            number of items selected and the choices are
988  *               copied to selected if not NULL
989  *            selected is an alist of the prompts chosen
990  *              Note! selected must already be initialized.
991  */
992 int do_alist_prompt(UAContext *ua, const char *automsg, const char *msg,
993               alist *selected)
994 {
995    int i, item;
996    char pmsg[MAXSTRING];
997    BSOCK *user = ua->UA_sock;
998    sellist sl;
999
1000    /* First item is the prompt string, not the items */
1001    if (ua->num_prompts == 1) {
1002       ua->error_msg(_("Selection list for \"%s\" is empty!\n"), automsg);
1003       item = -1;                    /* list is empty ! */
1004       goto done;
1005    }
1006    if (ua->num_prompts == 2) {
1007       item = 1;
1008       selected->append(bstrdup(ua->prompt[1]));
1009       ua->send_msg(_("Automatically selected %s: %s\n"), automsg, ua->prompt[1]);
1010       goto done;
1011    }
1012    /* If running non-interactive, bail out */
1013    if (ua->batch) {
1014       /* First print the choices he wanted to make */
1015       ua->send_msg(ua->prompt[0]);
1016       for (i=1; i < ua->num_prompts; i++) {
1017          ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
1018       }
1019       /* Now print error message */
1020       ua->send_msg(_("Your request has multiple choices for \"%s\". Selection is not possible in batch mode.\n"), automsg);
1021       item = -1;
1022       goto done;
1023    }
1024    if (ua->api) user->signal(BNET_START_SELECT);
1025    ua->send_msg(ua->prompt[0]);
1026    for (i=1; i < ua->num_prompts; i++) {
1027       if (ua->api) {
1028          ua->send_msg("%s", ua->prompt[i]);
1029       } else {
1030          ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
1031       }
1032    }
1033    if (ua->api) user->signal(BNET_END_SELECT);
1034
1035    sprintf(pmsg, "%s (1-%d): ", msg, ua->num_prompts-1);
1036
1037    for ( ;; ) {
1038       bool ok = true;
1039       /* Either a . or an @ will get you out of the loop */
1040       if (ua->api) user->signal(BNET_SELECT_INPUT);
1041
1042       if (!get_selection_list(ua, sl, pmsg, false)) {
1043          item = -1;
1044          break;
1045       }
1046
1047       if (sl.is_all()) {
1048          for (i=1; i < ua->num_prompts; i++) {
1049             selected->append(bstrdup(ua->prompt[i]));
1050          }
1051       } else {
1052          while ( (item = sl.next()) > 0) {
1053             if (item < 1 || item >= ua->num_prompts) {
1054                ua->warning_msg(_("Please enter a number between 1 and %d\n"), ua->num_prompts-1);
1055                ok = false;
1056                break;
1057             }
1058             selected->append(bstrdup(ua->prompt[item]));
1059          }
1060       }
1061       if (ok) {
1062          item = selected->size();
1063          break;
1064       }
1065    }
1066
1067 done:
1068    for (i=0; i < ua->num_prompts; i++) {
1069       free(ua->prompt[i]);
1070       if (ua->unique[i]) free(ua->unique[i]);
1071    }
1072    ua->num_prompts = 0;
1073    return item;
1074 }
1075
1076
1077 /*
1078  * We scan what the user has entered looking for
1079  *    storage=<storage-resource>
1080  *    job=<job_name>
1081  *    jobid=<jobid>
1082  *    ?              (prompt him with storage list)
1083  *    <some-error>   (prompt him with storage list)
1084  *
1085  * If use_default is set, we assume that any keyword without a value
1086  *   is the name of the Storage resource wanted.
1087  */
1088 STORE *get_storage_resource(UAContext *ua, bool use_default, bool unique)
1089 {
1090    char *store_name = NULL;
1091    STORE *store = NULL;
1092    int jobid;
1093    JCR *jcr;
1094    int i;
1095    char ed1[50];
1096
1097    for (i=1; i<ua->argc; i++) {
1098       if (use_default && !ua->argv[i]) {
1099          /* Ignore slots, scan and barcode(s) keywords */
1100          if (strcasecmp("scan", ua->argk[i]) == 0 ||
1101              strcasecmp("barcode", ua->argk[i]) == 0 ||
1102              strcasecmp("barcodes", ua->argk[i]) == 0 ||
1103              strcasecmp("slots", ua->argk[i]) == 0) {
1104             continue;
1105          }
1106          /* Default argument is storage */
1107          if (store_name) {
1108             ua->error_msg(_("Storage name given twice.\n"));
1109             return NULL;
1110          }
1111          store_name = ua->argk[i];
1112          if (*store_name == '?') {
1113             *store_name = 0;
1114             break;
1115          }
1116       } else {
1117          if (strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
1118              strcasecmp(ua->argk[i], NT_("sd")) == 0) {
1119             store_name = ua->argv[i];
1120             break;
1121
1122          } else if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
1123             jobid = str_to_int64(ua->argv[i]);
1124             if (jobid <= 0) {
1125                ua->error_msg(_("Expecting jobid=nn command, got: %s\n"), ua->argk[i]);
1126                return NULL;
1127             }
1128             if (!(jcr=get_jcr_by_id(jobid))) {
1129                ua->error_msg(_("JobId %s is not running.\n"), edit_int64(jobid, ed1));
1130                return NULL;
1131             }
1132             store = jcr->wstore;
1133             free_jcr(jcr);
1134             break;
1135
1136          } else if (strcasecmp(ua->argk[i], NT_("job")) == 0 ||
1137                     strcasecmp(ua->argk[i], NT_("jobname")) == 0) {
1138             if (!ua->argv[i]) {
1139                ua->error_msg(_("Expecting job=xxx, got: %s.\n"), ua->argk[i]);
1140                return NULL;
1141             }
1142             if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
1143                ua->error_msg(_("Job \"%s\" is not running.\n"), ua->argv[i]);
1144                return NULL;
1145             }
1146             store = jcr->wstore;
1147             free_jcr(jcr);
1148             break;
1149          } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0) {
1150             if (!ua->argv[i]) {
1151                ua->error_msg(_("Expecting ujobid=xxx, got: %s.\n"), ua->argk[i]);
1152                return NULL;
1153             }
1154             if ((jcr=get_jcr_by_full_name(ua->argv[i]))) {
1155                store = jcr->wstore;
1156                free_jcr(jcr);
1157                /* The job might not be running, so we try to see other keywords */
1158                if (store) {
1159                   break;
1160                }
1161             }
1162          }
1163       }
1164    }
1165    if (store && !acl_access_ok(ua, Storage_ACL, store->name())) {
1166       store = NULL;
1167    }
1168
1169    if (!store && store_name && store_name[0] != 0) {
1170       store = (STORE *)GetResWithName(R_STORAGE, store_name);
1171       if (!store) {
1172          ua->error_msg(_("Storage resource \"%s\": not found\n"), store_name);
1173       }
1174    }
1175    if (store && !acl_access_ok(ua, Storage_ACL, store->name())) {
1176       store = NULL;
1177    }
1178    /* No keywords found, so present a selection list */
1179    if (!store) {
1180       store = select_storage_resource(ua, unique);
1181    }
1182    return store;
1183 }
1184
1185 /* Get drive that we are working with for this storage */
1186 int get_storage_drive(UAContext *ua, STORE *store)
1187 {
1188    int i, drive = -1;
1189    /* Get drive for autochanger if possible */
1190    i = find_arg_with_value(ua, "drive");
1191    if (i >=0) {
1192       drive = atoi(ua->argv[i]);
1193    } else if (store && store->autochanger) {
1194       /* If our structure is not set ask SD for # drives */
1195       if (store->drives == 0) {
1196          store->drives = get_num_drives_from_SD(ua);
1197       }
1198       /* If only one drive, default = 0 */
1199       if (store->drives == 1) {
1200          drive = 0;
1201       } else {
1202          /* Ask user to enter drive number */
1203          ua->cmd[0] = 0;
1204          if (!get_cmd(ua, _("Enter autochanger drive[0]: "))) {
1205             drive = -1;  /* None */
1206          } else {
1207             drive = atoi(ua->cmd);
1208          }
1209      }
1210    }
1211    return drive;
1212 }
1213
1214 /* Get slot that we are working with for this storage */
1215 int get_storage_slot(UAContext *ua, STORE *store)
1216 {
1217    int i, slot = -1;
1218    /* Get slot for autochanger if possible */
1219    i = find_arg_with_value(ua, "slot");
1220    if (i >=0) {
1221       slot = atoi(ua->argv[i]);
1222    } else if (store && store->autochanger) {
1223       /* Ask user to enter slot number */
1224       ua->cmd[0] = 0;
1225       if (!get_cmd(ua, _("Enter autochanger slot: "))) {
1226          slot = -1;  /* None */
1227       } else {
1228          slot = atoi(ua->cmd);
1229       }
1230    }
1231    return slot;
1232 }
1233
1234
1235
1236 /*
1237  * Scan looking for mediatype=
1238  *
1239  *  if not found or error, put up selection list
1240  *
1241  *  Returns: 0 on error
1242  *           1 on success, MediaType is set
1243  */
1244 int get_media_type(UAContext *ua, char *MediaType, int max_media)
1245 {
1246    STORE *store;
1247    int i;
1248
1249    i = find_arg_with_value(ua, "mediatype");
1250    if (i >= 0) {
1251       bstrncpy(MediaType, ua->argv[i], max_media);
1252       return 1;
1253    }
1254
1255    start_prompt(ua, _("Media Types defined in conf file:\n"));
1256    LockRes();
1257    foreach_res(store, R_STORAGE) {
1258       add_prompt(ua, store->media_type);
1259    }
1260    UnlockRes();
1261    return (do_prompt(ua, _("Media Type"), _("Select the Media Type"), MediaType, max_media) < 0) ? 0 : 1;
1262 }
1263
1264
1265 bool get_level_from_name(JCR *jcr, const char *level_name)
1266 {
1267    /* Look up level name and pull code */
1268    bool found = false;
1269    for (int i=0; joblevels[i].level_name; i++) {
1270       if (strcasecmp(level_name, joblevels[i].level_name) == 0) {
1271          jcr->setJobLevel(joblevels[i].level);
1272          found = true;
1273          break;
1274       }
1275    }
1276    return found;
1277 }
1278
1279 static int count_running_jobs(UAContext *ua)
1280 {
1281    int tjobs = 0;                  /* total # number jobs */
1282    int njobs = 0;
1283    JCR *jcr;
1284    /* Count Jobs running */
1285    foreach_jcr(jcr) {
1286       if (jcr->JobId == 0) {      /* this is us */
1287          continue;
1288       }
1289       tjobs++;                    /* count of all jobs */
1290       if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1291          continue;               /* skip not authorized */
1292       }
1293       njobs++;                   /* count of authorized jobs */
1294    }
1295    endeach_jcr(jcr);
1296
1297    if (njobs == 0) {            /* no authorized */
1298       if (tjobs == 0) {
1299          ua->send_msg(_("No Jobs running.\n"));
1300       } else {
1301          ua->send_msg(_("None of your jobs are running.\n"));
1302       }
1303    }
1304    return njobs;
1305 }
1306
1307
1308 /* Get a list of running jobs
1309  * "reason" is used in user messages
1310  * can be: cancel, limit, ...
1311  *  Returns: -1 on error
1312  *           nb of JCR on success (should be free_jcr() after)
1313  */
1314 int select_running_jobs(UAContext *ua, alist *jcrs, const char *reason)
1315 {
1316    int i;
1317    JCR *jcr = NULL;
1318    int njobs = 0;
1319    char JobName[MAX_NAME_LENGTH];
1320    char temp[256];
1321    alist *selected = NULL;
1322
1323    for (i=1; i<ua->argc; i++) {
1324       if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
1325          sellist sl;
1326          int32_t JobId;
1327
1328          if (!ua->argv[i]) {
1329             ua->error_msg(_("No value given for \"jobid\".\n"));
1330             goto bail_out;
1331          }
1332          if (!sl.set_string(ua->argv[i], true)) {
1333             ua->send_msg("%s", sl.get_errmsg());
1334             goto bail_out;
1335          }
1336          foreach_sellist(JobId, &sl) {
1337             jcr = get_jcr_by_id(JobId);
1338             if (jcr && jcr->job && acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1339                jcrs->append(jcr);
1340             } else if (jcr) {
1341                ua->error_msg(_("Unauthorized command from this console "
1342                                "for JobId=%d.\n"), JobId);
1343                free_jcr(jcr);
1344             } else {
1345                ua->warning_msg(_("Warning Job JobId=%d is not running.\n"), JobId);
1346             }
1347          }
1348          if (jcrs->size() == 0) {
1349             goto bail_out;               /* If we did not find specified jobid, get out */
1350          }
1351          break;
1352
1353       /* TODO: might want to implement filters (client, status, etc...) */
1354       } else if (strcasecmp(ua->argk[i], NT_("all")) == 0) {
1355          foreach_jcr(jcr) {
1356             if (jcr->JobId == 0) {      /* Do not cancel consoles */
1357                continue;
1358             }
1359             if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1360                continue;               /* skip not authorized */
1361             }
1362             jcr->inc_use_count();
1363             jcrs->append(jcr);
1364          }
1365          endeach_jcr(jcr);
1366
1367          /* If we have something and no "yes" on command line, get confirmation */
1368          if (jcrs->size() > 0 && find_arg(ua, NT_("yes")) < 0) {
1369             char nbuf[1000];
1370             bsnprintf(nbuf, sizeof(nbuf),  _("Confirm %s of %d Job%s (yes/no): "),
1371                       reason, jcrs->size(), jcrs->size()>1?"s":"");
1372             if (!get_yesno(ua, nbuf) || ua->pint32_val == 0) {
1373                goto bail_out;
1374             }
1375          }
1376          if (jcrs->size() == 0) {
1377             goto bail_out;               /* If we did not find specified jobid, get out */
1378          }
1379          break;
1380
1381       } else if (strcasecmp(ua->argk[i], NT_("job")) == 0) {
1382          if (!ua->argv[i]) {
1383             ua->error_msg(_("No value given for \"job\".\n"));
1384             goto bail_out;
1385          }
1386          jcr = get_jcr_by_partial_name(ua->argv[i]);
1387
1388          if (jcr && jcr->job && acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1389             jcrs->append(jcr);
1390
1391          } else if (jcr) {
1392             if (jcr->job) {
1393                ua->error_msg(_("Unauthorized command from this console "
1394                                "for job=%s.\n"), ua->argv[i]);
1395             }
1396             free_jcr(jcr);
1397
1398          } else {
1399             ua->warning_msg(_("Warning Job %s is not running.\n"), ua->argv[i]);
1400          }
1401          if (jcrs->size() == 0) {
1402             goto bail_out;               /* If we did not find specified jobid, get out */
1403          }
1404          break;
1405
1406       } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0) {
1407          if (!ua->argv[i]) {
1408             ua->error_msg(_("No value given for \"ujobid\".\n"));
1409             goto bail_out;
1410          }
1411          jcr = get_jcr_by_full_name(ua->argv[i]);
1412
1413          if (jcr && jcr->job && acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1414             jcrs->append(jcr);
1415
1416          } else if (jcr) {
1417             if (jcr->job) {
1418                ua->error_msg(_("Unauthorized command from this console "
1419                                "for ujobid=%s.\n"), ua->argv[i]);
1420             }
1421             free_jcr(jcr);
1422
1423          } else {
1424             ua->warning_msg(_("Warning Job %s is not running.\n"), ua->argv[i]);
1425          }
1426          if (jcrs->size() == 0) {
1427             goto bail_out;               /* If we did not find specified jobid, get out */
1428          }
1429          break;
1430       }
1431    }
1432
1433    if (jcrs->size() == 0) {
1434       /*
1435        * If we still do not have a jcr,
1436        *   throw up a list and ask the user to select one.
1437        */
1438       char *item;
1439       char buf[1000];
1440       njobs = count_running_jobs(ua);
1441       if (njobs == 0) {
1442          goto bail_out;
1443       }
1444       start_prompt(ua, _("Select Job(s):\n"));
1445       foreach_jcr(jcr) {
1446          char ed1[50];
1447          if (jcr->JobId == 0) {      /* this is us */
1448             continue;
1449          }
1450          bsnprintf(buf, sizeof(buf), _("JobId=%s Job=%s"), edit_int64(jcr->JobId, ed1), jcr->Job);
1451          add_prompt(ua, buf);
1452       }
1453       endeach_jcr(jcr);
1454       bsnprintf(temp, sizeof(temp), _("Choose Job list to %s"), _(reason));
1455       selected = New(alist(5, owned_by_alist));
1456       if (do_alist_prompt(ua, _("Job"), temp, selected) < 0) {
1457          goto bail_out;
1458       }
1459       /* Possibly ask for confirmation */
1460       if (selected->size() > 0 && find_arg(ua, NT_("yes")) < 0) {
1461          char nbuf[1000];
1462          foreach_alist(item, selected) {
1463             ua->send_msg("%s\n", item);
1464          }
1465          bsnprintf(nbuf, sizeof(nbuf),  _("Confirm %s of %d Job%s (yes/no): "),
1466                    reason, selected->size(), selected->size()>1?"s":"");
1467          if (!get_yesno(ua, nbuf) || ua->pint32_val == 0) {
1468             goto bail_out;
1469          }
1470       }
1471
1472       foreach_alist(item, selected) {
1473          if (sscanf(item, "JobId=%d Job=%127s", &njobs, JobName) != 2) {
1474             ua->warning_msg(_("Job \"%s\" not found.\n"), item);
1475             continue;
1476          }
1477          jcr = get_jcr_by_full_name(JobName);
1478          if (jcr) {
1479             jcrs->append(jcr);
1480          } else {
1481             ua->warning_msg(_("Job \"%s\" not found.\n"), JobName);
1482          }
1483       }
1484    }
1485 bail_out:
1486    if (selected) delete selected;
1487    return jcrs->size();
1488 }