home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2000 #4 / Amiga Plus CD - 2000 - No. 4.iso / Tools / Musik / Misc / Amster / Source / share.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-05-27  |  28.8 KB  |  1,143 lines

  1. /*
  2. ** Amster - File sharing
  3. ** by Jacob Laursen <laursen@myself.com>
  4. */
  5.  
  6. #include "include/config.h"
  7.  
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11.  
  12. #include "include/mui.h"
  13. #include <MUI/NListview_mcc.h>
  14.  
  15. #include <proto/asl.h>
  16. #include <proto/dos.h>
  17.  
  18. #include <libraries/asl.h>
  19. #include <libraries/dos.h>
  20.  
  21. #include <exec/memory.h>
  22. #include <dos/exall.h>
  23. #include <utility/tagitem.h>
  24. #include <workbench/workbench.h>
  25.  
  26. #include "md5.h"
  27. #include "include/protos.h"
  28. #include "include/gui.h"
  29. #include "include/info.h"
  30. #include "include/share.h"
  31. #include "include/prefs.h"
  32. #include "include/panel.h"
  33. #include "include/napster.h"
  34. #include "include/upload.h"
  35. #include "include/rexx.h"
  36. #include "amster_Cat.h"
  37.  
  38.  
  39. unsigned int numsongs=0, numbytes=0;
  40. BOOL sharechanged=FALSE, sharefailed=FALSE;
  41.  
  42. struct FileRequester *FReqAddFiles;
  43. struct FileRequester *FReqAddDir;
  44. struct FileRequester *FReqLibrary;
  45.  
  46.  
  47. MUIF share_dispatch(REG(a0) struct IClass *cl, REG(a2) Object *obj, REG(a1) Msg msg)
  48. {
  49.     struct shdata *data = INST_DATA(cl, obj);
  50.  
  51.     switch(msg->MethodID) {
  52.         case OM_NEW:
  53.             return(share_new(cl, obj, (APTR)msg));
  54.         case OM_DISPOSE:
  55.             if (FReqAddFiles) FreeAslRequest(FReqAddFiles);
  56.             if (FReqAddDir)   FreeAslRequest(FReqAddDir);
  57.             if (FReqLibrary)  FreeAslRequest(FReqLibrary);
  58.             break;
  59.         case SHARE_OPEN:
  60.             update_stat(data);
  61.             set(obj, MUIA_Window_Open, TRUE);
  62.             return(NULL);
  63.         case SHARE_CLOSE:
  64.             set(obj, MUIA_Window_Open, FALSE);
  65.             return(NULL);
  66.         case SHARE_ADD:
  67.             add_shares(data);
  68.             return(NULL);
  69.         case SHARE_ADDDIR:
  70.             add_directory(data);
  71.             return(NULL);
  72.         case SHARE_REMOVE:
  73.             remove_shares(data, (long)(((muimsg)msg)->arg1));
  74.             return(NULL);
  75.         case SHARE_SAVE:
  76.             save_shares(data);
  77.             return(NULL);
  78.         case SHARE_SAVEAS:
  79.             save_shares_as(data);
  80.             return(NULL);
  81.         case SHARE_LOAD:
  82.             load_shares(data);
  83.             return(NULL);
  84.         case SHARE_LOADAS:
  85.             load_shares_as(data);
  86.             return(NULL);
  87.         case SHARE_UPLOAD:
  88.             upload_file_confirm(data, (char *)(((muimsg)msg)->arg1), (char *)(((muimsg)msg)->arg2));
  89.             return(NULL);
  90.         case SHARE_NOTIFYALL:
  91.             notify_shares(data);
  92.             return(NULL);
  93.         case SHARE_PLAY:
  94.             play_share(data);
  95.             return(NULL);
  96.         case SHARE_ADDFILE:
  97.             add_file(data, (song)(((muimsg)msg)->arg1), (char *)(((muimsg)msg)->arg2));
  98.             return(NULL);
  99.         case SHARE_ADDFILEN:
  100.             add_filename(data, (char *)(((muimsg)msg)->arg1));
  101.             return(NULL);
  102.     }
  103.     return(DoSuperMethodA(cl, obj, msg));
  104. }
  105.  
  106.  
  107. MUIF sharelistdest(REG(a2) APTR pool, REG(a1) sharedata sd)
  108. {
  109.     char *path;
  110.  
  111.     numsongs--;
  112.     numbytes -= sd->size;
  113.     if (gui_napon) {
  114.         path = MakeWinPath(sd->title);
  115.         nap_sendbuf(NAPC_REMOVESHARE, path);
  116.         free(path);
  117.     }
  118.     free(sd);
  119.  
  120.     return(0);
  121. }
  122.  
  123.  
  124. MUIF sharelistdisp(REG(a2) char **array, REG(a1) sharedata sd)
  125. {
  126.     static char size[16], md5[33], time[20], bitrate[16], freq[16];
  127.  
  128.     if (sd) {
  129.             *array++ = sd->title;
  130.             sprintf(size, "\33r%ld", sd->size);
  131.             *array++ = size;
  132.             sprintf(time, "\33r%ld:%02ld", sd->time/60, sd->time%60);
  133.             *array++ = time;
  134.             sprintf(bitrate, "\33r%ld", sd->bitrate);
  135.             *array++ = bitrate;
  136.             sprintf(freq, "\33l%ld", sd->freq);
  137.             *array++ = freq;
  138.             strcpy(md5, sd->md5);
  139.             *array = md5;
  140.     } else {
  141.         *array++ = (char *)MSG_LH_FILE;
  142.         *array++ = (char *)MSG_LH_SIZE;
  143.         *array++ = (char *)MSG_LH_TIME;
  144.         *array++ = (char *)MSG_LH_BITRATE;
  145.         *array++ = (char *)MSG_LH_FREQ;
  146.         *array   = (char *)MSG_LH_CHECKSUM;
  147.     }
  148.     return(0);
  149. }
  150.  
  151.  
  152. MUIF sharelistcomp(REG(a0) struct Hook *hook, REG(a2) Object *obj, REG(a1) struct NList_CompareMessage *ncm)
  153. {
  154.     sharedata entry1 = ncm->entry1;
  155.     sharedata entry2 = ncm->entry2;
  156.     LONG col1 = ncm->sort_type & MUIV_NList_TitleMark_ColMask;
  157.     LONG col2 = ncm->sort_type2 & MUIV_NList_TitleMark2_ColMask;
  158.     ULONG result = 0;
  159.  
  160.     if (ncm->sort_type == MUIV_NList_SortType_None) return (0);
  161.  
  162.     if (col1 == 0) {
  163.         if (ncm->sort_type & MUIV_NList_TitleMark_TypeMask)
  164.             result = (LONG) stricmp(entry2->title, entry1->title);
  165.         else
  166.             result = (LONG) stricmp(entry1->title, entry2->title);
  167.     }
  168.     else if (col1 == 1) {
  169.         if (ncm->sort_type & MUIV_NList_TitleMark_TypeMask)
  170.             result = entry2->size - entry1->size;
  171.         else
  172.             result = entry1->size - entry2->size;
  173.     }
  174.     else if (col1 == 2) {
  175.         if (ncm->sort_type & MUIV_NList_TitleMark_TypeMask)
  176.             result = entry2->time - entry1->time;
  177.         else
  178.             result = entry1->time - entry2->time;
  179.     }
  180.     else if (col1 == 3) {
  181.         if (ncm->sort_type & MUIV_NList_TitleMark_TypeMask)
  182.             result = entry2->bitrate - entry1->bitrate;
  183.         else
  184.             result = entry1->bitrate - entry2->bitrate;
  185.     }
  186.     else if (col1 == 4) {
  187.         if (ncm->sort_type & MUIV_NList_TitleMark_TypeMask)
  188.             result = entry2->freq - entry1->freq;
  189.         else
  190.             result = entry1->freq - entry2->freq;
  191.     }
  192.     else if (col1 == 5) {
  193.         if (ncm->sort_type & MUIV_NList_TitleMark_TypeMask)
  194.             result = (LONG) stricmp(entry2->md5, entry1->md5);
  195.         else
  196.             result = (LONG) stricmp(entry1->md5, entry2->md5);
  197.     }
  198.  
  199.     if ((result != 0) || (col1 == col2)) return (result);
  200.  
  201.     if (col2 == 0) {
  202.         if (ncm->sort_type & MUIV_NList_TitleMark2_TypeMask)
  203.             result = (LONG) stricmp(entry2->title, entry1->title);
  204.         else
  205.             result = (LONG) stricmp(entry1->title, entry2->title);
  206.     }
  207.     else if (col2 == 1) {
  208.         if (ncm->sort_type & MUIV_NList_TitleMark2_TypeMask)
  209.             result = entry2->size - entry1->size;
  210.         else
  211.             result = entry1->size - entry2->size;
  212.     }
  213.     else if (col2 == 2) {
  214.         if (ncm->sort_type & MUIV_NList_TitleMark2_TypeMask)
  215.             result = entry2->time - entry1->time;
  216.         else
  217.             result = entry1->time - entry2->time;
  218.     }
  219.     else if (col2 == 3) {
  220.         if (ncm->sort_type & MUIV_NList_TitleMark2_TypeMask)
  221.             result = entry2->bitrate - entry1->bitrate;
  222.         else
  223.             result = entry1->bitrate - entry2->bitrate;
  224.     }
  225.     else if (col2 == 4) {
  226.         if (ncm->sort_type & MUIV_NList_TitleMark2_TypeMask)
  227.             result = entry2->freq - entry1->freq;
  228.         else
  229.             result = entry1->freq - entry2->freq;
  230.     }
  231.     else if (col2 == 5) {
  232.         if (ncm->sort_type & MUIV_NList_TitleMark2_TypeMask)
  233.             result = (LONG) stricmp(entry2->md5, entry1->md5);
  234.         else
  235.             result = (LONG) stricmp(entry1->md5, entry2->md5);
  236.     }
  237.  
  238.     return (result);
  239. }
  240.  
  241.  
  242. MUIF ShareListAppMsgFunc(REG(a2) APTR obj, REG(a1) struct AppMessage **x)
  243. {
  244.     struct WBArg *ap;
  245.     struct AppMessage *amsg = *x;
  246.     int i;
  247.     static char buf[256];
  248.  
  249.     for (ap=amsg->am_ArgList, i=0; i<amsg->am_NumArgs; i++, ap++)
  250.     {
  251.             NameFromLock(ap->wa_Lock, buf, sizeof(buf));
  252.             AddPart(buf, ap->wa_Name, sizeof(buf));
  253.             DoMethod(gui->shwin, SHARE_ADDFILEN, buf);
  254.     }
  255.  
  256.     return(0);
  257. }
  258.  
  259.  
  260. ULONG share_new(struct IClass *cl, Object *obj, struct opSet *msg)
  261. {
  262.     static const struct Hook sharelistdispHook    = { {NULL, NULL}, &sharelistdisp, NULL, NULL };
  263.     static const struct Hook sharelistcompHook    = { {NULL, NULL}, &sharelistcomp, NULL, NULL };
  264.     static const struct Hook sharelistdestHook    = { {NULL, NULL}, &sharelistdest, NULL, NULL };
  265.     static const struct Hook ShareListAppMsgHook  = { {NULL, NULL}, &ShareListAppMsgFunc, NULL, NULL };
  266.  
  267.     struct shdata *data;
  268.     Object *list, *stat, *addbut, *adddirbut, *rembut, *remallbut;
  269.  
  270.     if (obj = (Object *)DoSuperNew(cl, obj,
  271.         MUIA_HelpNode, "sharing",
  272.         MUIA_Window_ID, MAKE_ID('S','H','A','R'),
  273.         MUIA_Window_Title, MSG_SHARE_TITLE,
  274.         MUIA_Window_AppWindow, TRUE,
  275.         WindowContents, VGroup,
  276.             MUIA_HelpNode, "sharing",
  277.             Child, stat = TextObject,
  278.                 TextFrame,
  279.                 MUIA_Background, MUII_TextBack,
  280.                 MUIA_Text_PreParse, "\33c",
  281.             End,
  282.             Child, list = NListviewObject,
  283.                 MUIA_NListview_NList, NListObject,
  284.                     InputListFrame,
  285.                     MUIA_NList_Title, TRUE,
  286.                     MUIA_NList_Format, "BAR, BAR, BAR, BAR, BAR",
  287.                     MUIA_NList_DisplayHook, &sharelistdispHook,
  288.                     MUIA_NList_CompareHook2, &sharelistcompHook,
  289.                     MUIA_NList_DestructHook, &sharelistdestHook,
  290.                     MUIA_NList_MultiSelect, MUIV_NList_MultiSelect_Default,
  291.                     MUIA_NList_MinColSortable, 0,
  292.                     MUIA_CycleChain, 1,
  293.                 End,
  294.             End,
  295.             Child, HGroup,
  296.                 Child, addbut    = SimpleButton(MSG_SHARE_ADD_GAD         ),
  297.                 Child, adddirbut = SimpleButton(MSG_SHARE_ADDRECURSIVE_GAD),
  298.                 Child, rembut    = SimpleButton(MSG_SHARE_REMOVE_GAD      ),
  299.                 Child, remallbut = SimpleButton(MSG_SHARE_REMOVEALL_GAD   ),
  300.             End,
  301.         End,
  302.         TAG_MORE, msg->ops_AttrList))
  303.     {
  304.         data = INST_DATA(cl,obj);
  305.         data->list = list;
  306.         data->stat = stat;
  307.  
  308.  
  309.         /* Default sort */
  310.  
  311.         DoMethod(list, MUIM_Set, MUIA_NList_TitleMark, 0);
  312.         DoMethod(list, MUIM_NList_Sort3, 0, MUIV_NList_SortTypeAdd_2Values, MUIV_NList_Sort3_SortType_Both);
  313.  
  314.         /* Window notify */
  315.  
  316.         DoMethod(obj, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, gui->iconpanel, 1, PANEL_CLOSESHARE);
  317.  
  318.         /* List notifies */
  319.  
  320.         DoMethod(list, MUIM_Notify, MUIA_NList_DoubleClick, MUIV_EveryTime, obj,  1, SHARE_PLAY);
  321.          DoMethod(list, MUIM_Notify, MUIA_NList_TitleClick,  MUIV_EveryTime, list, 4, MUIM_NList_Sort3, MUIV_TriggerValue, MUIV_NList_SortTypeAdd_2Values, MUIV_NList_Sort3_SortType_Both);
  322.         DoMethod(list, MUIM_Notify, MUIA_NList_TitleClick2, MUIV_EveryTime, list, 4, MUIM_NList_Sort3, MUIV_TriggerValue, MUIV_NList_SortTypeAdd_2Values, MUIV_NList_Sort3_SortType_2);
  323.         DoMethod(list, MUIM_Notify, MUIA_NList_SortType,    MUIV_EveryTime, list, 3, MUIM_Set, MUIA_NList_TitleMark,  MUIV_TriggerValue);
  324.         DoMethod(list, MUIM_Notify, MUIA_NList_SortType2,   MUIV_EveryTime, list, 3, MUIM_Set, MUIA_NList_TitleMark2, MUIV_TriggerValue);
  325.         DoMethod(list, MUIM_Notify, MUIA_AppMessage,        MUIV_EveryTime, list, 3, MUIM_CallHook, &ShareListAppMsgHook, MUIV_TriggerValue);
  326.  
  327.         /* Button notifies */
  328.  
  329.         DoMethod(addbut,    MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, SHARE_ADD      );
  330.         DoMethod(adddirbut, MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, SHARE_ADDDIR   );
  331.         DoMethod(rembut,    MUIM_Notify, MUIA_Pressed, FALSE, obj, 2, SHARE_REMOVE, 0);
  332.         DoMethod(remallbut, MUIM_Notify, MUIA_Pressed, FALSE, obj, 2, SHARE_REMOVE, 1);
  333.  
  334.         /* Allocate file requesters */
  335.  
  336.         FReqAddFiles = AllocAslRequestTags(ASL_FileRequest,
  337.             ASLFR_TitleText, MSG_SHARE_ADD_REQ,
  338.             ASLFR_InitialPattern, (ULONG)"#?.mp(2|3)",
  339.             ASLFR_InitialDrawer, (ULONG)prf->dlpath,
  340.             ASLFR_DoPatterns, TRUE,
  341.             ASLFR_DoMultiSelect, TRUE,
  342.             ASLFR_RejectIcons, TRUE,
  343.             TAG_DONE);
  344.         FReqAddDir = AllocAslRequestTags(ASL_FileRequest,
  345.             ASLFR_TitleText, MSG_SHARE_ADDDIR_REQ,
  346.             ASLFR_InitialDrawer, (ULONG)prf->dlpath,
  347.             ASLFR_DrawersOnly, TRUE,
  348.             TAG_DONE);
  349.         FReqLibrary = AllocAslRequestTags(ASL_FileRequest,
  350.             ASLFR_InitialFile, "Amster.shares",
  351.             ASLFR_InitialDrawer, "PROGDIR:",
  352.             ASLFR_RejectIcons, TRUE,
  353.             TAG_DONE);
  354.  
  355.         return((ULONG)obj);
  356.     }
  357.     return(0);
  358. }
  359.  
  360.  
  361. /* Private functions */
  362.  
  363.  
  364. void add_filename(struct shdata *data, char *fname)
  365. {
  366.     sharedata sd;
  367.     struct FileInfoBlock *fib;
  368.     BPTR lock;
  369.  
  370.     if (!(fib = AllocMem(sizeof(*fib), MEMF_PUBLIC))) return;
  371.  
  372.     if (sd = malloc(sizeof(_sharedata))) {
  373.         memset(sd, 0, sizeof(_sharedata));
  374.  
  375.         strcpy(sd->title, fname);
  376.         if (lock = Lock(fname, ACCESS_READ)) {
  377.             if (Examine(lock, fib)) {
  378.                 sd->size = fib->fib_Size;
  379.                 if (NameFromLock(lock, sd->title, 255)) {
  380.                     if (fib->fib_DirEntryType < 0) add_shareinfo(data, sd, lock);
  381.                     else if (fib->fib_DirEntryType > 0) {
  382.                         add_recursive(data, sd, lock, sd->title);
  383.                         UnLock(lock);
  384.                     }
  385.                 }
  386.                 else UnLock(lock);
  387.             }
  388.         }
  389.     }
  390.  
  391.     FreeMem(fib, sizeof(*fib));
  392. }
  393.  
  394.  
  395. void add_file(struct shdata *data, song sdl, char *fname)
  396. {
  397.     sharedata sd;
  398.     struct FileInfoBlock *fib;
  399.     BPTR lock;
  400.  
  401.     if (sd = malloc(sizeof(_sharedata))) {
  402.         memset(sd, 0, sizeof(_sharedata));
  403.  
  404.         if (fib = AllocMem(sizeof(*fib), MEMF_PUBLIC)) {
  405.             if (lock = Lock(fname, ACCESS_READ)) {
  406.                 NameFromLock(lock, sd->title, 255);
  407.                 UnLock(lock);
  408.             }
  409.             FreeMem(fib, sizeof(*fib));
  410.         }
  411.  
  412.         if(!sd->title) strcpy(sd->title, fname);
  413.         strncpy(sd->md5, sdl->md5, 32);
  414.         sd->size    = sdl->size;
  415.         sd->bitrate = sdl->bit;
  416.         sd->freq    = sdl->freq;
  417.         sd->time    = sdl->time;
  418.  
  419.         DoMethod(data->list, MUIM_NList_InsertSingle, sd, MUIV_NList_Insert_Sorted);
  420.         numsongs++; numbytes += sd->size;
  421.         sharechanged = TRUE;
  422.         update_stat(data);
  423.         if(gui_napon) nap_notifyshare(sd);
  424.     }
  425.  
  426.     return;
  427. }
  428.  
  429.  
  430. void add_shares(struct shdata *data)
  431. {
  432.     sharedata sd;
  433.     BPTR lock;
  434.     struct FileInfoBlock *fib;
  435.     int i;
  436.  
  437.     if (FReqAddFiles) {
  438.         if (AslRequestTags(FReqAddFiles, ASLFR_InitialFile, NULL, TAG_DONE)) {
  439.                 if (fib = AllocMem(sizeof(*fib), MEMF_PUBLIC)) {
  440.                     for (i=0; i<FReqAddFiles->fr_NumArgs; i++) {
  441.                         if (sd = malloc(sizeof(_sharedata))) {
  442.                             memset(sd, 0, sizeof(_sharedata));
  443.                             strcpy(sd->title, FReqAddFiles->fr_Drawer);
  444.                             AddPart(sd->title, FReqAddFiles->fr_ArgList[i].wa_Name, 255);
  445.                             if (lock = Lock(sd->title, ACCESS_READ)) {
  446.                                 if (Examine(lock, fib)) {
  447.                                     sd->size = fib->fib_Size;
  448.                                     if (NameFromLock(lock, sd->title, 255)) {
  449.                                         if (fib->fib_DirEntryType < 0) add_shareinfo(data, sd, lock);
  450.                                         else if (fib->fib_DirEntryType > 0) {
  451.                                             add_recursive(data, sd, lock, sd->title);
  452.                                             UnLock(lock);
  453.                                         }
  454.                                     }
  455.                                     else UnLock(lock);
  456.                                 }
  457.                             }
  458.                         }
  459.                     }
  460.                     FreeMem(fib, sizeof(*fib));
  461.                 }
  462.         }
  463.         if (sharefailed) {
  464.             MUI_Request(gui->app, gui->shwin, 0L,
  465.                 (char *)MSG_ERROR_TITLE,
  466.                 (char *)MSG_OK_GAD,
  467.                 (char *)MSG_SHARE_ADDFAILED);
  468.             sharefailed = FALSE;
  469.         }
  470.     }
  471. }
  472.  
  473.  
  474. void add_directory(struct shdata *data)
  475. {
  476.     sharedata sd;
  477.     BPTR lock;
  478.     struct FileInfoBlock *fib;
  479.  
  480.     if (FReqAddDir) {
  481.         if (AslRequestTags(FReqAddDir, TAG_DONE)) {
  482.                 if (fib = AllocMem(sizeof(*fib), MEMF_PUBLIC)) {
  483.                     if (sd = malloc(sizeof(_sharedata))) {
  484.                         memset(sd, 0, sizeof(_sharedata));
  485.                         strcpy(sd->title, FReqAddDir->fr_Drawer);
  486.                         if (lock = Lock(sd->title, ACCESS_READ)) {
  487.                             if (Examine(lock, fib)) {
  488.                                 sd->size = fib->fib_Size;
  489.                                 if (NameFromLock(lock, sd->title, 255)) {
  490.                                     if (fib->fib_DirEntryType > 0) {
  491.                                         add_recursive(data, sd, lock, sd->title);
  492.                                         UnLock(lock);
  493.                                     }
  494.                                 }
  495.                                 else UnLock(lock);
  496.                             }
  497.                         }
  498.                     }
  499.                     FreeMem(fib, sizeof(*fib));
  500.                 }
  501.         }
  502.         if (sharefailed) {
  503.             MUI_Request(gui->app, gui->shwin, 0L,
  504.                 (char *)MSG_ERROR_TITLE,
  505.                 (char *)MSG_OK_GAD,
  506.                 (char *)MSG_SHARE_ADDFAILED);
  507.             sharefailed = FALSE;
  508.         }
  509.     }
  510. }
  511.  
  512.  
  513. void add_recursive(struct shdata *data, sharedata sd, BPTR dirlock, const char *dirname)
  514. {
  515.     ULONG namelen;
  516.     long len;
  517.     struct ExAllControl *eac;
  518.     struct ExAllData *ead;
  519.     APTR eadata;
  520.     BOOL more;
  521.     char *name;
  522.     BPTR lock;
  523.     struct FileInfoBlock *fib;
  524.     const long buffersize = 4096;
  525.  
  526.     if (dirlock) {
  527.         namelen = strlen(dirname);
  528.         eac = AllocDosObject(DOS_EXALLCONTROL, NULL);
  529.         if (eac) {
  530.             eac->eac_LastKey = 0;
  531.             eac->eac_MatchString = 0;
  532.             eac->eac_MatchFunc = 0;
  533.             eadata = malloc(buffersize);
  534.             if (eadata) {
  535.                 do {
  536.                     more = ExAll(dirlock, eadata, buffersize, ED_TYPE, eac);
  537.                     if (eac->eac_Entries > 0) {
  538.                         ead = eadata;
  539.                         do {
  540.                             len = namelen + strlen(ead->ed_Name);
  541.                             name = (char *)malloc(len+5);
  542.                             if (name) {
  543.                                 strcpy(name, dirname);
  544.                                 if (AddPart(name, ead->ed_Name, len+5)) {
  545.                                     if (ead->ed_Type > 0) {
  546.                                         lock = Lock(name, ACCESS_READ);
  547.                                         if (lock) {
  548.                                             add_recursive(data, sd, lock, name);
  549.                                             UnLock(lock);
  550.                                         }
  551.                                     }
  552.                                     else if (ead->ed_Type < 0) {
  553.                                         if (sd = malloc(sizeof(_sharedata))) {
  554.                                             memset(sd, 0, sizeof(_sharedata));
  555.                                             strcpy(sd->title, name);
  556.                                             if (fib = AllocMem(sizeof(*fib), MEMF_PUBLIC)) {
  557.                                                 lock = Lock(name, ACCESS_READ);
  558.                                                 if (lock) {
  559.                                                     if (Examine(lock, fib)) {
  560.                                                         sd->size = fib->fib_Size;
  561.                                                         add_shareinfo(data, sd, lock);
  562.                                                     }
  563.                                                 }
  564.                                             }
  565.                                             FreeMem(fib, sizeof(*fib));
  566.                                         }
  567.                                     }
  568.                                 }
  569.                                 free(name);
  570.                             }
  571.                             ead = ead->ed_Next;
  572.                         } while(ead);
  573.                     }
  574.                     if ((!more) && (IoErr() != ERROR_NO_MORE_ENTRIES)) break;
  575.                     if (eac->eac_Entries == 0) continue;
  576.                 } while (more);
  577.                 free(eadata);
  578.             }
  579.             FreeDosObject(DOS_EXALLCONTROL, eac);
  580.         }
  581.     }
  582. }
  583.  
  584.  
  585. void add_shareinfo(struct shdata *data, sharedata sd, BPTR lock)
  586. {
  587.     unsigned int m_id, m_layer, m_bit, m_freq, m_mode;
  588.     APTR buffer;
  589.     BPTR fh;
  590.     int i=0, j=0, len, total, col;
  591.     long vbrbytes = 0, vbrframes = 0, vbr = 0;
  592.     BOOL header = FALSE;
  593.     int badhdr[10];
  594.     char *suffix;
  595.  
  596.     sharedata sdtmp;
  597.     ULONG tmp;
  598.  
  599.     md5_state_t state;
  600.     md5_byte_t digest[16];
  601.     int di;
  602.  
  603.     /*    MP3 information source:
  604.         http://mp3tech.free.fr/programmers/frame_header.html
  605.     */
  606.  
  607.     int mp3_bitrates[14][6] = {
  608.     /*   V1L1,V1L2,V1L3,V2L1,V2L2,V2L3   */
  609.         {  32,  32,  32,  32,   8,   8 },
  610.         {  64,  48,  40,  48,  16,  16 },
  611.         {  96,  56,  48,  56,  24,  24 },
  612.         { 128,  64,  56,  64,  32,  32 },
  613.         { 160,  80,  64,  80,  40,  40 },
  614.         { 192,  96,  80,  96,  48,  48 },
  615.         { 224, 112,  96, 112,  56,  56 },
  616.         { 256, 128, 112, 128,  64,  64 },
  617.         { 288, 160, 128, 144,  80,  80 },
  618.         { 320, 192, 160, 160,  96,  96 },
  619.         { 352, 224, 192, 176, 112, 112 },
  620.         { 384, 256, 224, 192, 128, 128 },
  621.         { 416, 320, 256, 224, 144, 144 },
  622.         { 448, 384, 320, 256, 160, 160 }
  623.     };
  624. /*    V1 = MPEG Version 1
  625.     V2 = MPEG Version 2 and Version 2.5
  626.     L1 = Layer I
  627.     L2 = Layer II
  628.     L3 = Layer III
  629. */
  630.  
  631.     int mp3_frequencies[3][3] = {
  632.     /*    MPEG1, MPEG2, MPEG2.5    */
  633.         { 44100, 22050, 11025 },
  634.         { 48000, 24000, 12000 },
  635.         { 32000, 16000,  8000 }
  636.     };
  637.  
  638.     if (IsIn(sd->title, '"') || IsIn(sd->title, '\\')) {
  639.         gui_debugf((char *)MSG_SHARE_ILLEGALCHARS, sd->title);
  640.         sharefailed = TRUE;
  641.         UnLock(lock);
  642.         return;
  643.     }
  644.  
  645.     suffix = sd->title + strlen(sd->title) - 4;
  646.     if (stricmp(suffix, ".mp3") != 0 && stricmp(suffix, ".mp2") != 0) {
  647.         gui_debugf((char *)MSG_SHARE_INVALIDEXTENSION, sd->title);
  648.         sharefailed = TRUE;
  649.         UnLock(lock);
  650.         return;
  651.     }
  652.  
  653.     GetAttr(MUIA_NList_Entries, data->list, &tmp);
  654.     total = tmp;
  655.  
  656.     while (i < total) {
  657.         DoMethod(data->list, MUIM_NList_GetEntry, i, &sdtmp);
  658.         if (sdtmp) if (strcmp(sd->title, sdtmp->title) == 0) {
  659.             gui_debugf((char *)MSG_SHARE_EXISTS, sd->title);
  660.             sharefailed = TRUE;
  661.             UnLock(lock);
  662.             return;
  663.         }
  664.         i++;
  665.     }
  666.  
  667.     if (fh = OpenFromLock(lock)) {
  668.         if (buffer = AllocMem(300032, MEMF_ANY)) {
  669.  
  670.             md5_init(&state);
  671.  
  672.             len = Read(fh, buffer, 300032);
  673.             if (len > 0) {
  674.  
  675.                 md5_append(&state, (const md5_byte_t *)buffer, len);
  676.                 md5_finish(&state, digest);
  677.                 for (di = 0; di < 16; ++di)
  678.                     sprintf(sd->md5+di*2, "%02x", digest[di]);
  679.  
  680.                 /* Only check first 128 kB for valid MP3 header */
  681.                 if (len > 128*1024) len = 128*1024;
  682.  
  683.                 /* Check for VBR */
  684.                 for (i=0; i<len; i++) {
  685.                     if (*((unsigned char *)buffer+i) == 'X')
  686.                         if (*((unsigned char *)buffer+i+1) == 'i')
  687.                             if (*((unsigned char *)buffer+i+2) == 'n')
  688.                                 if (*((unsigned char *)buffer+i+3) == 'g') {
  689.                                     j = i + 7;
  690.                                     if ((*((char *)buffer+j) & 1) && ((*((char *)buffer+j) & 2) >> 1)) {
  691.                                         j++;
  692.                                         vbrframes = *((unsigned long *)buffer+j/4);
  693.                                         vbrbytes = *((unsigned long *)buffer+(j+4)/4);
  694.                                         j += 7;
  695.                                     }
  696.                                     if (vbrframes > 0 && vbrbytes > 0) vbr = ((vbrbytes / vbrframes) * 1000) / 3265;
  697.                                     break;
  698.                                 }
  699.                 }
  700.  
  701.                 i = j;
  702.                 if (stcd_i(buffer, badhdr) == 8 && i < 417) i = 417;
  703.                 /* Work-around for "MpegDJ Encoder" bug */
  704.  
  705.                 while (!header && i<len-3) {
  706.                     /* Seek until synchronization is found (%11111111.111xxxxx) */
  707.                     if (*((unsigned char *)buffer+i) == 255) {
  708.                         if (*((unsigned char *)buffer+i+1) >= 224) {
  709.  
  710.                             /*    MPEG Audio version ID
  711.                                 00 - MPEG Version 2.5 (later extension of MPEGĀ 2)
  712.                                 01 - reserved
  713.                                 10 - MPEG Version 2 (ISO/IEC 13818-3)
  714.                                 11 - MPEG Version 1 (ISO/IEC 11172-3)
  715.                             */
  716.  
  717.                             m_id = 3 - ((*((char *)buffer+i+1) & 24)>>3);
  718.                             if (m_id == 3) m_id = 1;
  719.  
  720.                             /*    Layer description
  721.                                 00 - reserved
  722.                                 01 - Layer III
  723.                                 10 - Layer II
  724.                                 11 - Layer I
  725.                             */
  726.  
  727.                             m_layer = 4 - ((*((char *)buffer+i+1) & (2+4))>>1);
  728.                             m_bit   =      (*((char *)buffer+i+2) & (16+32+64+128))>>4;
  729.                             m_freq  =      (*((char *)buffer+i+2) & (4+8))>>2;
  730.  
  731.                             /*    Channel Mode
  732.                                 00 - Stereo
  733.                                 01 - Joint stereo (Stereo)
  734.                                 10 - Dual channel (2 mono channels)
  735.                                 11 - Single channel (Mono)
  736.                             */
  737.  
  738.                             m_mode  =      (*((char *)buffer+i+3) & (64+128))>>6;
  739.  
  740.                             /*
  741.                             printf("version %d layer %d mode %d bit %ld freq %ld\n", m_id+1, m_layer, m_mode, m_bit, m_freq);
  742.                             */
  743.  
  744.                             col = m_layer-1;
  745.                             if (m_id == 1) col=col+3;
  746.  
  747.                             if (m_bit>0 && m_bit<15 && m_freq < 3 && m_layer < 4 && m_id != 2) {
  748.  
  749.                                 header = TRUE;
  750.  
  751.                                 sd->freq = mp3_frequencies[m_freq][m_id];
  752.                                 if (vbr > 0) sd->bitrate = vbr;
  753.                                 else sd->bitrate = mp3_bitrates[m_bit-1][col];
  754.  
  755.                                 if (m_layer == 2) { /* Sanity checks */
  756.                                     if ((sd->bitrate == 32 || sd->bitrate == 48 || sd->bitrate == 46 || sd->bitrate == 80) && m_mode != 3) header = FALSE;
  757.                                     if ((sd->bitrate == 224 || sd->bitrate == 256 || sd->bitrate == 320 || sd->bitrate == 384) && m_mode == 3) header = FALSE;
  758.                                 }
  759.  
  760.                                 sd->time = (sd->size-i)/(sd->bitrate*125);
  761.                                 /* 'i' is the length of ID3v2 tag. ID3v1 size is always 128 bytes,
  762.                                    so it's not worth the overhead to check for this.
  763.                                    128 bytes of a 128 kbps MP3 = 0.000008 seconds! */
  764.                             }
  765.                         }
  766.                     }
  767.                     i++;
  768.                 }
  769.             }
  770.             FreeMem(buffer, 300032);
  771.         }
  772.         Close(fh);
  773.         if (header) {
  774.             DoMethod(data->list, MUIM_NList_InsertSingle, sd, MUIV_NList_Insert_Sorted);
  775.             numsongs++; numbytes += sd->size;
  776.             sharechanged = TRUE;
  777.             update_stat(data);
  778.             if(gui_napon) nap_notifyshare(sd);
  779.         }
  780.         else {
  781.             gui_debugf((char *)MSG_SHARE_ADDERROR, sd->title, sd->size, sd->bitrate, sd->freq);
  782.             sharefailed = TRUE;
  783.         }
  784.     }
  785.     else UnLock(lock);
  786.  
  787. }
  788.  
  789.  
  790. void notify_shares(struct shdata *data)
  791. {
  792.     sharedata sd;
  793.     u_long tmp;
  794.     int i, total;
  795.  
  796.     if (!gui_napon) return;
  797.  
  798.     GetAttr(MUIA_NList_Entries, data->list, &tmp);
  799.     total = tmp;
  800.  
  801.     if (total > 0) {
  802.         gui_stat((char *)MSG_STATUS2_NOTIFYALL);
  803.         for (i=0; i<total; i++) {
  804.             DoMethod(data->list, MUIM_NList_GetEntry, i, &sd);
  805.             if (!sd) break;
  806.             nap_notifyshare(sd);
  807.         }
  808.     }
  809. }
  810.  
  811.  
  812. void remove_shares(struct shdata *data, long t)
  813. {
  814.     sharedata sd;
  815.     u_long tmp;
  816.     int total;
  817.  
  818.     GetAttr(MUIA_NList_Entries, data->list, &tmp);
  819.     total = tmp;
  820.  
  821.     if (total == 0) return;
  822.  
  823.     switch(t) {
  824.         case 0: /* Remove marked */
  825.             set(data->list, MUIA_NList_Quiet, MUIV_NList_Quiet_Visual);
  826.             DoMethod(data->list, MUIM_NList_Remove, MUIV_NList_Remove_Selected);
  827.             update_stat(data);
  828.             set(data->list,MUIA_NList_Quiet, MUIV_NList_Quiet_None);
  829.             break;
  830.         case 1: /* Remove all */
  831.             set(data->list, MUIA_NList_Quiet, MUIV_NList_Quiet_Visual);
  832.             for (;;) {
  833.                 DoMethod(data->list, MUIM_NList_GetEntry, 0, &sd);
  834.                 if (!sd) break;
  835.                 DoMethod(data->list, MUIM_NList_Remove, MUIV_NList_Remove_First);
  836.             }
  837.             update_stat(data);
  838.             set(data->list, MUIA_NList_Quiet, MUIV_NList_Quiet_None);
  839.             break;
  840.     }
  841.     sharechanged = TRUE;
  842. }
  843.  
  844.  
  845. void save_shares(struct shdata *data)
  846. {
  847.     sharedata sd;
  848.     int i;
  849.     BPTR fh;
  850.     char buf[512], *tmp;
  851.  
  852.     strcpy(buf, FReqLibrary->fr_Drawer);
  853.     AddPart(buf, FReqLibrary->fr_File, 511);
  854.  
  855.     fh = Open(buf, MODE_NEWFILE);
  856.     if (!fh) return;
  857.  
  858.     for(i=0; ; i++) {
  859.         DoMethod(data->list, MUIM_NList_GetEntry, i, &sd);
  860.         if (!sd) break;
  861.         tmp = strrep(sd->title, "\"", "*\"");
  862.         sprintf(buf, "\"%s\" %s %ld %ld %ld %ld\n", tmp, sd->md5, sd->size, sd->bitrate, sd->freq, sd->time);
  863.         free(tmp);
  864.         Write(fh, buf, strlen(buf)); /* Should be buffered, check FWrite */
  865.     }
  866.  
  867.     Close(fh);
  868.     sharechanged = FALSE;
  869. }
  870.  
  871.  
  872. void save_shares_as(struct shdata *data)
  873. {
  874.     if (FReqLibrary) {
  875.         if (AslRequestTags(FReqLibrary,
  876.             ASLFR_TitleText, MSG_SHARE_SAVEAS,
  877.             ASLFR_DoSaveMode, TRUE,
  878.             TAG_DONE)) {
  879.                     save_shares(data);
  880.         }
  881.     }
  882. }
  883.  
  884.  
  885. void load_shares(struct shdata *data)
  886. {
  887.     sharedata sd;
  888.     int bufsize = 0, line = 0;
  889.     BPTR fh, lock;
  890.     char buf[512], sharefile[512];
  891.     struct FileInfoBlock *fib;
  892.     LONG argarray[] = { NULL, NULL, NULL, NULL, NULL, NULL };
  893.     UBYTE *argstr = "PATH/A,MD5/A,SIZE/A/N,BITRATE/A/N,FREQUENCY/A/N,TIME/A/N";
  894.     struct RDArgs *rdargs;
  895.  
  896.     remove_shares(data, 1);
  897.  
  898.     strcpy(sharefile, FReqLibrary->fr_Drawer);
  899.     AddPart(sharefile, FReqLibrary->fr_File, 511);
  900.  
  901.     if (!(lock = Lock(sharefile, ACCESS_READ))) return;
  902.  
  903.     if (fib = AllocMem(sizeof(*fib), MEMF_PUBLIC)) {
  904.             if (Examine(lock, fib)) bufsize = fib->fib_Size;
  905.             FreeMem(fib, sizeof(*fib));
  906.     }
  907.  
  908.     if (bufsize > 0) {
  909.         if (fh = OpenFromLock(lock)) {
  910.  
  911.             set(data->list,MUIA_NList_Quiet, MUIV_NList_Quiet_Visual);
  912.  
  913.             while (FGets(fh, buf, 512)) {
  914.                 line++;
  915.                 if (rdargs = AllocDosObject(DOS_RDARGS, NULL)) {
  916.                     rdargs->RDA_Buffer = NULL;
  917.                     rdargs->RDA_Source.CS_Buffer = buf;
  918.                     rdargs->RDA_Source.CS_Length = strlen(buf);
  919.                     if (ReadArgs(argstr, argarray, rdargs)) {
  920.  
  921.                         sd = malloc(sizeof(_sharedata));
  922.  
  923.                         strcpy(sd->title, (char *)argarray[ ARG_PATH    ]);
  924.                         strcpy(sd->md5,   (char *)argarray[ ARG_MD5     ]);
  925.                         sd->size    =   *((long *)argarray[ ARG_SIZE    ]);
  926.                         sd->bitrate =   *((long *)argarray[ ARG_BITRATE ]);
  927.                         sd->freq    =   *((long *)argarray[ ARG_FREQ    ]);
  928.                         sd->time    =   *((long *)argarray[ ARG_TIME    ]);
  929.  
  930.                         DoMethod(data->list, MUIM_NList_InsertSingle, sd, MUIV_NList_Insert_Bottom);
  931.                         numsongs++; numbytes += sd->size;
  932.                         if (gui_napon) nap_notifyshare(sd);
  933.  
  934.                         FreeArgs(rdargs);
  935.                     }
  936.                     else gui_debugf("Error parsing '%s' line #%ld\n", sharefile, line);
  937.                     FreeDosObject(DOS_RDARGS, rdargs);
  938.                 }
  939.             }
  940.  
  941.             set(data->list, MUIA_NList_Quiet, MUIV_NList_Quiet_None);
  942.             update_stat(data);
  943.  
  944.             Close(fh);
  945.         }
  946.     }
  947.     UnLock(lock);
  948.     sharechanged = FALSE;
  949. }
  950.  
  951.  
  952. void load_shares_as(struct shdata *data)
  953. {
  954.     if (FReqLibrary) {
  955.         if (AslRequestTags(FReqLibrary,
  956.             ASLFR_TitleText, MSG_SHARE_LOADAS,
  957.             TAG_DONE)) {
  958.                     load_shares(data);
  959.         }
  960.     }
  961. }
  962.  
  963.  
  964. void update_stat(struct shdata *data)
  965. {
  966.     static char buf[100], totalsize[8];
  967.     char descriptor[16];
  968.     unsigned long number, tempnumber;
  969.  
  970.     if (numbytes >= (1024*1024*1024)) {
  971.         strcpy(descriptor, MSG_SHARE_STAT_GB);
  972.         tempnumber = numbytes/1024/1024*10/1024;
  973.         number = tempnumber/10;
  974.         tempnumber = tempnumber-(number*10);
  975.         sprintf(totalsize,"%d.%d", number, tempnumber);
  976.     }
  977.     else if (numbytes >= (1024*1024)) {
  978.         strcpy(descriptor, MSG_SHARE_STAT_MB);
  979.         tempnumber = numbytes/1024*10/1024;
  980.         number = tempnumber/10;
  981.         tempnumber = tempnumber-(number*10);
  982.         sprintf(totalsize, "%d.%d", number, tempnumber);
  983.     }
  984.     else {
  985.         strcpy(descriptor, MSG_SHARE_STAT_KB);
  986.         number = numbytes/1024;
  987.         sprintf(totalsize, "%d", number);
  988.     }
  989.  
  990.     sprintf(buf, MSG_SHARE_STAT_TMP, numsongs, totalsize, descriptor);
  991.     set(data->stat, MUIA_Text_Contents, buf);
  992. }
  993.  
  994.  
  995. void play_share(struct shdata *data)
  996. {
  997.     sharedata sd;
  998.     char buf[1024], *command;
  999.  
  1000.     DoMethod(data->list, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &sd);
  1001.     if (sd) {
  1002.         if (prf->scripts[PRFE_PLAYMP3]) {
  1003.             sprintf(buf, "Run <>NIL: %s", prf->scripts[PRFE_PLAYMP3]);
  1004.             command = strrep(buf, "%f", sd->title);
  1005.             Execute(command, 0, 0);
  1006.             free(command);
  1007.         }
  1008.     }
  1009. }
  1010.  
  1011.  
  1012. void upload_req(char *user, char *fname)
  1013. {
  1014.     DoMethod(gui->shwin, SHARE_UPLOAD, user, fname);
  1015. }
  1016.  
  1017.  
  1018. void upload_file_confirm(struct shdata *data, char *user, char *fname)
  1019. /* Continued from upload_req() */
  1020. {
  1021.     sharedata sd;
  1022.     song s;
  1023.     int i=0, total;
  1024.     ULONG tmp;
  1025.     BOOL found = FALSE;
  1026.     char *path;
  1027.  
  1028.     GetAttr(MUIA_NList_Entries, data->list, &tmp);
  1029.     total = tmp;
  1030.  
  1031.     gui_debugf((char *)MSG_SHARE_REQFILE, user, fname);
  1032.  
  1033.     while (i<total && !found) {
  1034.         DoMethod(data->list, MUIM_NList_GetEntry, i, &sd);
  1035.         if (sd) {
  1036.             path = MakeWinPath(sd->title);
  1037.             if (strcmp(path, fname) == 0) found = TRUE;
  1038.             free(path);
  1039.         }
  1040.         i++;
  1041.     }
  1042.  
  1043.     if (!found) {
  1044.         gui_debug((char *)MSG_SHARE_NOTFOUND);
  1045.         return;
  1046.     }
  1047.  
  1048.     s = malloc(sizeof(_song));
  1049.     if (!s) return;
  1050.     memset(s, 0, sizeof(_song));
  1051.  
  1052.     s->title = strdup(sd->title);
  1053.     s->md5 = strdup(sd->md5);
  1054.     s->size = sd->size;
  1055.     s->bit = sd->bitrate;
  1056.     s->freq = sd->freq;
  1057.     s->time = sd->time;
  1058.     s->user = strdup(user);
  1059.     /* At this point we don't know IP and link speed - can't complete the struct */
  1060.  
  1061.     ul_addq(s);
  1062. }
  1063.  
  1064.  
  1065. void nap_notifyshare(sharedata sd)
  1066. {
  1067.     char *path, *suffix;
  1068.  
  1069.     /* In case invalid files were added manually or with an earlier version */
  1070.     if (IsIn(sd->title, '"') || IsIn(sd->title, '\\')) {
  1071.         gui_debugf((char *)MSG_SHARE_ILLEGALCHARS, sd->title);
  1072.         return;
  1073.     }
  1074.  
  1075.     suffix = sd->title + strlen(sd->title) - 4;
  1076.     if (stricmp(suffix, ".mp3") != 0 && stricmp(suffix, ".mp2") != 0) {
  1077.         gui_debugf((char *)MSG_SHARE_INVALIDEXTENSION, sd->title);
  1078.         return;
  1079.     }
  1080.  
  1081.     path = MakeWinPath(sd->title);
  1082.     sprintf(nap_buf, "\"%s\" %s %ld %ld %ld %ld", path, sd->md5, sd->size, sd->bitrate, sd->freq, sd->time);
  1083.     free(path);
  1084.     nap_send(NAPC_NOTIFYSHARE);
  1085. }
  1086.  
  1087.  
  1088. char *strrep(char *str1, char *old_str, char *new_str)
  1089. {
  1090.     char *str;
  1091.     int len, i;
  1092.  
  1093.     if (!(str = malloc(1024))) return str1;
  1094.     str[0] = '\0';
  1095.  
  1096.     for (i=0; i<strlen(str1); i++) {
  1097.         if (strncmp(str1+i, old_str, strlen(old_str)) == 0) {
  1098.             strcat(str, new_str);
  1099.             i += strlen(old_str)-1;
  1100.         }
  1101.         else {
  1102.             len = strlen(str);
  1103.             str[len] = str1[i];
  1104.             str[len+1] = '\0';
  1105.         }
  1106.     }
  1107.  
  1108.     return str;
  1109. }
  1110.  
  1111.  
  1112. char *MakeWinPath(char *AmigaPath)
  1113. /* PRE: The AmigaPath must contain max. 1 colon */
  1114. {
  1115.     char *WinPath;
  1116.     int i, j;
  1117.  
  1118.     if (!(WinPath = malloc(strlen(AmigaPath)+2))) return AmigaPath;
  1119.  
  1120.     for (i=0, j=0; i<strlen(AmigaPath); i++, j++) {
  1121.         if (AmigaPath[i] == '/') WinPath[j] = '\\';
  1122.         else if (AmigaPath[i] == ':') {
  1123.             WinPath[j++] = ':';
  1124.             WinPath[j] = '\\';
  1125.         }
  1126.         else WinPath[j] = AmigaPath[i];
  1127.     }
  1128.     WinPath[j] = '\0';
  1129.  
  1130.     return WinPath;
  1131. }
  1132.  
  1133.  
  1134. BOOL IsIn(char *string, char c)
  1135. {
  1136.     int i;
  1137.  
  1138.     for (i=0; i<strlen(string); i++)
  1139.         if (string[i] == c) return TRUE;
  1140.  
  1141.     return FALSE;
  1142. }
  1143.