]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_select.c
This commit was manufactured by cvs2svn to create tag
[bacula/bacula] / bacula / src / dird / ua_select.c
1 /*
2  *
3  *   Bacula Director -- User Agent Prompt and Selection code
4  *
5  *     Kern Sibbald, October MMI
6  *
7  *   Version  $Id$
8  */
9 /*
10    Copyright (C) 2001-2006 Kern Sibbald
11
12    This program is free software; you can redistribute it and/or
13    modify it under the terms of the GNU General Public License
14    version 2 as amended with additional clauses defined in the
15    file LICENSE in the main source directory.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
20    the file LICENSE for additional details.
21
22  */
23
24 #include "bacula.h"
25 #include "dird.h"
26
27 /* Imported variables */
28 extern struct s_jl joblevels[];
29
30
31 /*
32  * Confirm a retention period
33  */
34 int confirm_retention(UAContext *ua, utime_t *ret, const char *msg)
35 {
36    char ed1[100];
37
38    for ( ;; ) {
39        bsendmsg(ua, _("The current %s retention period is: %s\n"),
40           msg, edit_utime(*ret, ed1, sizeof(ed1)));
41        if (!get_cmd(ua, _("Continue? (yes/mod/no): "))) {
42           return 0;
43        }
44        if (strcasecmp(ua->cmd, _("mod")) == 0) {
45           if (!get_cmd(ua, _("Enter new retention period: "))) {
46              return 0;
47           }
48           if (!duration_to_utime(ua->cmd, ret)) {
49              bsendmsg(ua, _("Invalid period.\n"));
50              continue;
51           }
52           continue;
53        }
54        if (strcasecmp(ua->cmd, _("yes")) == 0) {
55           return 1;
56        }
57        if (strcasecmp(ua->cmd, _("no")) == 0) {
58           return 0;
59        }
60     }
61     return 1;
62 }
63
64 /*
65  * Given a list of keywords, find the first one
66  *  that is in the argument list.
67  * Returns: -1 if not found
68  *          index into list (base 0) on success
69  */
70 int find_arg_keyword(UAContext *ua, const char **list)
71 {
72    for (int i=1; i<ua->argc; i++) {
73       for(int j=0; list[j]; j++) {
74          if (strcasecmp(_(list[j]), ua->argk[i]) == 0) {
75             return j;
76          }
77       }
78    }
79    return -1;
80 }
81
82 /*
83  * Given one keyword, find the first one that
84  *   is in the argument list.
85  * Returns: argk index (always gt 0)
86  *          -1 if not found
87  */
88 int find_arg(UAContext *ua, const char *keyword)
89 {
90    for (int i=1; i<ua->argc; i++) {
91       if (strcasecmp(keyword, ua->argk[i]) == 0) {
92          return i;
93       }
94    }
95    return -1;
96 }
97
98 /*
99  * Given a single keyword, find it in the argument list, but
100  *   it must have a value
101  * Returns: -1 if not found or no value
102  *           list index (base 0) on success
103  */
104 int find_arg_with_value(UAContext *ua, const char *keyword)
105 {
106    for (int i=1; i<ua->argc; i++) {
107       if (strcasecmp(keyword, ua->argk[i]) == 0) {
108          if (ua->argv[i]) {
109             return i;
110          } else {
111             return -1;
112          }
113       }
114    }
115    return -1;
116 }
117
118 /*
119  * Given a list of keywords, prompt the user
120  * to choose one.
121  *
122  * Returns: -1 on failure
123  *          index into list (base 0) on success
124  */
125 int do_keyword_prompt(UAContext *ua, const char *msg, const char **list)
126 {
127    int i;
128    start_prompt(ua, _("You have the following choices:\n"));
129    for (i=0; list[i]; i++) {
130       add_prompt(ua, list[i]);
131    }
132    return do_prompt(ua, "", msg, NULL, 0);
133 }
134
135
136 /*
137  * Select a Storage resource from prompt list
138  */
139 STORE *select_storage_resource(UAContext *ua)
140 {
141    char name[MAX_NAME_LENGTH];
142    STORE *store;
143
144    start_prompt(ua, _("The defined Storage resources are:\n"));
145    LockRes();
146    foreach_res(store, R_STORAGE) {
147       if (acl_access_ok(ua, Storage_ACL, store->hdr.name)) {
148          add_prompt(ua, store->hdr.name);
149       }
150    }
151    UnlockRes();
152    if (do_prompt(ua, _("Storage"),  _("Select Storage resource"), name, sizeof(name)) < 0) {
153       return NULL;
154    }
155    store = (STORE *)GetResWithName(R_STORAGE, name);
156    return store;
157 }
158
159 /*
160  * Select a FileSet resource from prompt list
161  */
162 FILESET *select_fileset_resource(UAContext *ua)
163 {
164    char name[MAX_NAME_LENGTH];
165    FILESET *fs;
166
167    start_prompt(ua, _("The defined FileSet resources are:\n"));
168    LockRes();
169    foreach_res(fs, R_FILESET) {
170       if (acl_access_ok(ua, FileSet_ACL, fs->hdr.name)) {
171          add_prompt(ua, fs->hdr.name);
172       }
173    }
174    UnlockRes();
175    if (do_prompt(ua, _("FileSet"), _("Select FileSet resource"), name, sizeof(name)) < 0) {
176       return NULL;
177    }
178    fs = (FILESET *)GetResWithName(R_FILESET, name);
179    return fs;
180 }
181
182
183 /*
184  * Get a catalog resource from prompt list
185  */
186 CAT *get_catalog_resource(UAContext *ua)
187 {
188    char name[MAX_NAME_LENGTH];
189    CAT *catalog = NULL;
190    int i;
191
192    for (i=1; i<ua->argc; i++) {
193       if (strcasecmp(ua->argk[i], _("catalog")) == 0 && ua->argv[i]) {
194          if (acl_access_ok(ua, Catalog_ACL, ua->argv[i])) {
195             catalog = (CAT *)GetResWithName(R_CATALOG, ua->argv[i]);
196             break;
197          }
198       }
199    }
200    if (!catalog) {
201       start_prompt(ua, _("The defined Catalog resources are:\n"));
202       LockRes();
203       foreach_res(catalog, R_CATALOG) {
204          if (acl_access_ok(ua, Catalog_ACL, catalog->hdr.name)) {
205             add_prompt(ua, catalog->hdr.name);
206          }
207       }
208       UnlockRes();
209       if (do_prompt(ua, _("Catalog"),  _("Select Catalog resource"), name, sizeof(name)) < 0) {
210          return NULL;
211       }
212       catalog = (CAT *)GetResWithName(R_CATALOG, name);
213    }
214    return catalog;
215 }
216
217
218 /*
219  * Select a Job resource from prompt list
220  */
221 JOB *select_job_resource(UAContext *ua)
222 {
223    char name[MAX_NAME_LENGTH];
224    JOB *job;
225
226    start_prompt(ua, _("The defined Job resources are:\n"));
227    LockRes();
228    foreach_res(job, R_JOB) {
229       if (acl_access_ok(ua, Job_ACL, job->hdr.name)) {
230          add_prompt(ua, job->hdr.name);
231       }
232    }
233    UnlockRes();
234    if (do_prompt(ua, _("Job"), _("Select Job resource"), name, sizeof(name)) < 0) {
235       return NULL;
236    }
237    job = (JOB *)GetResWithName(R_JOB, name);
238    return job;
239 }
240
241 /*
242  * Select a Restore Job resource from prompt list
243  */
244 JOB *select_restore_job_resource(UAContext *ua)
245 {
246    char name[MAX_NAME_LENGTH];
247    JOB *job;
248
249    start_prompt(ua, _("The defined Restore Job resources are:\n"));
250    LockRes();
251    foreach_res(job, R_JOB) {
252       if (job->JobType == JT_RESTORE && acl_access_ok(ua, Job_ACL, job->hdr.name)) {
253          add_prompt(ua, job->hdr.name);
254       }
255    }
256    UnlockRes();
257    if (do_prompt(ua, _("Job"), _("Select Restore Job"), name, sizeof(name)) < 0) {
258       return NULL;
259    }
260    job = (JOB *)GetResWithName(R_JOB, name);
261    return job;
262 }
263
264
265
266 /*
267  * Select a client resource from prompt list
268  */
269 CLIENT *select_client_resource(UAContext *ua)
270 {
271    char name[MAX_NAME_LENGTH];
272    CLIENT *client;
273
274    start_prompt(ua, _("The defined Client resources are:\n"));
275    LockRes();
276    foreach_res(client, R_CLIENT) {
277       if (acl_access_ok(ua, Client_ACL, client->hdr.name)) {
278          add_prompt(ua, client->hdr.name);
279       }
280    }
281    UnlockRes();
282    if (do_prompt(ua, _("Client"),  _("Select Client (File daemon) resource"), name, sizeof(name)) < 0) {
283       return NULL;
284    }
285    client = (CLIENT *)GetResWithName(R_CLIENT, name);
286    return client;
287 }
288
289 /*
290  *  Get client resource, start by looking for
291  *   client=<client-name>
292  *  if we don't find the keyword, we prompt the user.
293  */
294 CLIENT *get_client_resource(UAContext *ua)
295 {
296    CLIENT *client = NULL;
297    int i;
298
299    for (i=1; i<ua->argc; i++) {
300       if ((strcasecmp(ua->argk[i], N_("client")) == 0 ||
301            strcasecmp(ua->argk[i], N_("fd")) == 0) && ua->argv[i]) {
302          if (!acl_access_ok(ua, Client_ACL, ua->argv[i])) {
303             break;
304          }
305          client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
306          if (client) {
307             return client;
308          }
309          bsendmsg(ua, _("Error: Client resource %s does not exist.\n"), ua->argv[i]);
310          break;
311       }
312    }
313    return select_client_resource(ua);
314 }
315
316 /* Scan what the user has entered looking for:
317  *
318  *  client=<client-name>
319  *
320  *  if error or not found, put up a list of client DBRs
321  *  to choose from.
322  *
323  *   returns: 0 on error
324  *            1 on success and fills in CLIENT_DBR
325  */
326 int get_client_dbr(UAContext *ua, CLIENT_DBR *cr)
327 {
328    int i;
329
330    if (cr->Name[0]) {                 /* If name already supplied */
331       if (db_get_client_record(ua->jcr, ua->db, cr)) {
332          return 1;
333       }
334       bsendmsg(ua, _("Could not find Client %s: ERR=%s"), cr->Name, db_strerror(ua->db));
335    }
336    for (i=1; i<ua->argc; i++) {
337       if ((strcasecmp(ua->argk[i], _("client")) == 0 ||
338            strcasecmp(ua->argk[i], _("fd")) == 0) && ua->argv[i]) {
339          if (!acl_access_ok(ua, Client_ACL, ua->argv[i])) {
340             break;
341          }
342          bstrncpy(cr->Name, ua->argv[i], sizeof(cr->Name));
343          if (!db_get_client_record(ua->jcr, ua->db, cr)) {
344             bsendmsg(ua, _("Could not find Client \"%s\": ERR=%s"), ua->argv[i],
345                      db_strerror(ua->db));
346             cr->ClientId = 0;
347             break;
348          }
349          return 1;
350       }
351    }
352    if (!select_client_dbr(ua, cr)) {  /* try once more by proposing a list */
353       return 0;
354    }
355    return 1;
356 }
357
358 /*
359  * Select a Client record from the catalog
360  *  Returns 1 on success
361  *          0 on failure
362  */
363 int select_client_dbr(UAContext *ua, CLIENT_DBR *cr)
364 {
365    CLIENT_DBR ocr;
366    char name[MAX_NAME_LENGTH];
367    int num_clients, i;
368    uint32_t *ids;
369
370
371    cr->ClientId = 0;
372    if (!db_get_client_ids(ua->jcr, ua->db, &num_clients, &ids)) {
373       bsendmsg(ua, _("Error obtaining client ids. ERR=%s\n"), db_strerror(ua->db));
374       return 0;
375    }
376    if (num_clients <= 0) {
377       bsendmsg(ua, _("No clients defined. You must run a job before using this command.\n"));
378       return 0;
379    }
380
381    start_prompt(ua, _("Defined Clients:\n"));
382    for (i=0; i < num_clients; i++) {
383       ocr.ClientId = ids[i];
384       if (!db_get_client_record(ua->jcr, ua->db, &ocr) ||
385           !acl_access_ok(ua, Client_ACL, ocr.Name)) {
386          continue;
387       }
388       add_prompt(ua, ocr.Name);
389    }
390    free(ids);
391    if (do_prompt(ua, _("Client"),  _("Select the Client"), name, sizeof(name)) < 0) {
392       return 0;
393    }
394    memset(&ocr, 0, sizeof(ocr));
395    bstrncpy(ocr.Name, name, sizeof(ocr.Name));
396
397    if (!db_get_client_record(ua->jcr, ua->db, &ocr)) {
398       bsendmsg(ua, _("Could not find Client \"%s\": ERR=%s"), name, db_strerror(ua->db));
399       return 0;
400    }
401    memcpy(cr, &ocr, sizeof(ocr));
402    return 1;
403 }
404
405
406
407 /* Scan what the user has entered looking for:
408  *
409  *  pool=<pool-name>
410  *
411  *  if error or not found, put up a list of pool DBRs
412  *  to choose from.
413  *
414  *   returns: false on error
415  *            true  on success and fills in POOL_DBR
416  */
417 bool get_pool_dbr(UAContext *ua, POOL_DBR *pr)
418 {
419    if (pr->Name[0]) {                 /* If name already supplied */
420       if (db_get_pool_record(ua->jcr, ua->db, pr) &&
421           acl_access_ok(ua, Pool_ACL, pr->Name)) {
422          return true;
423       }
424       bsendmsg(ua, _("Could not find Pool \"%s\": ERR=%s"), pr->Name, db_strerror(ua->db));
425    }
426    if (!select_pool_dbr(ua, pr)) {  /* try once more */
427       return false;
428    }
429    return true;
430 }
431
432 /*
433  * Select a Pool record from the catalog
434  */
435 bool select_pool_dbr(UAContext *ua, POOL_DBR *pr)
436 {
437    POOL_DBR opr;
438    char name[MAX_NAME_LENGTH];
439    int num_pools, i;
440    uint32_t *ids;
441
442    for (i=1; i<ua->argc; i++) {
443       if (strcasecmp(ua->argk[i], N_("pool")) == 0 && ua->argv[i] &&
444           acl_access_ok(ua, Pool_ACL, ua->argv[i])) {
445          bstrncpy(pr->Name, ua->argv[i], sizeof(pr->Name));
446          if (!db_get_pool_record(ua->jcr, ua->db, pr)) {
447             bsendmsg(ua, _("Could not find Pool \"%s\": ERR=%s"), ua->argv[i],
448                      db_strerror(ua->db));
449             pr->PoolId = 0;
450             break;
451          }
452          return true;
453       }
454    }
455
456    pr->PoolId = 0;
457    if (!db_get_pool_ids(ua->jcr, ua->db, &num_pools, &ids)) {
458       bsendmsg(ua, _("Error obtaining pool ids. ERR=%s\n"), db_strerror(ua->db));
459       return 0;
460    }
461    if (num_pools <= 0) {
462       bsendmsg(ua, _("No pools defined. Use the \"create\" command to create one.\n"));
463       return false;
464    }
465
466    start_prompt(ua, _("Defined Pools:\n"));
467    for (i=0; i < num_pools; i++) {
468       opr.PoolId = ids[i];
469       if (!db_get_pool_record(ua->jcr, ua->db, &opr) ||
470           !acl_access_ok(ua, Pool_ACL, opr.Name)) {
471          continue;
472       }
473       add_prompt(ua, opr.Name);
474    }
475    free(ids);
476    if (do_prompt(ua, _("Pool"),  _("Select the Pool"), name, sizeof(name)) < 0) {
477       return false;
478    }
479    memset(&opr, 0, sizeof(opr));
480    bstrncpy(opr.Name, name, sizeof(opr.Name));
481
482    if (!db_get_pool_record(ua->jcr, ua->db, &opr)) {
483       bsendmsg(ua, _("Could not find Pool \"%s\": ERR=%s"), name, db_strerror(ua->db));
484       return false;
485    }
486    memcpy(pr, &opr, sizeof(opr));
487    return true;
488 }
489
490 /*
491  * Select a Pool and a Media (Volume) record from the database
492  */
493 int select_pool_and_media_dbr(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr)
494 {
495
496    if (!select_media_dbr(ua, mr)) {
497       return 0;
498    }
499    memset(pr, 0, sizeof(POOL_DBR));
500    pr->PoolId = mr->PoolId;
501    if (!db_get_pool_record(ua->jcr, ua->db, pr)) {
502       bsendmsg(ua, "%s", db_strerror(ua->db));
503       return 0;
504    }
505    if (!acl_access_ok(ua, Pool_ACL, pr->Name)) {
506       bsendmsg(ua, _("No access to Pool \"%s\"\n"), pr->Name);
507       return 0;
508    }
509    return 1;
510 }
511
512 /* Select a Media (Volume) record from the database */
513 int select_media_dbr(UAContext *ua, MEDIA_DBR *mr)
514 {
515    int i;
516
517    memset(mr, 0, sizeof(MEDIA_DBR));
518
519    i = find_arg_with_value(ua, "volume");
520    if (i >= 0) {
521       bstrncpy(mr->VolumeName, ua->argv[i], sizeof(mr->VolumeName));
522    }
523    if (mr->VolumeName[0] == 0) {
524       POOL_DBR pr;
525       memset(&pr, 0, sizeof(pr));
526       /* Get the pool from pool=<pool-name> */
527       if (!get_pool_dbr(ua, &pr)) {
528          return 0;
529       }
530       mr->PoolId = pr.PoolId;
531       db_list_media_records(ua->jcr, ua->db, mr, prtit, ua, HORZ_LIST);
532       if (!get_cmd(ua, _("Enter MediaId or Volume name: "))) {
533          return 0;
534       }
535       if (is_a_number(ua->cmd)) {
536          mr->MediaId = str_to_int64(ua->cmd);
537       } else {
538          bstrncpy(mr->VolumeName, ua->cmd, sizeof(mr->VolumeName));
539       }
540    }
541
542    if (!db_get_media_record(ua->jcr, ua->db, mr)) {
543       bsendmsg(ua, "%s", db_strerror(ua->db));
544       return 0;
545    }
546    return 1;
547 }
548
549
550 /*
551  * Select a pool resource from prompt list
552  */
553 POOL *select_pool_resource(UAContext *ua)
554 {
555    char name[MAX_NAME_LENGTH];
556    POOL *pool;
557
558    start_prompt(ua, _("The defined Pool resources are:\n"));
559    LockRes();
560    foreach_res(pool, R_POOL) {
561       if (acl_access_ok(ua, Pool_ACL, pool->hdr.name)) {
562          add_prompt(ua, pool->hdr.name);
563       }
564    }
565    UnlockRes();
566    if (do_prompt(ua, _("Pool"), _("Select Pool resource"), name, sizeof(name)) < 0) {
567       return NULL;
568    }
569    pool = (POOL *)GetResWithName(R_POOL, name);
570    return pool;
571 }
572
573
574 /*
575  *  If you are thinking about using it, you
576  *  probably want to use select_pool_dbr()
577  *  or get_pool_dbr() above.
578  */
579 POOL *get_pool_resource(UAContext *ua)
580 {
581    POOL *pool = NULL;
582    int i;
583
584    i = find_arg_with_value(ua, "pool");
585    if (i >= 0 && acl_access_ok(ua, Pool_ACL, ua->argv[i])) {
586       pool = (POOL *)GetResWithName(R_POOL, ua->argv[i]);
587       if (pool) {
588          return pool;
589       }
590       bsendmsg(ua, _("Error: Pool resource \"%s\" does not exist.\n"), ua->argv[i]);
591    }
592    return select_pool_resource(ua);
593 }
594
595 /*
596  * List all jobs and ask user to select one
597  */
598 int select_job_dbr(UAContext *ua, JOB_DBR *jr)
599 {
600    db_list_job_records(ua->jcr, ua->db, jr, prtit, ua, HORZ_LIST);
601    if (!get_pint(ua, _("Enter the JobId to select: "))) {
602       return 0;
603    }
604    jr->JobId = ua->int64_val;
605    if (!db_get_job_record(ua->jcr, ua->db, jr)) {
606       bsendmsg(ua, "%s", db_strerror(ua->db));
607       return 0;
608    }
609    return jr->JobId;
610
611 }
612
613
614 /* Scan what the user has entered looking for:
615  *
616  *  jobid=nn
617  *
618  *  if error or not found, put up a list of Jobs
619  *  to choose from.
620  *
621  *   returns: 0 on error
622  *            JobId on success and fills in JOB_DBR
623  */
624 int get_job_dbr(UAContext *ua, JOB_DBR *jr)
625 {
626    int i;
627
628    for (i=1; i<ua->argc; i++) {
629       if (strcasecmp(ua->argk[i], N_("ujobid")) == 0 && ua->argv[i]) {
630          jr->JobId = 0;
631          bstrncpy(jr->Job, ua->argv[i], sizeof(jr->Job));
632       } else if (strcasecmp(ua->argk[i], N_("jobid")) == 0 && ua->argv[i]) {
633          jr->JobId = str_to_int64(ua->argv[i]);
634          jr->Job[0] = 0;
635       } else {
636          continue;
637       }
638       if (!db_get_job_record(ua->jcr, ua->db, jr)) {
639          bsendmsg(ua, _("Could not find Job \"%s\": ERR=%s"), ua->argv[i],
640                   db_strerror(ua->db));
641          jr->JobId = 0;
642          break;
643       }
644       return jr->JobId;
645    }
646
647    jr->JobId = 0;
648    jr->Job[0] = 0;
649
650    for (i=1; i<ua->argc; i++) {
651       if ((strcasecmp(ua->argk[i], N_("jobname")) == 0 ||
652            strcasecmp(ua->argk[i], N_("job")) == 0) && ua->argv[i]) {
653          jr->JobId = 0;
654          bstrncpy(jr->Name, ua->argv[i], sizeof(jr->Name));
655          break;
656       }
657    }
658    if (!select_job_dbr(ua, jr)) {  /* try once more */
659       return 0;
660    }
661    return jr->JobId;
662 }
663
664 /*
665  * Implement unique set of prompts
666  */
667 void start_prompt(UAContext *ua, const char *msg)
668 {
669   if (ua->max_prompts == 0) {
670      ua->max_prompts = 10;
671      ua->prompt = (char **)bmalloc(sizeof(char *) * ua->max_prompts);
672   }
673   ua->num_prompts = 1;
674   ua->prompt[0] = bstrdup(msg);
675 }
676
677 /*
678  * Add to prompts -- keeping them unique
679  */
680 void add_prompt(UAContext *ua, const char *prompt)
681 {
682    int i;
683    if (ua->num_prompts == ua->max_prompts) {
684       ua->max_prompts *= 2;
685       ua->prompt = (char **)brealloc(ua->prompt, sizeof(char *) *
686          ua->max_prompts);
687     }
688     for (i=1; i < ua->num_prompts; i++) {
689        if (strcmp(ua->prompt[i], prompt) == 0) {
690           return;
691        }
692     }
693     ua->prompt[ua->num_prompts++] = bstrdup(prompt);
694 }
695
696 /*
697  * Display prompts and get user's choice
698  *
699  *  Returns: -1 on error
700  *            index base 0 on success, and choice
701  *               is copied to prompt if not NULL
702  *             prompt is set to the chosen prompt item string
703  */
704 int do_prompt(UAContext *ua, const char *automsg, const char *msg, char *prompt, int max_prompt)
705 {
706    int i, item;
707    char pmsg[MAXSTRING];
708
709    if (prompt) {
710       *prompt = 0;
711    }
712    if (ua->num_prompts == 2) {
713       item = 1;
714       if (prompt) {
715          bstrncpy(prompt, ua->prompt[1], max_prompt);
716       }
717       bsendmsg(ua, _("Automatically selected %s: %s\n"), automsg, ua->prompt[1]);
718       goto done;
719    }
720    /* If running non-interactive, bail out */
721    if (ua->batch) {
722       bsendmsg(ua, _("Cannot select %s in batch mode.\n"), automsg);
723       item = -1;
724       goto done;
725    }
726 // bnet_sig(ua->UA_sock, BNET_START_SELECT);
727    bsendmsg(ua, ua->prompt[0]);
728    for (i=1; i < ua->num_prompts; i++) {
729       bsendmsg(ua, "%6d: %s\n", i, ua->prompt[i]);
730    }
731 // bnet_sig(ua->UA_sock, BNET_END_SELECT);
732
733    for ( ;; ) {
734       /* First item is the prompt string, not the items */
735       if (ua->num_prompts == 1) {
736          bsendmsg(ua, _("Selection is empty!\n"));
737          item = -1;                    /* list is empty ! */
738          break;
739       }
740       if (ua->num_prompts == 2) {
741          item = 1;
742          bsendmsg(ua, _("Item 1 selected automatically.\n"));
743          if (prompt) {
744             bstrncpy(prompt, ua->prompt[1], max_prompt);
745          }
746          break;
747       } else {
748          sprintf(pmsg, "%s (1-%d): ", msg, ua->num_prompts-1);
749       }
750       /* Either a . or an @ will get you out of the loop */
751       if (!get_pint(ua, pmsg)) {
752          item = -1;                   /* error */
753          bsendmsg(ua, _("Selection aborted, nothing done.\n"));
754          break;
755       }
756       item = ua->pint32_val;
757       if (item < 1 || item >= ua->num_prompts) {
758          bsendmsg(ua, _("Please enter a number between 1 and %d\n"), ua->num_prompts-1);
759          continue;
760       }
761       if (prompt) {
762          bstrncpy(prompt, ua->prompt[item], max_prompt);
763       }
764       break;
765    }
766
767 done:
768    for (i=0; i < ua->num_prompts; i++) {
769       free(ua->prompt[i]);
770    }
771    ua->num_prompts = 0;
772    return item>0 ? item-1 : item;
773 }
774
775
776 /*
777  * We scan what the user has entered looking for
778  *    storage=<storage-resource>
779  *    job=<job_name>
780  *    jobid=<jobid>
781  *    ?              (prompt him with storage list)
782  *    <some-error>   (prompt him with storage list)
783  *
784  * If use_default is set, we assume that any keyword without a value
785  *   is the name of the Storage resource wanted.
786  */
787 STORE *get_storage_resource(UAContext *ua, bool use_default)
788 {
789    char *store_name = NULL;
790    STORE *store = NULL;
791    int jobid;
792    JCR *jcr;
793    int i;
794    char ed1[50];
795
796    for (i=1; i<ua->argc; i++) {
797       if (use_default && !ua->argv[i]) {
798          /* Ignore slots, scan and barcode(s) keywords */
799          if (strcasecmp("scan", ua->argk[i]) == 0 ||
800              strcasecmp("barcode", ua->argk[i]) == 0 ||
801              strcasecmp("barcodes", ua->argk[i]) == 0 ||
802              strcasecmp("slots", ua->argk[i]) == 0) {
803             continue;
804          }
805          /* Default argument is storage */
806          if (store_name) {
807             bsendmsg(ua, _("Storage name given twice.\n"));
808             return NULL;
809          }
810          store_name = ua->argk[i];
811          if (*store_name == '?') {
812             *store_name = 0;
813             break;
814          }
815       } else {
816          if (strcasecmp(ua->argk[i], N_("storage")) == 0 ||
817              strcasecmp(ua->argk[i], N_("sd")) == 0) {
818             store_name = ua->argv[i];
819             break;
820
821          } else if (strcasecmp(ua->argk[i], N_("jobid")) == 0) {
822             jobid = str_to_int64(ua->argv[i]);
823             if (jobid <= 0) {
824                bsendmsg(ua, _("Expecting jobid=nn command, got: %s\n"), ua->argk[i]);
825                return NULL;
826             }
827             if (!(jcr=get_jcr_by_id(jobid))) {
828                bsendmsg(ua, _("JobId %s is not running.\n"), edit_int64(jobid, ed1));
829                return NULL;
830             }
831             store = jcr->store;
832             free_jcr(jcr);
833             break;
834
835          } else if (strcasecmp(ua->argk[i], N_("job")) == 0 ||
836                     strcasecmp(ua->argk[i], N_("jobname")) == 0) {
837             if (!ua->argv[i]) {
838                bsendmsg(ua, _("Expecting job=xxx, got: %s.\n"), ua->argk[i]);
839                return NULL;
840             }
841             if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
842                bsendmsg(ua, _("Job \"%s\" is not running.\n"), ua->argv[i]);
843                return NULL;
844             }
845             store = jcr->store;
846             free_jcr(jcr);
847             break;
848          } else if (strcasecmp(ua->argk[i], N_("ujobid")) == 0) {
849             if (!ua->argv[i]) {
850                bsendmsg(ua, _("Expecting ujobid=xxx, got: %s.\n"), ua->argk[i]);
851                return NULL;
852             }
853             if (!(jcr=get_jcr_by_full_name(ua->argv[i]))) {
854                bsendmsg(ua, _("Job \"%s\" is not running.\n"), ua->argv[i]);
855                return NULL;
856             }
857             store = jcr->store;
858             free_jcr(jcr);
859             break;
860         }
861       }
862    }
863    if (store && !acl_access_ok(ua, Storage_ACL, store->hdr.name)) {
864       store = NULL;
865    }
866
867    if (!store && store_name && store_name[0] != 0) {
868       store = (STORE *)GetResWithName(R_STORAGE, store_name);
869       if (!store) {
870          bsendmsg(ua, _("Storage resource \"%s\": not found\n"), store_name);
871       }
872    }
873    if (store && !acl_access_ok(ua, Storage_ACL, store->hdr.name)) {
874       store = NULL;
875    }
876    /* No keywords found, so present a selection list */
877    if (!store) {
878       store = select_storage_resource(ua);
879    }
880    return store;
881 }
882
883 /* Get drive that we are working with for this storage */
884 int get_storage_drive(UAContext *ua, STORE *store)
885 {
886    int i, drive = -1;
887    /* Get drive for autochanger if possible */
888    i = find_arg_with_value(ua, "drive");
889    if (i >=0) {
890       drive = atoi(ua->argv[i]);
891    } else if (store && store->autochanger) {
892       /* If our structure is not set ask SD for # drives */
893       if (store->drives == 0) {
894          store->drives = get_num_drives_from_SD(ua);
895       }
896       /* If only one drive, default = 0 */
897       if (store->drives == 1) {
898          drive = 0;
899       } else {
900          /* Ask user to enter drive number */
901          ua->cmd[0] = 0;
902          if (!get_cmd(ua, _("Enter autochanger drive[0]: "))) {
903             drive = -1;  /* None */
904          } else {
905             drive = atoi(ua->cmd);
906          }
907      }
908    }
909    return drive;
910 }
911
912
913 /*
914  * Scan looking for mediatype=
915  *
916  *  if not found or error, put up selection list
917  *
918  *  Returns: 0 on error
919  *           1 on success, MediaType is set
920  */
921 int get_media_type(UAContext *ua, char *MediaType, int max_media)
922 {
923    STORE *store;
924    int i;
925
926    i = find_arg_with_value(ua, "mediatype");
927    if (i >= 0) {
928       bstrncpy(MediaType, ua->argv[i], max_media);
929       return 1;
930    }
931
932    start_prompt(ua, _("Media Types defined in conf file:\n"));
933    LockRes();
934    foreach_res(store, R_STORAGE) {
935       add_prompt(ua, store->media_type);
936    }
937    UnlockRes();
938    return (do_prompt(ua, _("Media Type"), _("Select the Media Type"), MediaType, max_media) < 0) ? 0 : 1;
939 }
940
941 bool get_level_from_name(JCR *jcr, const char *level_name)
942 {
943    /* Look up level name and pull code */
944    bool found = false;
945    for (int i=0; joblevels[i].level_name; i++) {
946       if (strcasecmp(level_name, joblevels[i].level_name) == 0) {
947          jcr->JobLevel = joblevels[i].level;
948          found = true;
949          break;
950       }
951    }
952    return found;
953 }