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

  1. /*
  2. ** Download
  3. */
  4.  
  5. #include "include/config.h"
  6.  
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10.  
  11. #include <proto/exec.h>
  12. #include <proto/socket.h>
  13. #include <proto/dos.h>
  14. #include <proto/asl.h>
  15. #include <exec/memory.h>
  16. #include <libraries/dos.h>
  17. #include <libraries/asl.h>
  18. #include <netdb.h>
  19. #include <sys/time.h>
  20. #include <sys/socket.h>
  21. #include <sys/ioctl.h>
  22. #include <netinet/tcp.h>
  23. #include <bsdsocket/socketbasetags.h>
  24. #include <error.h>
  25. #include <time.h>
  26.  
  27. #include "include/mui.h"
  28. #include <MUI/NListview_mcc.h>
  29. #include <MUI/NFloattext_mcc.h>
  30. #include "include/gui.h"
  31. #include "include/rexx.h"
  32. #include "include/panel.h"
  33. #include "include/transfer.h"
  34. #include "include/download.h"
  35. #include "include/prefs.h"
  36. #include "include/share.h"
  37. #include "md5.h"
  38. #include "amster_Cat.h"
  39. #include "include/protos.h"
  40.  
  41.  
  42. int dl_count = 0;
  43. int WaitingCount = 0;
  44.  
  45. /* Private functions */
  46.  
  47. ULONG dl_new(struct IClass *cl, Object *obj, struct opSet *msg);
  48. void dl_startq2(struct TransferData *data, Object *obj, char *title, char *user, u_long ip, int port);
  49. void dl_checkqueue(struct TransferData *data);
  50. void DownloadRetry(struct TransferData *data, Object *obj, char *title, char *user, int limit);
  51. void PollWaiting(struct TransferData *data, Object *obj);
  52. int dl_filename(songtrans sd);
  53. char *chkmd5_fromlock(BPTR lock);
  54. int dl_askfname(char *fname);
  55. void dl_handlemsg(thread t, int com, APTR data);
  56. void dl_abort(struct TransferData *data);
  57. void dl_resume(struct TransferData *data);
  58. void dl_cps(struct TransferData *data);
  59. __asm __saveds void dl_sucker(void);
  60.  
  61.  
  62. MUIF dl_dispatch(REG(a0) struct IClass *cl,REG(a2) Object *obj,REG(a1) Msg msg)
  63. {
  64.     struct TransferData *data = INST_DATA(cl,obj);
  65.  
  66.     switch(msg->MethodID) {
  67.         case OM_NEW:
  68.             return(dl_new(cl,obj,(APTR)msg));
  69.         case MUIM_Window_Setup:
  70.             return(dl_setup(cl,obj,(APTR)msg));
  71.         case MUIM_Window_Cleanup:
  72.             return(dl_muicleanup(cl,obj,(APTR)msg));
  73.         case DL_ADD:
  74.             DoMethod(data->list, MUIM_NList_InsertSingle, (songtrans)(((muimsg)msg)->arg1), MUIV_NList_Insert_Bottom);
  75.             return(NULL);
  76.         case DL_START:
  77.             dl_startq2(data, obj, (char *)(((muimsg)msg)->arg1), (char *)(((muimsg)msg)->arg2), (u_long)(((muimsg)msg)->arg3), (int)(((muimsg)msg)->arg4));
  78.             return(NULL);
  79.         case DL_CHECKQUEUE:
  80.             dl_checkqueue(data);
  81.             return(NULL);
  82.         case DL_UPDATE:
  83.             {
  84.             long pos = MUIV_NList_GetPos_Start;
  85.             DoMethod(data->list, MUIM_NList_GetPos, (((muimsg)msg)->arg1), &pos);
  86.             DoMethod(data->list, MUIM_NList_Redraw, pos);
  87.             return(NULL);
  88.             }
  89.         case DL_CPS:
  90.             dl_cps(data);
  91.             return(NULL);
  92.         case DL_CLEANUP:
  93.             TransferCleanup(data);
  94.             return(NULL);
  95.         case DL_ABORT:
  96.             dl_abort(data);
  97.             return(NULL);
  98.         case DL_RESUME:
  99.             dl_resume(data);
  100.             return(NULL);
  101.         case DL_INFO:
  102.             TransferInfo(data);
  103.             return(NULL);
  104.         case DL_PLAY:
  105.             {
  106.             u_long palpa;
  107.             char buf[1024], *command;
  108.  
  109.             DoMethod(data->list, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &palpa);
  110.             if (!palpa) return(NULL);
  111.             if (((songtrans)palpa)->state < DLS_DOWN) return(NULL);
  112.             if (prf->scripts[PRFE_PLAYMP3]) {
  113.                 sprintf(buf, "Run <>NIL: %s", prf->scripts[PRFE_PLAYMP3]);
  114.                 command = strrep(buf, "%f", ((songtrans)palpa)->fname);
  115.                 Execute(command, 0, 0);
  116.                 free(command);
  117.             }
  118.             return(NULL);
  119.             }
  120.         case DL_SETERROR:
  121.             TransferSetError(data, (char *)(((muimsg)msg)->arg1), (char *)(((muimsg)msg)->arg2), (int)(((muimsg)msg)->arg3));
  122.             return(NULL);
  123.         case DL_RETRY:
  124.             DownloadRetry(data, obj, (char *)(((muimsg)msg)->arg1), (char *)(((muimsg)msg)->arg2), (int)(((muimsg)msg)->arg3));
  125.             return(NULL);
  126.         case DL_POLLWAIT:
  127.             PollWaiting(data, obj);
  128.             return(NULL);
  129.         case DL_SETDELAY:
  130.             data->waitnode.ihn_Millis = (int)(((muimsg)msg)->arg1)*1000;
  131.             return(NULL);
  132.     }
  133.     return(DoSuperMethodA(cl,obj,msg));
  134. }
  135.  
  136.  
  137. ULONG dl_new(struct IClass *cl, Object *obj, struct opSet *msg)
  138. {
  139.     static struct Hook downlistdispHook = { {0,0}, &translistdisp, NULL, NULL };
  140.     struct TransferData *data;
  141.     Object *list, *info, *playbut, *abortbut, *resbut, *cleanbut;
  142.  
  143.     if (obj = (Object *)DoSuperNew(cl, obj,
  144.         MUIA_HelpNode, "download",
  145.         MUIA_Window_Title, MSG_DL_TITLE,
  146.         MUIA_Window_ID, MAKE_ID('D','O','W','N'),
  147.         WindowContents, VGroup,
  148.             Child, list = NListviewObject,
  149.                 MUIA_NListview_NList, NListObject,
  150.                     InputListFrame,
  151.                     MUIA_Font, MUIV_Font_Tiny,
  152.                     MUIA_NList_Title, TRUE,
  153.                     MUIA_NList_Format, "BAR, BAR, BAR, BAR, BAR",
  154.                     MUIA_NList_DisplayHook, &downlistdispHook,
  155.                     MUIA_CycleChain, 1,
  156.                 End,
  157.             End,
  158.             Child, info = TextObject,
  159.                 TextFrame,
  160.                 MUIA_Background, MUII_TextBack,
  161.                 MUIA_Text_PreParse, "\33c",
  162.             End,
  163.             Child, HGroup,
  164.                 Child, HGroup,
  165.                     Child, playbut = SimpleButton(MSG_DL_PLAY_GAD),
  166.                     MUIA_ShortHelp, MSG_PLAY_HELP,
  167.                 End,
  168.                 Child, HSpace(4),
  169.                 Child, HGroup,
  170.                     Child, abortbut = SimpleButton(MSG_DL_ABORT_GAD),
  171.                     MUIA_ShortHelp, MSG_ABORT_HELP,
  172.                 End,
  173.                 Child, HGroup,
  174.                     Child, resbut = SimpleButton(MSG_DL_RESUME_GAD),
  175.                     MUIA_ShortHelp, MSG_RESUME_HELP,
  176.                 End,
  177.                 Child, HSpace(4),
  178.                 Child, HGroup,
  179.                     Child, cleanbut = SimpleButton(MSG_DL_CLEANUP_GAD),
  180.                     MUIA_ShortHelp, MSG_CLEANUP_HELP,
  181.                 End,
  182.             End,
  183.         End,
  184.         TAG_MORE, msg->ops_AttrList))
  185.     {
  186.         data = INST_DATA(cl,obj);
  187.         data->list = list;
  188.         data->info = info;
  189.  
  190.         data->ihnode.ihn_Object = obj;
  191.         data->ihnode.ihn_Millis = 1000;
  192.         data->ihnode.ihn_Method = DL_CPS;
  193.         data->ihnode.ihn_Flags  = MUIIHNF_TIMER;
  194.  
  195.         data->waitnode.ihn_Object = obj;
  196.         data->waitnode.ihn_Millis = prf->QueueDelay*1000;    /* Poll interval in milliseconds */
  197.         data->waitnode.ihn_Method = DL_POLLWAIT;
  198.         data->waitnode.ihn_Flags  = MUIIHNF_TIMER;
  199.  
  200.         DoMethod(playbut,  MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, DL_PLAY   );
  201.         DoMethod(resbut,   MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, DL_RESUME );
  202.         DoMethod(abortbut, MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, DL_ABORT  );
  203.         DoMethod(cleanbut, MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, DL_CLEANUP);
  204.  
  205.         DoMethod(list, MUIM_Notify, MUIA_NList_EntryClick, MUIV_EveryTime, obj, 1, DL_INFO);
  206.         DoMethod(obj, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, gui->iconpanel, 1, PANEL_CLOSEDL);
  207.  
  208.         return((ULONG)obj);
  209.     }
  210.  
  211.     return(0);
  212. }
  213.  
  214.  
  215. void dl_addq(song s)
  216. /* This is the initial function, called from search.c */
  217. {
  218.     songtrans sd;
  219.  
  220.     sd = malloc(sizeof(_songtrans));
  221.     if (!sd) return;
  222.     memset(sd,0,sizeof(_songtrans));
  223.  
  224.     sd->song = nap_songdup(s);
  225.     if (!sd->song) {
  226.         free(sd);
  227.         return;
  228.     }
  229.  
  230.     sd->size = s->size;
  231.     sd->mynick = prf->user;
  232.     sd->type = TYPE_DOWNLOAD_OUT;
  233.  
  234.     DoMethod(gui->dwin, DL_ADD, sd);
  235. }
  236.  
  237.  
  238. void dl_startq(char *title, char *user, u_long ip, int port)
  239. /* This is the initial function, when the actual download is about to
  240.    take place (acknowledged by server) - called from napster.c */
  241. {
  242. /*gui_debugf("port : %d (file: %s, user: %s)", port, title, user);*/
  243.  
  244.     DoMethod(gui->dwin, DL_START, title, user, ip, port);
  245. }
  246.  
  247.  
  248. void dl_startq2(struct TransferData *data, Object *obj, char *title, char *user, u_long ip, int port)
  249. /* dl_startq() continued (to get TransferData struct) */
  250. {
  251.     u_long tmp;
  252.     songtrans sd;
  253.     long i;
  254.  
  255.     for (i=0; ; i++) {
  256.         DoMethod(data->list, MUIM_NList_GetEntry, i, &tmp);
  257.         if (!tmp) return;
  258.         sd = (songtrans)tmp;
  259.         if ((sd->state == DLS_PREP || sd->state == DLS_WAIT) && stricmp(user,sd->song->user)==0 && strcmp(title,sd->song->title)==0) break;
  260.     }
  261.  
  262.     if (sd->state == DLS_WAIT) {
  263.         WaitingCount--;
  264.         if (WaitingCount == 0) DoMethod(_app(obj), MUIM_Application_RemInputHandler, &data->waitnode);
  265.         /* This was the last waiting entry - remove input handler */
  266.  
  267.         sd->state = DLS_PREP;
  268.     } /* No more waiting - we've got green light! */
  269.  
  270.     if (sd->t) {
  271. gui_debug("this shouldn't happen!");
  272.         return;    /* Already in a thread */
  273.     }
  274.  
  275.     if (!dl_filename(sd)) {
  276.         sd->state = DLS_ABORT;
  277.         DoMethod(gui->dwin, DL_UPDATE, sd);
  278.         return;
  279.     }
  280.  
  281. /*gui_debugf("ack [%s]",title);*/
  282.  
  283.     sd->ip = ip;
  284.     sd->port = port;
  285.     sd->oldsize = sd->cur;
  286.  
  287.     if (dl_count == prf->DownloadQueueLimit) {
  288.         sd->state = DLS_QUEUE;
  289.         DoMethod(gui->dwin, DL_UPDATE, sd);
  290.         return;
  291.     }
  292.  
  293.     sd->t = th_spawn(dl_handlemsg, "Amster downloader", dl_sucker, prf->DownloadTaskPri, sd);
  294.     if (!sd->t) {
  295.         sd->state = DLS_ERROR;
  296.         DoMethod(gui->dwin, DL_UPDATE, sd);
  297.     }
  298. }
  299.  
  300.  
  301. void dl_checkqueue(struct TransferData *data)
  302. {
  303.     u_long tmp;
  304.     songtrans sd;
  305.     long i;
  306.  
  307.     for (i=0;;i++) {
  308.         DoMethod(data->list, MUIM_NList_GetEntry, i, &tmp);
  309.         if (!tmp) return;
  310.         sd = (songtrans)tmp;
  311.         if (sd->state == DLS_QUEUE) break;
  312.     }
  313.  
  314.     sd->t = th_spawn(dl_handlemsg, "Amster downloader", dl_sucker, prf->DownloadTaskPri, sd);
  315.     if (!sd->t) sd->state = DLS_ERROR;
  316.     else sd->state = DLS_PREP;
  317.     DoMethod(gui->dwin, DL_UPDATE, sd);
  318. }
  319.  
  320.  
  321. void DownloadRetry(struct TransferData *data, Object *obj, char *title, char *user, int limit)
  322. {
  323.     u_long tmp;
  324.     songtrans sd;
  325.     long i;
  326.  
  327.     for (i=0; ; i++) {
  328.         DoMethod(data->list, MUIM_NList_GetEntry, i, &tmp);
  329.         if (!tmp) return;
  330.         sd = (songtrans)tmp;
  331.         if (strcmp(sd->song->title, title) == 0 && stricmp(sd->song->user, user) == 0) break;
  332.     }
  333.  
  334.     if (sd->RetryCount >= prf->QueueRetries) return;    /* We've already given up */
  335.     else if (limit == 0) {
  336.         sd->state = DLS_ERROR;
  337.         sd->error = ERROR_TEASER;    /* Queue limit is 0 = file can't be downloaded by anyone */
  338.     }
  339.     else {
  340.         if (sd->state == DLS_WAIT) return;    /* Already marked */
  341.  
  342.         sd->state = DLS_WAIT;
  343.         sd->ErrorCode = limit;
  344.         WaitingCount++;
  345.  
  346.         if (WaitingCount == 1) DoMethod(_app(obj), MUIM_Application_AddInputHandler, &data->waitnode);
  347.         /* This is the first waiting entry - add input handler */
  348.     }
  349.  
  350.     DoMethod(gui->dwin, DL_UPDATE, sd);
  351. }
  352.  
  353.  
  354. void PollWaiting(struct TransferData *data, Object *obj)
  355. {
  356.     u_long tmp;
  357.     songtrans sd;
  358.     long i;
  359.  
  360. /*gui_debug("PollWaiting()");*/
  361.     if (WaitingCount == 0) return;    /* Don't waste time! */
  362.  
  363.     for (i=0; ; i++) {
  364.         DoMethod(data->list, MUIM_NList_GetEntry, i, &tmp);
  365.         if (!tmp) return;
  366.         sd = (songtrans)tmp;
  367.         if (sd->state == DLS_WAIT) {
  368.             if (sd->RetryCount < prf->QueueRetries) {
  369. /*gui_debugf("Repeating request for '%s'", sd->song->title);*/
  370.                 sprintf(nap_buf,"\"%s\" \"%s\"", sd->song->user, sd->song->title);
  371.                 nap_send(NAPC_FILEINFOREQ);
  372.                 sd->RetryCount++;
  373.             }
  374.             else {
  375.                 sd->state = DLS_ERROR;
  376.                 sd->error = ERROR_BUSY;
  377.                 WaitingCount--;
  378.                 if (WaitingCount == 0) DoMethod(_app(obj), MUIM_Application_RemInputHandler, &data->waitnode);
  379.  
  380.                 DoMethod(gui->dwin, DL_UPDATE, sd);
  381.             }
  382.         }
  383.     }
  384. }
  385.  
  386.  
  387. void dl_resume(struct TransferData *data)
  388. {
  389.     u_long item;
  390.     songtrans sd;
  391.  
  392.     DoMethod(data->list, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &item);
  393.     if (!item) return;
  394.  
  395.     sd = (songtrans)item;
  396.     if (sd->state < DLS_ABORT) return;    /* Can't resume files that's already in progress */
  397.     if (sd->t) return;
  398.  
  399.     sd->state = DLS_PREP;
  400.     sprintf(nap_buf, "\"%s\" \"%s\"", sd->song->user, sd->song->title);
  401.     nap_send(NAPC_FILEINFOREQ);
  402.  
  403.     DoMethod(gui->dwin, DL_UPDATE, sd);
  404. }
  405.  
  406.  
  407. int dl_filename(songtrans sd)
  408. {
  409.     BPTR lock;
  410.     struct FileInfoBlock fib;
  411.     char md5[80]="";
  412.     char *fname;
  413.     long oldsize=0;
  414.     int way, reqrc;
  415.     char *expl, *choice;
  416.  
  417.     fname = malloc(512);
  418.     if (!fname) return(0);
  419.     strcpy(fname, prf->dlpath);
  420.     AddPart(fname, nap_strippath(sd->song->title), 511);
  421.  
  422.     if (prf->askfile) dl_askfname(fname);
  423.     else {    /* Needs optimization and elegance */
  424.         if (strlen(nap_strippath(sd->song->title)) > prf->NameLength) {
  425.             strcpy(fname+strlen(fname)-strlen(nap_strippath(sd->song->title))-4+prf->NameLength, fname+strlen(fname)-4);
  426.         }
  427.     }
  428.  
  429.     lock = Lock(fname, ACCESS_READ);
  430.     if (!lock) {
  431.         sd->fname = fname;
  432.         sd->cur = 0;
  433.         return(1);
  434.     }
  435.  
  436.     if (Examine(lock, &fib)) {
  437.         oldsize = fib.fib_Size;
  438.         sscanf(fib.fib_Comment, "md5: %[^;]", &md5);
  439.         if (md5[0] == 0 && oldsize >= 300032) strcpy(md5, chkmd5_fromlock(lock));
  440.             else UnLock(lock);
  441.     }
  442.     else UnLock(lock);
  443.  
  444.     if (sd->size <= oldsize) {
  445.         way = 1;
  446.         expl = (char *)MSG_DL_RESBIGSIZE;
  447.         choice = (char *)MSG_DL_OVERCANCEL_GAD;
  448.     }
  449.     else if (md5[0] == 0) {
  450.         way = 0;
  451.         expl = (char *)MSG_DL_NOMD5INFO;
  452.         choice = (char *)MSG_DL_RESUMECANCEL_GAD;
  453.     }
  454.     else if (strcmp(md5,sd->song->md5)!=0) {
  455.         way = 1;
  456.         expl = (char *)MSG_DL_NOMATCH;
  457.         choice = (char *)MSG_DL_OVERCANCEL_GAD;
  458.     }
  459.     else {
  460.         way = 2;
  461.         expl = (char *)MSG_DL_RESMATCH;
  462.         choice = (char *)MSG_DL_RESUMEOVER_GAD;
  463.     }
  464.  
  465.     reqrc = MUI_Request(gui->app, gui->win, 0L,
  466.                         (char *)MSG_DL_RESUME_INFO,
  467.                         choice,
  468.                         (char *)MSG_DL_RESUME_MSG,
  469.                         fname,
  470.                         oldsize,
  471.                         sd->size,
  472.                         md5[0]==0 ? (char*)MSG_DL_NOMD5 : md5,
  473.                         sd->song->md5,
  474.                         expl);
  475.  
  476.     if (reqrc == 0) return(0);
  477.  
  478.     if ((way==0 || way==2) && reqrc == 1) {
  479.         sd->fname = fname;
  480.         sd->cur = oldsize;
  481.         return(1);
  482.     }
  483.  
  484.     if (reqrc == 2) {
  485.         if (dl_askfname(fname)) {
  486.             sd->fname = fname;
  487.             sd->cur = 0;
  488.             return(1);
  489.         }
  490.         else return(0);
  491.     }
  492.  
  493.     sd->cur = 0;
  494.     sd->fname = fname;
  495.     return(1);
  496. }
  497.  
  498.  
  499. char *chkmd5_fromlock(BPTR lock)
  500. {
  501.     APTR buffer;
  502.     BPTR fh;
  503.     int len;
  504.     char md5[33] = "";
  505.  
  506.     md5_state_t state;
  507.     md5_byte_t digest[16];
  508.     int di;
  509.  
  510.     md5_init(&state);
  511.  
  512.     if (fh = OpenFromLock(lock)) {
  513.         if (buffer = AllocMem(300032, MEMF_ANY)) {
  514.  
  515.             len = Read(fh, buffer, 300032);
  516.             if (len > 0) {
  517.                 md5_append(&state, (const md5_byte_t *)buffer, len);
  518.                 md5_finish(&state, digest);
  519.                 for (di = 0; di < 16; ++di)
  520.                     sprintf(md5+di*2, "%02x", digest[di]);
  521.             }
  522.             FreeMem(buffer, 300032);
  523.         }
  524.         Close(fh);
  525.     }
  526.     else UnLock(lock);
  527.  
  528.     return md5;
  529. }
  530.  
  531.  
  532. int dl_askfname(char *fname)
  533. {
  534.     struct FileRequester *freq;
  535.  
  536.     freq = AllocAslRequestTags(ASL_FileRequest, TAG_DONE);
  537.     if (!freq) return(0);
  538.  
  539.     if (AslRequestTags(freq,
  540.                       ASLFR_TitleText, MSG_DL_SELECTFILE,
  541.                       ASLFR_InitialFile, nap_strippath(fname),
  542.                       ASLFR_InitialDrawer, prf->dlpath,
  543.                       ASLFR_DoSaveMode, TRUE,
  544.                       TAG_DONE)) {
  545.         strcpy(fname, freq->fr_Drawer);
  546.         AddPart(fname, freq->fr_File, 511);
  547.         FreeAslRequest(freq);
  548.         return(1);
  549.     }
  550.     else {
  551.         FreeAslRequest(freq);
  552.         return(0);
  553.     }
  554. }
  555.  
  556.  
  557. void dl_abort(struct TransferData *data)
  558. {
  559.     u_long item;
  560.     songtrans sd;
  561.  
  562.     DoMethod(data->list, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &item);
  563.     if (!item) return;
  564.  
  565.     sd = (songtrans)item;
  566.     if (!sd->t) {
  567.         if (sd->state == DLS_WAIT) WaitingCount--;
  568.         sd->state = DLS_ABORT;
  569.         DoMethod(gui->dwin, DL_UPDATE, sd);
  570.         return;
  571.     }
  572.     else {
  573.         if (sd->ts) th_message(sd->t, THC_EXIT, 0);
  574.     }
  575. }
  576.  
  577.  
  578. void dl_handlemsg(thread t, int com, APTR data)
  579. /* This is the function that receives messages from the download
  580.    thread. It's called when something needs to be done in the
  581.    main thread (i.e. updating the window). */
  582. {
  583.     songtrans sd=(songtrans)t->data;
  584.  
  585.     switch(com) {
  586.         case THC_STARTUP:
  587. gui_debugf("thread start");
  588.             sd->ts = 1;
  589.             dl_count++;
  590.             nap_sendbuf(NAPC_DLINC, "");
  591.             break;
  592.         case THC_EXIT:
  593. gui_debugf("thread exit = %ld, file: %s",data, sd->fname);
  594.             sd->error = (int)data;
  595.             TransferHandleError(sd);
  596.             sd->ts = 0;
  597.             sd->t = NULL;
  598.             dl_count--;
  599.             nap_sendbuf(NAPC_DLCOMPLETE, "");
  600.             DoMethod(gui->dwin, DL_CHECKQUEUE);
  601.             break;
  602.         case DLC_STATE:
  603.             sd->state = (int)data;
  604.         case DLC_UPDATE:
  605.             DoMethod(gui->dwin, DL_UPDATE, sd);
  606.             break;
  607.         case DLC_ADDSHARE:
  608.             DoMethod(gui->shwin, SHARE_ADDFILE, sd->song, sd->fname);
  609.             break;
  610.         default:
  611.             gui_debugf("thread c: %d, d: %ld",com,data);
  612.     }
  613. }
  614.  
  615.  
  616. void dl_cps(struct TransferData *data)
  617. {
  618.     songtrans sd;
  619.     u_long item;
  620.     int i;
  621.  
  622.     for (i=0; ; i++) {
  623.         DoMethod(data->list,MUIM_NList_GetEntry,i,&item);
  624.         if(!item) return;
  625.         sd = (songtrans)item;
  626.         if (sd->state == DLS_DOWN) {
  627.  
  628.             CalculateCps(sd);
  629.             DoMethod(gui->dwin, DL_UPDATE, sd);
  630.  
  631. /*
  632.             sd->transtime++;
  633.             size = sd->cur;
  634.             if(size != sd->oldsize) {
  635.                 sd->stalltick = 0;
  636.                 sd->cps = size - sd->oldsize;
  637.                 sd->oldsize = size;
  638.                 if(sd->cps>0) sd->timeleft = (sd->size - size) / sd->cps;
  639.                 DoMethod(gui->dwin,DL_UPDATE,sd);
  640.             }
  641.             else {
  642.                 if(sd->stalltick>2) sd->cps=0; else sd->stalltick++;
  643.             }
  644. */
  645.         }
  646.     }
  647. }
  648.  
  649.  
  650. /* thread code */
  651.  
  652. __asm __saveds void dl_sucker(void)
  653. {
  654.     thread t;
  655.     songtrans sd;
  656.     struct Library *DosBase;
  657.     struct Library *SocketBase;
  658.     char *buffer;
  659.     long tmp;
  660.     long s;
  661.     thmsg m;
  662.     char cmnt[80];
  663.     int count;
  664.  
  665.     t = thr_init();
  666.     if (!t) return;
  667.     sd = t->data;
  668.  
  669.     if (!InitTransferThread(t, sd)) return;
  670.     sd->RetryCount = 0;
  671.     s = sd->s;
  672.     buffer = sd->buffer;
  673.     DosBase = sd->DosBase;
  674.     SocketBase = sd->SocketBase;
  675.  
  676.     while (1) {
  677.         u_long sigs;
  678.  
  679.         sigs = Wait(sd->nsigm | sd->msigm);
  680.         if (sigs&(sd->msigm)) {
  681.             m = (thmsg)GetMsg(t->port);
  682.             if (m) {
  683.                 if (m->com == THC_EXIT) {
  684.                     sd->state = DLS_ABORT;
  685.                     thr_message(t, DLC_UPDATE, 0);
  686.                     ExitTransferThread(sd, 0);
  687.                     return;
  688.                 }
  689.                 if (!m->isreply) {
  690.                     m->isreply=1;
  691.                     ReplyMsg((struct Message *)m);
  692.                 }
  693.             }
  694.         }
  695.  
  696.         if (sigs&(sd->nsigm)) {
  697.             FD_ZERO(&sd->fds);
  698.             FD_SET(s,&sd->fds);
  699.             sd->tv.tv_sec = 0;
  700.             sd->tv.tv_usec = 0;
  701.  
  702.             switch (sd->state) {
  703.                 case DLS_CON:
  704.                     if (WaitSelect(s+1,NULL,&sd->fds,NULL,&sd->tv,0) != 1) break;
  705.                     {
  706.                         sd->state = DLS_REQ;
  707.                         tmp = 0;
  708.                         IoctlSocket(s, FIONBIO, (char*)&tmp);
  709.                         /* Disable non-blocking I/O to the socket */
  710.                     }
  711.  
  712.                 case DLS_REQ:
  713.                     if (WaitSelect(s+1,&sd->fds,NULL,NULL,&sd->tv,0) != 1) break;
  714.                     {
  715.                         tmp = recv(s, buffer, 1, 0);
  716.                         if (tmp != 1 || (tmp == 1 && buffer[0] != '1')) {
  717.                             ExitTransferThread(sd, 29);
  718.                             return;
  719.                         }
  720.                         thr_message(t, DLC_UPDATE, 0);
  721.                         send(s, "GET", 3, 0);
  722.                         sprintf(buffer, "%s \"%s\" %d", sd->mynick, sd->song->title, sd->cur);
  723.                         send(s, buffer, strlen(buffer), 0);
  724.  
  725.                         tmp = recv(s, buffer, 32, 0);
  726.                         if (tmp < 1) {
  727.                             sd->ErrorCode = Errno();
  728.                             ExitTransferThread(sd, ERROR_NET);
  729.                             return;
  730.                         }
  731.                         buffer[tmp] = '\0';
  732.  
  733.                         if (atoi(buffer) != sd->size) {
  734.                             if (strcmp(buffer, "FILE NOT FOUND") == 0) {
  735.                                 ExitTransferThread(sd, ERROR_NOTFOUND);
  736.                                 return;
  737.                             }
  738.                             else if (strcmp(buffer, "INVALID REQUEST") == 0) {
  739.                                 ExitTransferThread(sd, ERROR_INVALIDREQUEST);
  740.                                 return;
  741.                             }
  742.                             ExitTransferThread(sd, 12);
  743.                             return;
  744.                         }
  745.  
  746.                         sd->f = Open(sd->fname, MODE_READWRITE);
  747.                         if (!sd->f) {
  748.                             sd->ErrorCode = IoErr();
  749.                             ExitTransferThread(sd, ERROR_FILEOPEN);
  750.                             return;
  751.                         }
  752.                         sprintf(cmnt,"md5:%s; size:%ld", sd->song->md5, sd->size);
  753.                         SetComment(sd->fname, cmnt);
  754.                         Seek(sd->f, sd->cur, OFFSET_BEGINNING);
  755.                         sd->state = DLS_DOWN;
  756.                         sd->starttime = time(NULL);
  757.                         sd->resumestart = sd->cur;
  758.                         thr_message(t, DLC_UPDATE, 0);
  759.                     }
  760.  
  761.                 case DLS_DOWN:
  762.                     if (WaitSelect(s+1,&sd->fds,NULL,NULL,&sd->tv,0) != 1) break;
  763.                     while (sd->cur < sd->size) {
  764.  
  765.                         tmp = recv(s, buffer, 4096, 0);
  766.                         if (tmp < 1) {
  767.                             sd->ErrorCode = Errno();
  768.                             ExitTransferThread(sd, ERROR_NET);
  769.                             return;
  770.                         }
  771.                         SetIoErr(0L);    /* FWrite doesn't clear IoErr() due to a bug */
  772.                         count = FWrite(sd->f, buffer, 1, tmp);
  773.                         sd->cur += count;
  774.                         if (count != tmp) {
  775.                             sd->ErrorCode = IoErr();
  776.                             ExitTransferThread(sd, ERROR_FILEWRITE);
  777.                             return;
  778.                         }
  779.  
  780.                         m = (thmsg)GetMsg(t->port);
  781.                         if (m) {
  782.                             if (m->com == THC_EXIT) {
  783.                                 thr_message(t, DLC_STATE, (APTR)DLS_ABORT);
  784.                                 ExitTransferThread(sd, 0);
  785.                                 return;
  786.                             }
  787.                             if (!m->isreply) {
  788.                                 m->isreply = 1;
  789.                                 ReplyMsg((struct Message *)m);
  790.                             }
  791.                         }
  792.  
  793.                         FD_ZERO(&sd->fds);
  794.                         FD_SET(s,&sd->fds);
  795.                     }
  796.  
  797.                     sd->state = DLS_FIN;
  798.                     thr_message(t, DLC_UPDATE, 0);
  799.  
  800.                     if ((strlen(sd->song->user)+strlen(sd->host)+9) < 80) sprintf(cmnt, "from %s (@%s)", sd->song->user, sd->host);
  801.                     else sprintf(cmnt, "from %s (@%s)", sd->song->user, Inet_NtoA(sd->song->ip));
  802.                     /* If the hostname is too long for the file comment, we fall back to the IP */
  803.                     SetComment(sd->fname, cmnt);
  804.  
  805.                     if (prf->autoadd) thr_message(t, DLC_ADDSHARE, 0);
  806.  
  807.                     ExitTransferThread(sd, 0);
  808.                     return;
  809.  
  810.             }
  811.         }
  812.     }
  813.  
  814.     ExitTransferThread(sd, 0);
  815. }
  816.