]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_select.c
Apply Peter Eriksson's fixes
[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-2004 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    if (!acl_access_ok(ua, Pool_ACL, pr->Name)) {
499       bsendmsg(ua, _("No access to Pool \"%s\"\n"), pr->Name);
500       return 0;
501    }
502    return 1;
503 }
504
505 /* Select a Media (Volume) record from the database */
506 int select_media_dbr(UAContext *ua, MEDIA_DBR *mr)
507 {
508    int i;
509
510    memset(mr, 0, sizeof(MEDIA_DBR));
511
512    i = find_arg_with_value(ua, "volume");
513    if (i >= 0) {
514       bstrncpy(mr->VolumeName, ua->argv[i], sizeof(mr->VolumeName));
515    }
516    if (mr->VolumeName[0] == 0) {
517       POOL_DBR pr;
518       memset(&pr, 0, sizeof(pr));
519       /* Get the pool from pool=<pool-name> */
520       if (!get_pool_dbr(ua, &pr)) {
521          return 0;
522       }
523       mr->PoolId = pr.PoolId;
524       db_list_media_records(ua->jcr, ua->db, mr, prtit, ua, HORZ_LIST);
525       if (!get_cmd(ua, _("Enter MediaId or Volume name: "))) {
526          return 0;
527       }
528       if (is_a_number(ua->cmd)) {
529          mr->MediaId = atoi(ua->cmd);
530       } else {
531          bstrncpy(mr->VolumeName, ua->cmd, sizeof(mr->VolumeName));
532       }
533    }
534
535    if (!db_get_media_record(ua->jcr, ua->db, mr)) {
536       bsendmsg(ua, "%s", db_strerror(ua->db));
537       return 0;
538    }
539    return 1;
540 }
541
542
543 /* 
544  * Select a pool resource from prompt list
545  */
546 POOL *select_pool_resource(UAContext *ua)
547 {
548    char name[MAX_NAME_LENGTH];    
549    POOL *pool;
550
551    start_prompt(ua, _("The defined Pool resources are:\n"));
552    LockRes();
553    foreach_res(pool, R_POOL) {
554       if (acl_access_ok(ua, Pool_ACL, pool->hdr.name)) {
555          add_prompt(ua, pool->hdr.name);
556       }
557    }
558    UnlockRes();
559    do_prompt(ua, _("Pool"), _("Select Pool resource"), name, sizeof(name));
560    pool = (POOL *)GetResWithName(R_POOL, name);
561    return pool;
562 }
563
564
565 /*
566  *  If you are thinking about using it, you
567  *  probably want to use select_pool_dbr() 
568  *  or get_pool_dbr() above.
569  */
570 POOL *get_pool_resource(UAContext *ua)
571 {
572    POOL *pool = NULL;
573    int i;
574    
575    i = find_arg_with_value(ua, "pool");
576    if (i >= 0 && acl_access_ok(ua, Pool_ACL, ua->argv[i])) {
577       pool = (POOL *)GetResWithName(R_POOL, ua->argv[i]);
578       if (pool) {
579          return pool;
580       }
581       bsendmsg(ua, _("Error: Pool resource \"%s\" does not exist.\n"), ua->argv[i]);
582    }
583    return select_pool_resource(ua);
584 }
585
586 /*
587  * List all jobs and ask user to select one
588  */
589 int select_job_dbr(UAContext *ua, JOB_DBR *jr)
590 {
591    db_list_job_records(ua->jcr, ua->db, jr, prtit, ua, HORZ_LIST);
592    if (!get_pint(ua, _("Enter the JobId to select: "))) {
593       return 0;
594    }
595    jr->JobId = ua->pint32_val;
596    if (!db_get_job_record(ua->jcr, ua->db, jr)) {
597       bsendmsg(ua, "%s", db_strerror(ua->db));
598       return 0;
599    }
600    return jr->JobId;
601
602 }
603
604
605 /* Scan what the user has entered looking for:
606  * 
607  *  jobid=nn
608  *
609  *  if error or not found, put up a list of Jobs
610  *  to choose from.
611  *
612  *   returns: 0 on error
613  *            JobId on success and fills in JOB_DBR
614  */
615 int get_job_dbr(UAContext *ua, JOB_DBR *jr)
616 {
617    int i;
618
619    for (i=1; i<ua->argc; i++) {
620       if (strcasecmp(ua->argk[i], _("job")) == 0 && ua->argv[i]) {
621          jr->JobId = 0;
622          bstrncpy(jr->Job, ua->argv[i], sizeof(jr->Job));
623       } else if (strcasecmp(ua->argk[i], _("jobid")) == 0 && ua->argv[i]) {
624          jr->JobId = str_to_int64(ua->argv[i]);
625       } else {
626          continue;
627       }
628       if (!db_get_job_record(ua->jcr, ua->db, jr)) {
629          bsendmsg(ua, _("Could not find Job \"%s\": ERR=%s"), ua->argv[i],
630                   db_strerror(ua->db));
631          jr->JobId = 0;
632          break;
633       }
634       return jr->JobId;
635    }
636
637    if (!select_job_dbr(ua, jr)) {  /* try once more */
638       return 0;
639    }
640    return jr->JobId;
641 }
642
643 /*
644  * Implement unique set of prompts 
645  */
646 void start_prompt(UAContext *ua, char *msg)
647 {
648   if (ua->max_prompts == 0) {
649      ua->max_prompts = 10;
650      ua->prompt = (char **)bmalloc(sizeof(char *) * ua->max_prompts);
651   }
652   ua->num_prompts = 1;
653   ua->prompt[0] = bstrdup(msg);
654 }
655
656 /*
657  * Add to prompts -- keeping them unique 
658  */
659 void add_prompt(UAContext *ua, char *prompt)
660 {
661    int i;
662    if (ua->num_prompts == ua->max_prompts) {
663       ua->max_prompts *= 2;
664       ua->prompt = (char **)brealloc(ua->prompt, sizeof(char *) *
665          ua->max_prompts);
666     }
667     for (i=1; i < ua->num_prompts; i++) {
668        if (strcmp(ua->prompt[i], prompt) == 0) {
669           return;
670        }
671     }
672     ua->prompt[ua->num_prompts++] = bstrdup(prompt);
673 }
674
675 /*
676  * Display prompts and get user's choice
677  *
678  *  Returns: -1 on error
679  *            index base 0 on success, and choice
680  *               is copied to prompt if not NULL
681  */
682 int do_prompt(UAContext *ua, char *automsg, char *msg, char *prompt, int max_prompt)
683 {
684    int i, item;
685    char pmsg[MAXSTRING];
686
687    if (ua->num_prompts == 2) {
688       item = 1;
689       if (prompt) {
690          bstrncpy(prompt, ua->prompt[1], max_prompt);
691       }
692       bsendmsg(ua, _("Automatically selected %s: %s\n"), automsg, ua->prompt[1]);
693       goto done;
694    }
695    bsendmsg(ua, ua->prompt[0]);
696    for (i=1; i < ua->num_prompts; i++) {
697       bsendmsg(ua, "%6d: %s\n", i, ua->prompt[i]);
698    }
699
700    if (prompt) {
701       *prompt = 0;
702    }
703
704    for ( ;; ) {
705       /* First item is the prompt string, not the items */
706       if (ua->num_prompts == 1) { 
707          bsendmsg(ua, _("Selection is empty!\n"));
708          item = 0;                    /* list is empty ! */
709          break;
710       }
711       if (ua->num_prompts == 2) {
712          item = 1;
713          bsendmsg(ua, _("Item 1 selected automatically.\n"));
714          if (prompt) {
715             bstrncpy(prompt, ua->prompt[1], max_prompt);
716          }
717          break;
718       } else {
719          sprintf(pmsg, "%s (1-%d): ", msg, ua->num_prompts-1);
720       }
721       /* Either a . or an @ will get you out of the loop */
722       if (!get_pint(ua, pmsg)) {
723          item = -1;                   /* error */
724          bsendmsg(ua, _("Selection aborted, nothing done.\n"));
725          break;
726       }
727       item = ua->pint32_val;
728       if (item < 1 || item >= ua->num_prompts) {
729          bsendmsg(ua, _("Please enter a number between 1 and %d\n"), ua->num_prompts-1);
730          continue;
731       }
732       if (prompt) {
733          bstrncpy(prompt, ua->prompt[item], max_prompt);
734       }
735       break;
736    }
737                               
738 done:
739    for (i=0; i < ua->num_prompts; i++) {
740       free(ua->prompt[i]);
741    }
742    ua->num_prompts = 0;
743    return item - 1;
744 }
745
746
747 /*
748  * We scan what the user has entered looking for
749  *    storage=<storage-resource>
750  *    job=<job_name>
751  *    jobid=<jobid>
752  *    ?              (prompt him with storage list)
753  *    <some-error>   (prompt him with storage list)
754  *
755  * If use_default is set, we assume that any keyword without a value
756  *   is the name of the Storage resource wanted.
757  */
758 STORE *get_storage_resource(UAContext *ua, int use_default)
759 {
760    char *store_name = NULL;
761    STORE *store = NULL;
762    int jobid;
763    JCR *jcr;
764    int i;
765       
766
767    for (i=1; i<ua->argc; i++) {
768       if (use_default && !ua->argv[i]) {
769          /* Ignore scan and barcode(s) keywords */
770          if (strncasecmp("scan", ua->argk[i], 4) == 0 ||
771              strncasecmp("barcode", ua->argk[i], 7) == 0) {
772             continue;
773          }
774          /* Default argument is storage */
775          if (store_name) {
776             bsendmsg(ua, _("Storage name given twice.\n"));
777             return NULL;
778          }
779          store_name = ua->argk[i];
780          if (*store_name == '?') {
781             *store_name = 0;
782             break;
783          }
784       } else {
785          if (strcasecmp(ua->argk[i], _("storage")) == 0 ||
786              strcasecmp(ua->argk[i], _("sd")) == 0) {
787             store_name = ua->argv[i];
788             break;
789
790          } else if (strcasecmp(ua->argk[i], _("jobid")) == 0) {
791             jobid = str_to_int64(ua->argv[i]);
792             if (jobid <= 0) {
793                bsendmsg(ua, _("Expecting jobid=nn command, got: %s\n"), ua->argk[i]);
794                return NULL;
795             }
796             if (!(jcr=get_jcr_by_id(jobid))) {
797                bsendmsg(ua, _("JobId %d is not running.\n"), jobid);
798                return NULL;
799             }
800             store = jcr->store;
801             free_jcr(jcr);
802             break;
803
804          } else if (strcasecmp(ua->argk[i], _("job")) == 0) {
805             if (!ua->argv[i]) {
806                bsendmsg(ua, _("Expecting job=xxx, got: %s.\n"), ua->argk[i]);
807                return NULL;
808             }
809             if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
810                bsendmsg(ua, _("Job \"%s\" is not running.\n"), ua->argv[i]);
811                return NULL;
812             }
813             store = jcr->store;
814             free_jcr(jcr);
815             break;
816         }
817       }
818    }
819    if (store && !acl_access_ok(ua, Storage_ACL, store->hdr.name)) {
820       store = NULL;
821    }
822    
823    if (!store && store_name) {
824       store = (STORE *)GetResWithName(R_STORAGE, store_name);
825       if (!store) {
826          bsendmsg(ua, "Storage resource \"%s\": not found\n", store_name);
827       }
828    }
829    if (store && !acl_access_ok(ua, Storage_ACL, store->hdr.name)) {
830       store = NULL;
831    }
832    /* No keywords found, so present a selection list */
833    if (!store) {
834       store = select_storage_resource(ua);
835    }
836    return store;
837 }
838
839
840 /*
841  * Scan looking for mediatype= 
842  *
843  *  if not found or error, put up selection list
844  *
845  *  Returns: 0 on error
846  *           1 on success, MediaType is set
847  */
848 int get_media_type(UAContext *ua, char *MediaType, int max_media)
849 {
850    STORE *store;
851    int i;
852
853    i = find_arg_with_value(ua, "mediatype");
854    if (i >= 0) {
855       bstrncpy(MediaType, ua->argv[i], max_media);
856       return 1;
857    }
858
859    start_prompt(ua, _("Media Types defined in conf file:\n"));
860    LockRes();
861    foreach_res(store, R_STORAGE) {
862       add_prompt(ua, store->media_type);
863    }
864    UnlockRes();
865    return (do_prompt(ua, _("Media Type"), _("Select the Media Type"), MediaType, max_media) < 0) ? 0 : 1;
866 }