- Possibly up network buffers to 65K.
 - Keep last 5 or 10 completed jobs and show them in a similar list.
 - Make a Running Jobs: output similar to current Scheduled Jobs:
-- Optimize fsf not to read.
-- Use ioctl() fsf if it exists. Figure out where we are from
-  the mt_status command. Use slow fsf only if other does not work.
-- Add flag to write only one EOF mark on the tape.
-- Implement autochanger testing in btape "test" command.
 
 After 1.33:
+- Don't continue Restore if no files selected.
 - Print warning message if FileId > 4 billion
 - do a "messages" before the first prompt in Console
 - Add a date and time stamp at the beginning of every line in the 
 
 /* find.c */
 int db_find_job_start_time(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM **stime);
 int db_find_last_jobid(JCR *jcr, B_DB *mdb, char *Name, JOB_DBR *jr);
-int db_find_next_volume(JCR *jcr, B_DB *mdb, int index, MEDIA_DBR *mr);
+int db_find_next_volume(JCR *jcr, B_DB *mdb, int index, bool InChanger, MEDIA_DBR *mr);
 
 /* get.c */
 int db_get_pool_record(JCR *jcr, B_DB *db, POOL_DBR *pdbr);
 
  *         numrows on success
  */
 int
-db_find_next_volume(JCR *jcr, B_DB *mdb, int item, MEDIA_DBR *mr) 
+db_find_next_volume(JCR *jcr, B_DB *mdb, int item, bool InChanger, MEDIA_DBR *mr) 
 {
    SQL_ROW row;
    int numrows;
      item = 1;
    } else {
       /* Find next available volume */
-      Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
-          "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
-          "VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,Recycle,Slot,"
-          "FirstWritten,LastWritten,VolStatus "
-          "FROM Media WHERE PoolId=%u AND MediaType='%s' AND VolStatus='%s' "
-          "ORDER BY LastWritten", 
-          mr->PoolId, mr->MediaType, mr->VolStatus); 
+      if (InChanger) {
+         Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
+             "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
+             "VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,Recycle,Slot,"
+             "FirstWritten,LastWritten,VolStatus "
+             "FROM Media WHERE PoolId=%u AND MediaType='%s' AND VolStatus='%s' "
+             "AND InChanger=1 ORDER BY LastWritten,MediaId", 
+             mr->PoolId, mr->MediaType, mr->VolStatus); 
+      } else {
+         Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
+             "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
+             "VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,Recycle,Slot,"
+             "FirstWritten,LastWritten,VolStatus "
+             "FROM Media WHERE PoolId=%u AND MediaType='%s' AND VolStatus='%s' "
+             "ORDER BY LastWritten,MediaId", 
+             mr->PoolId, mr->MediaType, mr->VolStatus); 
+      }
    }
    if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
       db_unlock(mdb);
 
  *  Returns: 0 on error or no Volumes found
  *          number of volumes on success
  *             Volumes are concatenated in VolumeNames
- *             separated by a vertical bar (|).
+ *             separated by a vertical bar (|) in the order
+ *             that they were written.
  *
  *  Returns: number of volumes on success
  */
 
    db_lock(mdb);
    Mmsg(&mdb->cmd, 
-"SELECT VolumeName FROM JobMedia,Media WHERE JobMedia.JobId=%u "
-"AND JobMedia.MediaId=Media.MediaId GROUP BY VolumeName", JobId);
+        "SELECT VolumeName,JobMedia.VolIndex FROM JobMedia,Media WHERE "
+        "JobMedia.JobId=%u AND JobMedia.MediaId=Media.MediaId "
+        "GROUP BY VolumeName ORDER BY JobMedia.VolIndex",  JobId);
 
    Dmsg1(130, "VolNam=%s\n", mdb->cmd);
    *VolumeNames[0] = 0;
 
 {
    int retry = 0;
    bool ok;
+   bool InChanger;
 
    mr->PoolId = jcr->PoolId;
    bstrncpy(mr->MediaType, jcr->store->media_type, sizeof(mr->MediaType));
    Dmsg2(120, "CatReq FindMedia: Id=%d, MediaType=%s\n", mr->PoolId, mr->MediaType);
+   /*
+    * If we are using an Autochanger, restrict Volume 
+    *  search to the Autochanger on the first pass 
+    */
+   InChanger = jcr->store->autochanger;
    /*
     * Find the Next Volume for Append
     */
       /*
        *  1. Look for volume with "Append" status.
        */
-      ok = db_find_next_volume(jcr, jcr->db, 1, mr);  
+      ok = db_find_next_volume(jcr, jcr->db, 1, InChanger, mr);  
       Dmsg2(100, "catreq after find_next_vol ok=%d FW=%d\n", ok, mr->FirstWritten);
       if (!ok) {
         /*
          * 2. Try finding a recycled volume
          */
-        ok = find_recycled_volume(jcr, mr);
+        ok = find_recycled_volume(jcr, InChanger, mr);
          Dmsg2(100, "find_recycled_volume %d FW=%d\n", ok, mr->FirstWritten);
         if (!ok) {
            /*
             * 3. Try pruning Volumes
             */
            prune_volumes(jcr);  
-           ok = recycle_oldest_purged_volume(jcr, mr);
+           ok = recycle_oldest_purged_volume(jcr, InChanger, mr);
+           if (InChanger) {
+              InChanger = false;
+              if (!ok) {
+                 continue;           /* retry again accepting any volume */
+              }
+           }
             Dmsg2(200, "find_recycled_volume2 %d FW=%d\n", ok, mr->FirstWritten);
            if (!ok && create) {
               /*
             Dmsg2(200, "No next volume found. PurgeOldest=%d\n RecyleOldest=%d",
                jcr->pool->purge_oldest_volume, jcr->pool->recycle_oldest_volume);
            /* Find oldest volume to recycle */
-           ok = db_find_next_volume(jcr, jcr->db, -1, mr);
+           ok = db_find_next_volume(jcr, jcr->db, -1, InChanger, mr);
             Dmsg1(400, "Find oldest=%d\n", ok);
            if (ok) {
               UAContext *ua;
 
 extern int prune_volumes(JCR *jcr);
 
 /* autorecycle.c */
-extern int recycle_oldest_purged_volume(JCR *jcr, MEDIA_DBR *mr);
+extern int recycle_oldest_purged_volume(JCR *jcr, bool InChanger, MEDIA_DBR *mr);
 extern int recycle_volume(JCR *jcr, MEDIA_DBR *mr);
-extern int find_recycled_volume(JCR *jcr, MEDIA_DBR *mr);
+extern int find_recycled_volume(JCR *jcr, bool InChanger, MEDIA_DBR *mr);
 
 /* backup.c */
 extern int wait_for_job_termination(JCR *jcr);
 
 /* fd_cmds.c */
 extern int connect_to_file_daemon(JCR *jcr, int retry_interval,
-                                 int max_retry_time, int verbose);
+                                  int max_retry_time, int verbose);
 extern int send_include_list(JCR *jcr);
 extern int send_exclude_list(JCR *jcr);
 extern int send_bootstrap_file(JCR *jcr);
 extern int get_attributes_and_put_in_catalog(JCR *jcr);
 extern int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId);
 extern int put_file_into_catalog(JCR *jcr, long file_index, char *fname, 
-                         char *link, char *attr, int stream);
+                          char *link, char *attr, int stream);
 extern void get_level_since_time(JCR *jcr, char *since, int since_len);
 extern int send_run_before_and_after_commands(JCR *jcr);
 
 
 /* msgchan.c */
 extern int connect_to_storage_daemon(JCR *jcr, int retry_interval,    
-                             int max_retry_time, int verbose);
+                              int max_retry_time, int verbose);
 extern int start_storage_daemon_job(JCR *jcr);
 extern int start_storage_daemon_message_thread(JCR *jcr);
 extern int bget_dirmsg(BSOCK *bs);
 void free_ua_context(UAContext *ua);
 
 /* ua_select.c */
-STORE  *select_storage_resource(UAContext *ua);
-JOB    *select_job_resource(UAContext *ua);
-JOB    *select_restore_job_resource(UAContext *ua);
-CLIENT *select_client_resource(UAContext *ua);
+STORE   *select_storage_resource(UAContext *ua);
+JOB     *select_job_resource(UAContext *ua);
+JOB     *select_restore_job_resource(UAContext *ua);
+CLIENT  *select_client_resource(UAContext *ua);
 FILESET *select_fileset_resource(UAContext *ua);
-int    select_pool_and_media_dbr(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr);
-int    select_media_dbr(UAContext *ua, MEDIA_DBR *mr);
-int    select_pool_dbr(UAContext *ua, POOL_DBR *pr);
-int    select_client_dbr(UAContext *ua, CLIENT_DBR *cr);
-
-void   start_prompt(UAContext *ua, char *msg);
-void   add_prompt(UAContext *ua, char *prompt);
-int    do_prompt(UAContext *ua, char *automsg, char *msg, char *prompt, int max_prompt);
-CAT    *get_catalog_resource(UAContext *ua);          
+int     select_pool_and_media_dbr(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr);
+int     select_media_dbr(UAContext *ua, MEDIA_DBR *mr);
+int     select_pool_dbr(UAContext *ua, POOL_DBR *pr);
+int     select_client_dbr(UAContext *ua, CLIENT_DBR *cr);
+
+void    start_prompt(UAContext *ua, char *msg);
+void    add_prompt(UAContext *ua, char *prompt);
+int     do_prompt(UAContext *ua, char *automsg, char *msg, char *prompt, int max_prompt);
+CAT    *get_catalog_resource(UAContext *ua);           
 STORE  *get_storage_resource(UAContext *ua, int use_default);
-int    get_media_type(UAContext *ua, char *MediaType, int max_media);
-int    get_pool_dbr(UAContext *ua, POOL_DBR *pr);
-int    get_client_dbr(UAContext *ua, CLIENT_DBR *cr);
+int     get_media_type(UAContext *ua, char *MediaType, int max_media);
+int     get_pool_dbr(UAContext *ua, POOL_DBR *pr);
+int     get_client_dbr(UAContext *ua, CLIENT_DBR *cr);
 POOL   *get_pool_resource(UAContext *ua);
 POOL   *select_pool_resource(UAContext *ua);
 CLIENT *get_client_resource(UAContext *ua);
-int    get_job_dbr(UAContext *ua, JOB_DBR *jr);
+int     get_job_dbr(UAContext *ua, JOB_DBR *jr);
 
 int find_arg_keyword(UAContext *ua, char **list);
 int find_arg(UAContext *ua, char *keyword);
 
 
 /* Forward referenced functions */
 
-int find_recycled_volume(JCR *jcr, MEDIA_DBR *mr)
+int find_recycled_volume(JCR *jcr, bool InChanger, MEDIA_DBR *mr)
 {
-   strcpy(mr->VolStatus, "Recycle");
-   if (db_find_next_volume(jcr, jcr->db, 1, mr)) {
+   bstrncpy(mr->VolStatus, "Recycle", sizeof(mr->VolStatus));
+   if (db_find_next_volume(jcr, jcr->db, 1, InChanger, mr)) {
       jcr->MediaId = mr->MediaId;
       Dmsg1(20, "Find_next_vol MediaId=%d\n", jcr->MediaId);
       pm_strcpy(&jcr->VolumeName, mr->VolumeName);
 /*
  *   Look for oldest Purged volume
  */
-int recycle_oldest_purged_volume(JCR *jcr, MEDIA_DBR *mr)
+int recycle_oldest_purged_volume(JCR *jcr, bool InChanger, MEDIA_DBR *mr)
 {
    struct s_oldest_ctx oldest;
    POOLMEM *query = get_pool_memory(PM_EMSG);
-   char *select =
-          "SELECT MediaId, LastWritten FROM Media "
+   char *select1 =
+          "SELECT MediaId,LastWritten FROM Media "
+          "WHERE PoolId=%u AND Recycle=1 AND VolStatus=\"Purged\" "
+          "AND MediaType=\"%s\" AND InChanger=1";
+   char *select2 =
+          "SELECT MediaId,LastWritten FROM Media "
           "WHERE PoolId=%u AND Recycle=1 AND VolStatus=\"Purged\" "
           "AND MediaType=\"%s\"";
 
+
    Dmsg0(100, "Enter recycle_oldest_purged_volume\n");
    oldest.MediaId = 0;
    bstrncpy(oldest.LastWritten, "9999-99-99 99:99:99", sizeof(oldest.LastWritten));
-   Mmsg(&query, select, mr->PoolId, mr->MediaType);
+   if (InChanger) {
+      Mmsg(&query, select1, mr->PoolId, mr->MediaType);
+   } else {
+      Mmsg(&query, select2, mr->PoolId, mr->MediaType);
+   }
+
    if (!db_sql_query(jcr->db, query, oldest_handler, (void *)&oldest)) {
       Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
       Dmsg0(100, "Exit 0  recycle_oldest_purged_volume query\n");
 
  { N_("estimate"),   estimate_cmd,  _("performs FileSet estimate, listing gives full listing")},
  { N_("exit"),       quit_cmd,      _("exit = quit")},
  { N_("help"),       help_cmd,      _("print this command")},
- { N_("list"),       list_cmd,      _("list [pools | jobs | jobtotals | media <pool> | files job=<nn>]; from catalog")},
+ { N_("list"),       list_cmd,      _("list [pools | jobs | jobtotals | media <pool> | files jobid=<nn>]; from catalog")},
  { N_("label"),      label_cmd,     _("label a tape")},
  { N_("llist"),      llist_cmd,     _("full or long list like list command")},
  { N_("messages"),   messagescmd,   _("messages")},
 
 #undef  VERSION
 #define VERSION "1.33"
 #define VSTRING "1"
-#define BDATE   "18 Nov 2003"
-#define LSMDATE "18Nov03"
+#define BDATE   "20 Nov 2003"
+#define LSMDATE "20Nov03"
 
 /* Debug flags */
 #undef  DEBUG