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