home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 24 / AACD 24.iso / AACD / Utilities / PdaLink / examples / PdaTransfer.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-07-17  |  21.0 KB  |  884 lines

  1. /*********************************************************************
  2. **                                                                  **
  3. **        PdaTransfer     -- Data dialog between Amiga and Palm     **
  4. **                                                                  **
  5. *********************************************************************/
  6. /*
  7. **  Copyright © 1998-2000 Richard Körber  --  All Rights Reserved
  8. **    E-Mail: rkoerber@gmx.de
  9. **    URL:    http://shredzone.home.pages.de
  10. **
  11. ***************************************************************/
  12. /*
  13. **  This program is free software; you can redistribute it and/or modify
  14. **  it under the terms of the GNU General Public License as published by
  15. **  the Free Software Foundation; either version 2 of the License, or
  16. **  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
  21. **  GNU General Public License for more details.
  22. **
  23. **  You should have received a copy of the GNU General Public License
  24. **  along with this program; if not, write to the Free Software
  25. **  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  26. **
  27. **  The author (Richard Körber) reserves the right to revoke the
  28. **  GNU General Public License whenever he feels that it is necessary,
  29. **  especially when he found out that the licence has been abused,
  30. **  ignored or violated, and without prior notice.
  31. **
  32. **  You must not use this source code to gain profit of any kind!
  33. **
  34. ***************************************************************/
  35. /*
  36. **  Compiles with SAS/C, e.g.
  37. **      sc PdaTransfer.c NOSTACKCHECK DATA=NEAR STRMER CPU=68060 OPT
  38. */
  39.  
  40. #include <stdio.h>
  41. #include <string.h>
  42. #include <clib/alib_protos.h>
  43. #include <clib/exec_protos.h>
  44. #include <clib/dos_protos.h>
  45. #include <clib/utility_protos.h>
  46. #include <clib/pdalink_protos.h>
  47. #include <pragmas/exec_pragmas.h>
  48. #include <pragmas/dos_pragmas.h>
  49. #include <pragmas/utility_pragmas.h>
  50. #include <pragmas/pdalink_pragmas.h>
  51. #include <exec/memory.h>
  52. #include <dos/dos.h>
  53. #include <dos/dosasl.h>
  54. #include <libraries/pdalink.h>
  55.  
  56.  
  57. #define  VERSIONSTR   "1.1"
  58. #define  DATESTR      "7.1.2000"
  59. #define  COPYRIGHTSTR "2000"
  60. #define  EMAILSTR     "rkoerber@gmx.de"
  61. #define  URLSTR       "http://shredzone.home.pages.de"
  62.  
  63. #define  NORMAL       "\2330m"
  64. #define  BOLD         "\2331m"
  65. #define  ITALIC       "\2333m"
  66. #define  UNDERLINE    "\2334m"
  67.  
  68. #define  MKTAG(a,b,c,d)  ((ULONG) (a)<<24 | (ULONG) (b)<<16 | (ULONG) (c)<<8 | (ULONG) (d))
  69.  
  70. static char ver[] = "$VER: PdaTransfer " VERSIONSTR " (" DATESTR ") " EMAILSTR;
  71. static char titletxt[] = \
  72.   BOLD "PdaTransfer " VERSIONSTR " (C) " COPYRIGHTSTR " Richard Körber -- all rights reserved" NORMAL "\n\n";
  73. static char helptxt[] = \
  74.   "  " ITALIC "E-Mail: " NORMAL EMAILSTR "\n"
  75.   "  " ITALIC "URL:    " NORMAL URLSTR "\n\n"
  76.   ITALIC "Usage:" NORMAL "\n"
  77.   "  BACKUP/S       Backup the database (DIR)\n"
  78.   "  RESTORE/S      Restore a backup (DIR)\n"
  79.   "  INSTALL/S      Install a file (FILE)\n"
  80.   "  MERGE/S        Merge a file (FILE)\n"
  81.   "  FETCH/S        Fetch a database (NAME)\n"
  82.   "  DELETE/S       Delete a database (NAME)\n"
  83.   "  LIST/S         List all databases\n"
  84.   "  PURGE/S        Purge deleted records\n"
  85.   "  DIR/K          Backup directory (if required)\n"
  86.   "  FILE/K         Filename (if required)\n"
  87.   "  NAME/K         Database name (if required)\n"
  88.   "  DEVICE/K       Serial device (\"serial.device\")\n"
  89.   "  UNIT/K/N       Serial unit (0)\n"
  90.   "  MAXBAUD/K/N    Maximum baud (57600)\n"
  91.   "\n";
  92.  
  93. struct Parameter
  94. {
  95.   LONG   backup;
  96.   LONG   restore;
  97.   LONG   install;
  98.   LONG   merge;
  99.   LONG   fetch;
  100.   LONG   delete;
  101.   LONG   list;
  102.   LONG   purge;
  103.   STRPTR dir;
  104.   STRPTR file;
  105.   STRPTR name;
  106.   STRPTR device;
  107.   LONG   *unit;
  108.   LONG   *maxbaud;
  109. }
  110. param;
  111.  
  112. static char template[] = "BACKUP/S,RESTORE/S,INSTALL/S,MERGE/S,FETCH/S,DELETE/S,LIST/S,PURGE/S,D=DIR/K,F=FILE/K,N=NAME/K,SD=DEVICE/K,SU=UNIT/K/N,SB=MAXBAUD/K/N";
  113.  
  114. struct FileNode
  115. {
  116.   struct Node Node;         // Backup/Restore
  117.   struct DateStamp Date;    // Backup only
  118.   struct DLP_DBInfo dbinfo; // Restore only
  119.   char FileName[108];       // Backup/Restore
  120. };
  121.  
  122. extern struct DOSBase *DOSBase;
  123. struct Library *PdalinkBase;
  124. struct Library *UtilityBase;
  125. APTR socket = NULL;
  126. BOOL ignoreError = FALSE;
  127.  
  128.  
  129.  
  130. /*
  131. ** get last error code as string
  132. */
  133. STRPTR getError(APTR socket)
  134. {
  135.   static unsigned char errortext[256];
  136.   PL_Explain(PL_LastError(socket),errortext,255);
  137.   return(errortext);
  138. }
  139.  
  140. /*
  141. ** Open a connection to the Pilot
  142. */
  143. int Connect(void)
  144. {
  145.   LONG error;
  146.  
  147.   if(socket) return(TRUE);
  148.  
  149.   socket = PL_OpenSocketTags
  150.     (
  151.     PLTAG_ErrorPtr      , &error,
  152.     (param.device  ? PLTAG_SerialDevice  : TAG_IGNORE) , param.device,
  153.     (param.unit    ? PLTAG_SerialUnit    : TAG_IGNORE) , *param.unit ,
  154.     (param.maxbaud ? PLTAG_SerialMaxRate : TAG_IGNORE) , *param.maxbaud,
  155.     PLTAG_AbortMask     , SIGBREAKF_CTRL_C,
  156.     TAG_DONE
  157.     );
  158.  
  159.   if(socket)
  160.   {
  161.     Printf("Please press the HotSync button " ITALIC "now" NORMAL "\n");
  162.     if(PL_Accept(socket,10L)) {
  163.       Printf("Connection established, %ld bps\n",PL_GetBaudRate(socket));
  164.       return(TRUE);
  165.     }
  166.   }
  167.   else
  168.   {
  169.     unsigned char errortext[256];
  170.     PL_Explain(error,errortext,255);
  171.     Printf("** Socket error: %s\n",errortext);
  172.   }
  173.   return(FALSE);
  174. }
  175.  
  176. /*
  177. ** Close all databases and disconnect
  178. */
  179. void Disconnect(void)
  180. {
  181.   if(!socket) return;
  182.   DLP_AddSyncLogEntry(socket,"Synchronized with PdaLink\n-- AMIGA made it possible --\n");
  183.   DLP_EndOfSync(socket,0);
  184.   PL_CloseSocket(socket);
  185. }
  186.  
  187. /*
  188. ** Generate a AmigaDOS conformous file name from the
  189. ** DataBase name.
  190. */
  191. void genFileName(STRPTR name, struct DLP_DBInfo *dbinfo)
  192. {
  193.   UWORD i;
  194.  
  195.   strcpy(name,dbinfo->name);
  196.   for(i=0; i<strlen(name); i++)
  197.     if(name[i]<' ' || name[i]=='/' || name[i]==':') name[i]='_';  // Protect DOS characters
  198.   if(dbinfo->flags & DLPDBIF_RESOURCE)
  199.     strcat(name,".prc");
  200.   else
  201.     strcat(name,".pdb");
  202. }
  203.  
  204.  
  205. /*
  206. ** Convert a DLP_SysTime to a DOS DateStamp
  207. */
  208. void Date2Stamp(struct DLP_SysTime *time, struct DateStamp *ds)
  209. {
  210.   struct ClockData cld;
  211.   ULONG sec;
  212.  
  213.   cld.year  = time->year;
  214.   cld.month = time->month;
  215.   cld.mday  = time->day;
  216.   cld.hour  = time->hour;
  217.   cld.min   = time->minute;
  218.   cld.sec   = time->second;
  219.   sec = Date2Amiga(&cld);
  220.  
  221.   ds->ds_Tick   = (sec%60) * TICKS_PER_SECOND;
  222.   sec /= 60;
  223.   ds->ds_Minute = sec%(24*60);
  224.   sec /= 24*60;
  225.   ds->ds_Days   = sec;
  226. }
  227.  
  228. /*
  229. ** Convert a DOS DateStamp to DLP_SysTime
  230. */
  231. void Stamp2Date(struct DateStamp *ds, struct DLP_SysTime *time)
  232. {
  233.   struct ClockData cld;
  234.  
  235.   Amiga2Date(((ds->ds_Days*24*60)+ds->ds_Minute)*60+(ds->ds_Tick/TICKS_PER_SECOND),&cld);
  236.   time->year   = cld.year;
  237.   time->month  = cld.month;
  238.   time->day    = cld.mday;
  239.   time->hour   = cld.hour;
  240.   time->minute = cld.min;
  241.   time->second = cld.sec;
  242. }
  243.  
  244. /*
  245. ** Set a DLP_SysTime to the current date and time
  246. */
  247. void setToday(struct DLP_SysTime *time)
  248. {
  249.   struct DateStamp ds;
  250.   DateStamp(&ds);
  251.   Stamp2Date(&ds,time);
  252. }
  253.  
  254.  
  255. /*
  256. ** Set the Pilot into a synchronized state
  257. */
  258. void VoidSyncFlags(void)
  259. {
  260.   struct DLP_UserInfo user;
  261.   if(Connect())
  262.   {
  263.     if(DLP_GetUserInfo(socket,&user))
  264.     {
  265.       user.lastSyncPC = 0x00000000;     // Hopefully unique...
  266.       setToday(&user.successfulSync);
  267.       setToday(&user.lastSync);
  268.       DLP_SetUserInfo(socket,&user);
  269.     }
  270.   }
  271. }
  272.  
  273.  
  274. /*
  275. ** Backup a database
  276. */
  277. void cmd_backup(STRPTR dir)
  278. {
  279.   APTR fh;
  280.   BPTR lock;
  281.   BPTR olddir;
  282.   struct FileInfoBlock *fib;
  283.   struct List files;
  284.   struct FileNode *newnode;
  285.   struct FileNode *currEntry, *nextEntry;
  286.   struct DLP_DBInfo dbinfo;
  287.   struct DLP_SysTime time;
  288.   struct DateStamp stamp;
  289.  
  290.   UWORD i;
  291.   char filename[100];
  292.  
  293.   NewList(&files);
  294.  
  295.   if(!dir)
  296.   {
  297.     PutStr("** DIR required\n");
  298.     return;
  299.   }
  300.  
  301.   /* Check if existing, and if it is really a directory */
  302.   if(!(fib = AllocVec(sizeof(struct FileInfoBlock),MEMF_PUBLIC))) return;
  303.   lock = Lock(dir,ACCESS_READ);
  304.   if(!lock)                             // Does not exist, so create it
  305.   {
  306.     lock = CreateDir(dir);
  307.     if(!lock)                           // Couldn't create either
  308.     {
  309.       Printf("** Couldn't create directory %s\n",dir);
  310.       FreeVec(fib);
  311.       return;
  312.     }
  313.   }
  314.  
  315.   if(!Examine(lock,fib))
  316.   {
  317.     Printf("** Couldn't examine directory %s\n",dir);
  318.     goto error;
  319.   }
  320.   if(fib->fib_DirEntryType < 0)
  321.   {
  322.     Printf("** %s is not a directory\n",dir);
  323.     goto error;
  324.   }
  325.  
  326.   olddir = CurrentDir(lock);
  327.  
  328.   /* Read all file names into the files list */
  329.   while(ExNext(lock,fib))
  330.   {
  331.     if(fib->fib_DirEntryType > 0) continue;   // Skip subdirectories
  332.  
  333.     newnode = AllocVec(sizeof(struct FileNode),MEMF_ANY);
  334.     if(!newnode) goto error;
  335.  
  336.     CopyMem(fib->fib_FileName,newnode->FileName,108);
  337.     CopyMem(&fib->fib_Date,&newnode->Date,sizeof(struct DateStamp));
  338.     newnode->Node.ln_Name = newnode->FileName;
  339.     AddTail(&files,(struct Node *)newnode);
  340.   }
  341.  
  342.   /* Open conduit */
  343.   if(!Connect()) goto error;
  344.  
  345.   /* Backup all database entries */
  346.   for(i=0;;)
  347.   {
  348.     if(!DLP_OpenConduit(socket)) goto error;
  349.     if(!DLP_GetDBInfo(socket,0,DLPGDBF_RAM,i,&dbinfo))    // get the next entry
  350.     {
  351.       if(PL_LastError(socket)==PLERR_NOTFOUND) break;     // last one
  352.       goto error;
  353.     }
  354.     i = dbinfo.index+1;
  355.     genFileName(filename,&dbinfo);
  356.     newnode = (struct FileNode *)FindName(&files,filename);   // search for the file
  357.     if(newnode)                                           // File does already exist
  358.     {
  359.       Stamp2Date(&newnode->Date,&time);                   // Check if the file has
  360.       if(  (time.year   == dbinfo.modifyDate.year)        // not been modified since
  361.          &&(time.month  == dbinfo.modifyDate.month)       // last backup
  362.          &&(time.day    == dbinfo.modifyDate.day)
  363.          &&(time.hour   == dbinfo.modifyDate.hour)
  364.          &&(time.minute == dbinfo.modifyDate.minute)
  365.          &&(time.second == dbinfo.modifyDate.second))
  366.       {
  367.         Printf("  Skipped: %s (not changed)\n",newnode->FileName);
  368.         Remove((struct Node *)newnode);                   // yes: skip it
  369.         FreeVec(newnode);
  370.         continue;
  371.       }
  372.     }
  373.  
  374.     /* Retrieve the file */
  375.     dbinfo.flags &= ~DLPDBIF_OPEN;                        // Saved database is not open
  376.  
  377.     fh = PL_FileOpen(filename,&dbinfo);
  378.     if(!fh)
  379.     {
  380.       Printf("** Unable to open file %s for writing\n",filename);
  381.       goto error;
  382.     }
  383.     Printf("  Store:   %s (from %s)... ",filename,dbinfo.name);
  384.     Flush(Output());
  385.     if(PL_FileRetrieve(fh,socket,0))                      // Get the file
  386.       PutStr("OK\n");
  387.     else
  388.       Printf("Failed (%s)\n",getError(socket));
  389.     PL_FileClose(fh);
  390.  
  391.     Date2Stamp(&dbinfo.modifyDate,&stamp);                // Set file date to the
  392.     SetFileDate(filename,&stamp);                         // last modification date
  393.  
  394.     if(newnode)
  395.     {
  396.       Remove((struct Node *)newnode);                     // Remove from list
  397.       FreeVec(newnode);
  398.     }
  399.   }
  400.  
  401.   /* Delete all remaining files */
  402.   for
  403.   (
  404.     currEntry=(struct FileNode *)files.lh_Head;
  405.     nextEntry=(struct FileNode *)currEntry->Node.ln_Succ;
  406.     currEntry=nextEntry
  407.   )
  408.   {
  409.     Printf("  Delete:  %s...\n",currEntry->FileName);     // Is deleted on the Pilot too
  410.     Flush(Output());
  411.     if(DeleteFile(currEntry->FileName))
  412.       PutStr("OK\n");
  413.     else
  414.       Printf("Failed (%s)\n",getError(socket));
  415.     Remove((struct Node *)currEntry);
  416.     FreeVec(currEntry);
  417.   }
  418.  
  419.   VoidSyncFlags();                                        // Sync done
  420.  
  421.   PutStr("Backup completed successfully\n");
  422.  
  423. error:
  424.   if(PL_LastError(socket)==PLERR_NOTFOUND) ignoreError = TRUE;
  425.   CurrentDir(olddir);
  426.   for                                                     // Clean up all memory
  427.   (
  428.     currEntry=(struct FileNode *)files.lh_Head;
  429.     nextEntry=(struct FileNode *)currEntry->Node.ln_Succ;
  430.     currEntry=nextEntry
  431.   )
  432.   {
  433.     Remove((struct Node *)currEntry),
  434.     FreeVec(currEntry);
  435.   }
  436.   FreeVec(fib);                         // Release FIB
  437.   UnLock(lock);                         // Free directory lock
  438.   return;
  439. }
  440.  
  441. /*
  442. ** Restore a database
  443. */
  444. void cmd_restore(STRPTR dir)
  445. {
  446.   APTR fh;
  447.   BPTR lock;
  448.   BPTR olddir;
  449.   struct FileInfoBlock *fib;
  450.   struct List files;
  451.   struct FileNode *newnode;
  452.   struct FileNode *currEntry, *nextEntry;
  453.  
  454.   NewList(&files);
  455.  
  456.   if(!dir)
  457.   {
  458.     PutStr("** DIR required\n");
  459.     return;
  460.   }
  461.  
  462.   /* Check if existing, and if it is really a directory */
  463.   if(!(fib = AllocVec(sizeof(struct FileInfoBlock),MEMF_PUBLIC))) return;
  464.   lock = Lock(dir,ACCESS_READ);
  465.   if(!lock)                             // Does not exist
  466.   {
  467.     Printf("** Couldn't find directory %s\n",dir);
  468.     FreeVec(fib);
  469.     return;
  470.   }
  471.  
  472.   if(!Examine(lock,fib))
  473.   {
  474.     Printf("** Couldn't examine directory %s\n",dir);
  475.     goto error;
  476.   }
  477.   if(fib->fib_DirEntryType < 0)
  478.   {
  479.     Printf("** %s is not a directory\n",dir);
  480.     goto error;
  481.   }
  482.  
  483.   olddir = CurrentDir(lock);            // Set as current dir
  484.  
  485.   /* Read all file names into the files list */
  486.   while(ExNext(lock,fib))
  487.   {
  488.     if(fib->fib_DirEntryType > 0) continue;   // Skip subdirectories
  489.  
  490.     newnode = AllocVec(sizeof(struct FileNode),MEMF_ANY);
  491.     if(!newnode) goto error;
  492.  
  493.     CopyMem(fib->fib_FileName,newnode->FileName,108);
  494.     newnode->Node.ln_Name = newnode->FileName;
  495.     CopyMem(&fib->fib_Date,&newnode->Date,sizeof(struct DateStamp));
  496.  
  497.     fh = PL_FileOpen(newnode->FileName,NULL);
  498.     if(!fh)
  499.     {
  500.       Printf("** Unable to open file %s for reading\n",newnode->FileName);
  501.       goto error;
  502.     }
  503.     CopyMem(PL_FileGetDBInfo(fh),&newnode->dbinfo,sizeof(struct DLP_DBInfo));
  504.     PL_FileClose(fh);
  505.  
  506.     if(newnode->dbinfo.type == MKTAG('a','p','p','l'))
  507.       AddTail(&files,(struct Node *)newnode);         // send 'appl' as last
  508.     else
  509.       AddHead(&files,(struct Node *)newnode);
  510.   }
  511.  
  512.   /* Open connection */
  513.   if(!Connect()) goto error;
  514.  
  515.   /* Restore all database files */
  516.   for
  517.   (
  518.     currEntry=(struct FileNode *)files.lh_Head;
  519.     nextEntry=(struct FileNode *)currEntry->Node.ln_Succ;
  520.     currEntry=nextEntry
  521.   )
  522.   {
  523.     if(!DLP_OpenConduit(socket)) goto error;
  524.     fh = PL_FileOpen(currEntry->FileName,NULL);
  525.     if(!fh)
  526.     {
  527.       Printf("** Unable to open file %s\n",currEntry->FileName);
  528.       goto error;
  529.     }
  530.     Printf("  Restore: %s as %s...",currEntry->FileName,currEntry->dbinfo.name);
  531.     Flush(Output());
  532.     if(PL_FileInstall(fh,socket,0))
  533.       PutStr("OK\n");
  534.     else
  535.       Printf("Failed (%s)\n",getError(socket));
  536.     PL_FileClose(fh);
  537.     Remove((struct Node *)currEntry);
  538.     FreeVec(currEntry);
  539.   }
  540.  
  541.   PutStr("Restore completed successfully\n");
  542.   VoidSyncFlags();                                        // Sync done
  543.  
  544. error:
  545.   if(PL_LastError(socket)==PLERR_NOTFOUND) ignoreError = TRUE;
  546.   CurrentDir(olddir);
  547.   for                                                     // Clean up all memory
  548.   (
  549.     currEntry=(struct FileNode *)files.lh_Head;
  550.     nextEntry=(struct FileNode *)currEntry->Node.ln_Succ;
  551.     currEntry=nextEntry
  552.   )
  553.   {
  554.     Remove((struct Node *)currEntry),
  555.     FreeVec(currEntry);
  556.   }
  557.   FreeVec(fib);                         // Release FIB
  558.   UnLock(lock);                         // Free directory lock
  559.   return;
  560. }
  561.  
  562.  
  563. /*
  564. ** Install a software
  565. */
  566. void cmd_install(STRPTR file)
  567. {
  568.   APTR fh;
  569.  
  570.   if(!file)
  571.   {
  572.     PutStr("** FILE required\n");
  573.     return;
  574.   }
  575.  
  576.   if(!Connect()) return;
  577.   if(!DLP_OpenConduit(socket)) return;
  578.  
  579.   fh = PL_FileOpen(file,NULL);
  580.   if(!fh)
  581.   {
  582.     Printf("** Unable to open file %s\n",file);
  583.     return;
  584.   }
  585.   Printf("Installing %s...",file);
  586.   Flush(Output());
  587.   if(PL_FileInstall(fh,socket,0))
  588.     PutStr("OK\n");
  589.   else
  590.     Printf("Failed (%s)\n",getError(socket));
  591.  
  592.   PL_FileClose(fh);
  593.   VoidSyncFlags();
  594. }
  595.  
  596. /*
  597. ** Merge a software
  598. */
  599. void cmd_merge(STRPTR file)
  600. {
  601.   APTR fh;
  602.  
  603.   if(!file)
  604.   {
  605.     PutStr("** FILE required\n");
  606.     return;
  607.   }
  608.  
  609.   if(!Connect()) return;
  610.   if(!DLP_OpenConduit(socket)) return;
  611.  
  612.   fh = PL_FileOpen(file,NULL);
  613.   if(!fh)
  614.   {
  615.     Printf("** Unable to open file %s\n",file);
  616.     return;
  617.   }
  618.   Printf("Merging %s...",file);
  619.   Flush(Output());
  620.   if(PL_FileMerge(fh,socket,0))
  621.     PutStr("OK\n");
  622.   else
  623.     Printf("Failed (%s)\n",getError(socket));
  624.  
  625.   PL_FileClose(fh);
  626.   VoidSyncFlags();
  627. }
  628.  
  629. /*
  630. ** Fetch a database
  631. */
  632. void cmd_fetch(STRPTR name)
  633. {
  634.   struct DLP_DBInfo dbinfo;
  635.   UWORD index;
  636.   BOOL found;
  637.   char filename[50];
  638.   APTR fh;
  639.  
  640.   if(!name)
  641.   {
  642.     PutStr("** NAME required\n");
  643.     return;
  644.   }
  645.  
  646.   if(!Connect()) return;
  647.   if(!DLP_OpenConduit(socket)) return;
  648.  
  649.   for(found=TRUE, index=0;;)
  650.   {
  651.     if(DLP_GetDBInfo(socket,0,DLPGDBF_RAM,index,&dbinfo))
  652.     {
  653.       if(!strcmp(name,dbinfo.name)) break;
  654.       index = dbinfo.index+1;
  655.     }
  656.     else
  657.     {
  658.       found=FALSE;
  659.       break;
  660.     }
  661.   }
  662.  
  663.   if(!found)
  664.     for(found=TRUE, index=0;;)
  665.     {
  666.       if(DLP_GetDBInfo(socket,0,DLPGDBF_ROM,index,&dbinfo))
  667.       {
  668.         if(!strcmp(name,dbinfo.name)) break;
  669.         index = dbinfo.index+1;
  670.       }
  671.       else
  672.       {
  673.         found=FALSE;
  674.         break;
  675.       }
  676.     }
  677.  
  678.   if(!found)
  679.   {
  680.     Printf("** Database %s not found\n",name);
  681.     return;
  682.   }
  683.  
  684.   genFileName(filename,&dbinfo);
  685.  
  686.   dbinfo.flags &= ~DLPDBIF_OPEN;      // Saved database is not open
  687.  
  688.   fh = PL_FileOpen(filename,&dbinfo);
  689.   if(!fh)
  690.   {
  691.     Printf("** Unable to open file %s\n",filename);
  692.     return;
  693.   }
  694.  
  695.   Printf("Fetching %s to file %s... ",name,filename);
  696.   Flush(Output());
  697.   if(PL_FileRetrieve(fh,socket,0))
  698.     PutStr("OK\n");
  699.   else
  700.     Printf("Failed (%s)\n",getError(socket));
  701.  
  702.   PL_FileClose(fh);
  703. }
  704.  
  705. /*
  706. ** Delete a database
  707. */
  708. void cmd_delete(STRPTR name)
  709. {
  710.   struct DLP_DBInfo dbinfo = {0};
  711.   UWORD index;
  712.   BOOL found;
  713.  
  714.   if(!name)
  715.   {
  716.     PutStr("** NAME required\n");
  717.     return;
  718.   }
  719.  
  720.   if(!Connect()) return;
  721.   if(!DLP_OpenConduit(socket)) return;
  722.  
  723.   for(found=TRUE, index=0;;)
  724.   {
  725.     if(DLP_GetDBInfo(socket,0,DLPGDBF_RAM,index,&dbinfo))
  726.     {
  727.       if(!strcmp(name,dbinfo.name)) break;
  728.       index = dbinfo.index+1;
  729.     }
  730.     else
  731.     {
  732.       found=FALSE;
  733.       break;
  734.     }
  735.   }
  736.  
  737.   if(!found)
  738.   {
  739.     Printf("** Database %s not found\n",name);
  740.     return;
  741.   }
  742.  
  743.   Printf("Deleting %s... ",name);
  744.   Flush(Output());
  745.  
  746.   if(!DLP_DeleteDB(socket,0,name))
  747.   {
  748.     Printf("Failed (%s)\n",getError(socket));
  749.     return;
  750.   }
  751.  
  752.   PutStr("OK\n");
  753.  
  754.   if(dbinfo.type==MKTAG('b','o','o','t')) PutStr("Rebooting after HotSync.\n");
  755. }
  756.  
  757. /*
  758. ** List all databases
  759. */
  760. void cmd_list(void)
  761. {
  762.   struct DLP_DBInfo info;
  763.   UWORD i;
  764.   ULONG nr;
  765.  
  766.   if(!Connect()) return;
  767.   if(!DLP_OpenConduit(socket)) return;
  768.  
  769.   PutStr(BOLD "-- LIST OF ALL RAM DATABASES --" NORMAL "\n");
  770.  
  771.   for(nr=1,i=0 ; ; nr++)
  772.   {
  773.     if(!DLP_GetDBInfo(socket,0,DLPGDBF_RAM,i,&info)) break;
  774.     Printf("%3ld: '%s'\n",nr,info.name);
  775.     i = info.index+1;
  776.   }
  777.  
  778.   PutStr(BOLD "-- LIST OF ALL ROM DATABASES --" NORMAL "\n");
  779.  
  780.   for(nr=1,i=0 ; ; nr++)
  781.   {
  782.     if(!DLP_GetDBInfo(socket,0,DLPGDBF_ROM,i,&info)) break;
  783.     Printf("%3ld: '%s'\n",nr,info.name);
  784.     i = info.index+1;
  785.   }
  786.  
  787.   PutStr(BOLD "---------------------------" NORMAL "\n");
  788.   if(PL_LastError(socket)==PLERR_NOTFOUND) ignoreError = TRUE;
  789. }
  790.  
  791. /*
  792. ** Purge all deleted records
  793. */
  794. void cmd_purge(void)
  795. {
  796.   struct DLP_DBInfo info;
  797.   UWORD i;
  798.   LONG dbh;
  799.  
  800.   if(!Connect()) return;
  801.   if(!DLP_OpenConduit(socket)) return;
  802.  
  803.   PutStr(BOLD "Purging deleted records from..." NORMAL "\n");
  804.  
  805.   for(i=0;;)
  806.   {
  807.     if(!DLP_GetDBInfo(socket,0,DLPGDBF_RAM,i,&info)) break;
  808.     i = info.index+1;
  809.     if(info.flags & DLPDBIF_RESOURCE) continue;       // don't purge resources
  810.     Printf("  %s: ",info.name);
  811.     Flush(Output());
  812.     dbh = DLP_OpenDB(socket,0,DLPDBOF_READWRITE,info.name);
  813.     if(   dbh>=0
  814.        && DLP_CleanUpDatabase(socket,dbh)
  815.        && DLP_ResetSyncFlags(socket,dbh))
  816.     {
  817.       PutStr("OK\n");
  818.       DLP_CloseDB(socket,dbh);
  819.     }
  820.     else
  821.     {
  822.       Printf("Failed (%s)\n",getError(socket));
  823.     }
  824.   }
  825.   if(PL_LastError(socket)==PLERR_NOTFOUND) ignoreError = TRUE;
  826.   VoidSyncFlags();
  827. }
  828.  
  829. /*
  830. ** MAIN PART
  831. */
  832. int main(void)
  833. {
  834.   struct RDArgs *args;
  835.  
  836.   PutStr(titletxt);
  837.  
  838.   if(args = (struct RDArgs *)ReadArgs(template,(LONG *)¶m,NULL))
  839.   {
  840.     if(UtilityBase = OpenLibrary("utility.library",36L))
  841.     {
  842.       if(PdalinkBase = OpenLibrary("pdalink.library",2L))
  843.       {
  844.         if(param.backup)                  // BACKUP
  845.           cmd_backup(param.dir);
  846.         else if(param.restore)            // RESTORE
  847.           cmd_restore(param.dir);
  848.         else if(param.install)            // INSTALL
  849.           cmd_install(param.file);
  850.         else if(param.merge)              // MERGE
  851.           cmd_merge(param.file);
  852.         else if(param.fetch)              // FETCH
  853.           cmd_fetch(param.name);
  854.         else if(param.delete)             // DELETE
  855.           cmd_delete(param.name);
  856.         else if(param.list)               // LIST
  857.           cmd_list();
  858.         else if(param.purge)              // PURGE
  859.           cmd_purge();
  860.         else
  861.           PutStr(helptxt);                // No command was given
  862.  
  863.         if(socket)
  864.         {
  865.           if(!ignoreError && (PL_LastError(socket)!=0))
  866.             Printf("** Socket error: %s\n",getError(socket));
  867.           Disconnect();
  868.         }
  869.         CloseLibrary(PdalinkBase);
  870.       }
  871.       else PutStr("** Couldn't open pdalink.library V2+\n");
  872.       CloseLibrary(UtilityBase);
  873.     }
  874.     else PutStr("** Couldn't open utility.library V36+\n");
  875.  
  876.     FreeArgs(args);
  877.   }
  878.   else PutStr(helptxt);
  879.  
  880.   return(0);
  881. }
  882.  
  883. /********************************************************************/
  884.