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

  1. /*
  2. ** Amster - Upload
  3. ** by Jacob Laursen <laursen@myself.com>
  4. */
  5.  
  6. #include "include/config.h"
  7.  
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10.  
  11. #include <proto/dos.h>
  12. #include <proto/exec.h>
  13. #include <proto/socket.h>
  14.  
  15. #include <netdb.h>
  16. #include <sys/time.h>
  17. #include <sys/socket.h>
  18. #include <sys/ioctl.h>
  19. #include <netinet/tcp.h>
  20. #include <bsdsocket/socketbasetags.h>
  21. #include <error.h>
  22. #include <time.h>
  23.  
  24. #include "include/mui.h"
  25. #include <MUI/NListview_mcc.h>
  26. #include "include/gui.h"
  27. #include "include/panel.h"
  28. #include "include/prefs.h"
  29. #include "include/share.h"
  30. #include "include/transfer.h"
  31. #include "include/upload.h"
  32. #include "amster_Cat.h"
  33. #include "include/protos.h"
  34.  
  35.  
  36. #define ULC_STATE 0
  37. #define ULC_SIZE 1
  38.  
  39. int ul_count = 0;
  40.  
  41. ULONG ul_new(struct IClass *cl, Object *obj, struct opSet *msg);
  42. void ul_cps(struct TransferData *data);
  43.  
  44.  
  45. MUIF ul_dispatch(REG(a0) struct IClass *cl,REG(a2) Object *obj,REG(a1) Msg msg)
  46. {
  47.     struct TransferData *data = INST_DATA(cl,obj);
  48.  
  49.     switch(msg->MethodID) {
  50.         case OM_NEW: return(ul_new(cl,obj,(APTR)msg));
  51.         case MUIM_Window_Setup:
  52.             return(dl_setup(cl,obj,(APTR)msg));
  53.         case MUIM_Window_Cleanup:
  54.             return(dl_muicleanup(cl,obj,(APTR)msg));
  55.         case UPLOAD_OPEN:
  56.             set(obj, MUIA_Window_Open, TRUE);
  57.             return(NULL);
  58.         case UPLOAD_CLOSE:
  59.             set(obj, MUIA_Window_Open, FALSE);
  60.             return(NULL);
  61.         case UPLOAD_UPDATE:
  62.             {
  63.             long pos = MUIV_NList_GetPos_Start;
  64.             DoMethod(data->list,MUIM_NList_GetPos,(((muimsg)msg)->arg1),&pos);
  65.             DoMethod(data->list,MUIM_NList_Redraw,pos);
  66.             return(NULL);
  67.             }
  68.         case UPLOAD_CPS:
  69.             ul_cps(data);
  70.             return(NULL);
  71.         case UPLOAD_ADD:
  72.             DoMethod(data->list,MUIM_NList_InsertSingle,(songtrans)(((muimsg)msg)->arg1),MUIV_NList_Insert_Bottom);
  73.             return(NULL);
  74.         case UPLOAD_START:
  75.             ul_startq2(data, (char *)(((muimsg)msg)->arg1), (char *)(((muimsg)msg)->arg2), (u_long)(((muimsg)msg)->arg3), (int)(((muimsg)msg)->arg4));
  76.             return(NULL);
  77.         case UPLOAD_INFO:
  78.             TransferInfo(data);
  79.             return(0);
  80.         case UPLOAD_ABORT:
  81.             ul_abort(data);
  82.             return(NULL);
  83.         case UPLOAD_CLEANUP:
  84.             TransferCleanup(data);
  85.             return(NULL);
  86.     }
  87.     return(DoSuperMethodA(cl,obj,msg));
  88. }
  89.  
  90.  
  91. ULONG ul_new(struct IClass *cl, Object *obj, struct opSet *msg)
  92. {
  93.     static struct Hook uplistdispHook = { {0,0}, &translistdisp, NULL, NULL };
  94.     struct TransferData *data;
  95.     Object *list, *info, *BT_Abort, *BT_Clean;
  96.  
  97.     if (obj = (Object *)DoSuperNew(cl,obj,
  98.         MUIA_Window_Title, MSG_UPLOAD_TITLE,
  99.         MUIA_Window_ID, MAKE_ID('U','P','L','D'),
  100.         WindowContents, VGroup,
  101.             Child, list = NListviewObject,
  102.                 MUIA_NListview_NList, NListObject,
  103.                     InputListFrame,
  104.                     MUIA_Font, MUIV_Font_Tiny,
  105.                     MUIA_NList_Title, TRUE,
  106.                     MUIA_NList_Format, "BAR, BAR, BAR, BAR, BAR",
  107.                     MUIA_NList_DisplayHook, &uplistdispHook,
  108.                     MUIA_CycleChain, 1,
  109.                 End,
  110.             End,
  111.             Child, info = TextObject,
  112.                 TextFrame,
  113.                 MUIA_Background, MUII_TextBack,
  114.                 MUIA_Text_PreParse, "\33c",
  115.             End,
  116.             Child, HGroup,
  117.                 Child, BT_Abort = SimpleButton(MSG_UPLOAD_ABORT_GAD),
  118.                 Child, BT_Clean = SimpleButton(MSG_UPLOAD_CLEANUP_GAD),
  119.             End,
  120.         End,
  121.         TAG_MORE, msg->ops_AttrList))
  122.     {
  123.         data = INST_DATA(cl,obj);
  124.         data->list = list;
  125.         data->info = info;
  126.  
  127.         data->ihnode.ihn_Object = obj;
  128.         data->ihnode.ihn_Millis = 1000;
  129.         data->ihnode.ihn_Method = UPLOAD_CPS;
  130.         data->ihnode.ihn_Flags  = MUIIHNF_TIMER;
  131.  
  132.         DoMethod(BT_Abort, MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, UPLOAD_ABORT  );
  133.         DoMethod(BT_Clean, MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, UPLOAD_CLEANUP);
  134.         DoMethod(list, MUIM_Notify, MUIA_NList_EntryClick, MUIV_EveryTime, obj, 1, UPLOAD_INFO);
  135.         DoMethod(obj, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, obj, 1, UPLOAD_CLOSE);
  136.  
  137.         return((ULONG)obj);
  138.     }
  139.     return(0);
  140. }
  141.  
  142.  
  143. void ul_cps(struct TransferData *data)
  144. {
  145.     songtrans sd;
  146.     u_long item;
  147.     int i;
  148.  
  149.     for (i=0; ; i++) {
  150.         DoMethod(data->list, MUIM_NList_GetEntry, i, &item);
  151.         if (!item) return;
  152.         sd = (songtrans)item;
  153.         if (sd->state == DLS_UP) {
  154.             CalculateCps(sd);
  155.             DoMethod(gui->uwin, UPLOAD_UPDATE, sd);
  156.         }
  157.     }
  158. }
  159.  
  160.  
  161. void ul_addq(song s)
  162. /* This is the initial function, called from share.c */
  163. {
  164.     songtrans sd;
  165.     char *path;
  166.  
  167. gui_debugf("ul_addq() - upload count: %d, queue limit: %d", ul_count, prf->UploadQueueLimit);
  168.  
  169.     path = MakeWinPath(s->title);
  170.     if (ul_count < prf->UploadQueueLimit) {
  171.         sprintf(nap_buf, "%s \"%s\"", s->user, path);
  172.         free(path);
  173.         nap_send(NAPC_UPLOADACCEPT);
  174.     }
  175.     else {
  176.         sprintf(nap_buf, "%s \"%s\" %d", s->user, path, prf->UploadQueueLimit);
  177.         free(path);
  178.         nap_send(NAPC_LOCALQUEUEFULL);
  179. gui_debugf("Queue limit reached! (%d)", prf->UploadQueueLimit);
  180.         return;
  181.     }
  182.  
  183.     sd = malloc(sizeof(_songtrans));
  184.     if (!sd) return;
  185.     memset(sd, 0, sizeof(_songtrans));
  186.  
  187.     sd->song = nap_songdup(s);
  188.     if (!sd->song) {
  189.         free(sd);
  190.         return;
  191.     }
  192.  
  193.     sd->size = s->size;
  194.     sd->mynick = prf->user;
  195.     sd->type = TYPE_UPLOAD_OUT;
  196.  
  197.     DoMethod(gui->uwin, UPLOAD_ADD, sd);
  198. }
  199.  
  200.  
  201. void ul_startq(char *title, char *user, u_long ip, int port, int link)
  202. /* This is the initial function, when the actual upload is about to
  203.    take place (acknowledged by server) - called from napster.c */
  204. {
  205.     DoMethod(gui->uwin, UPLOAD_START, title, user, ip, port);
  206. }
  207.  
  208.  
  209. void ul_startq2(struct TransferData *data, char *title, char *user, u_long ip, int port)
  210. /* ul_startq() continued (to get TransferData struct) */
  211. {
  212.     u_long tmp;
  213.     songtrans sd;
  214.     long i;
  215.     char *path;
  216.  
  217.     for (i=0; ; i++) {
  218.         DoMethod(data->list, MUIM_NList_GetEntry, i, &tmp);
  219.         if (!tmp) return;
  220.         sd = (songtrans)tmp;
  221.         path = MakeWinPath(sd->song->title);
  222.         if (sd->state==DLS_PREP && stricmp(user, sd->song->user)==0 && strcmp(title, path)==0) break;
  223.     }
  224.     free(path);
  225.  
  226.     if (sd->t) return;    /* Already in a thread */
  227.  
  228. gui_debugf("ul-ack [%s], port: %d, ip: %ld\n",title,port,ip);
  229.  
  230.     /* We haven't filled out sd->song completely yet, since not much
  231.        information was available when the request was made */
  232.     sd->song->ip = ip;
  233.  
  234.     /* Why do we need the IP twice? Check and use only one of them! */
  235.     sd->ip = ip;
  236.     sd->port = port;
  237.  
  238.     sd->t = th_spawn(ul_handlemsg, "Amster uploader", UploadThread, prf->UploadTaskPri, sd);
  239.     if (!sd->t) {
  240.         sd->state = DLS_ERROR;
  241.         DoMethod(gui->uwin, DL_UPDATE, sd);
  242.     }
  243. }
  244.  
  245.  
  246. void ul_abort(struct TransferData *data)
  247. {
  248.     u_long item;
  249.     songtrans sd;
  250.  
  251.     DoMethod(data->list, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &item);
  252.     if (!item) return;
  253.  
  254.     sd = (songtrans)item;
  255.     if (!sd->t) {
  256.         sd->state = DLS_ABORT;
  257.         DoMethod(gui->uwin, UPLOAD_UPDATE, sd);
  258.         return;
  259.     }
  260.     else {
  261.         if (sd->ts) th_message(sd->t, THC_EXIT, 0);
  262.     }
  263. }
  264.  
  265.  
  266. void ul_handlemsg(thread t, int com, APTR data)
  267. {
  268.     songtrans sd=(songtrans)t->data;
  269.  
  270.     switch(com) {
  271.         case THC_STARTUP:
  272. gui_debugf("upload thread start");
  273.             sd->ts = 1;
  274.             ul_count++;
  275.             nap_sendbuf(NAPC_ULINC, "");
  276.             break;
  277.         case THC_EXIT:
  278. gui_debugf("upload thread exit = %ld", data);
  279.             sd->error = (int)data;
  280.             TransferHandleError(sd);
  281.             sd->ts = 0;
  282.             sd->t = NULL;
  283.             ul_count--;
  284.             nap_sendbuf(NAPC_ULCOMPLETE, "");
  285.             break;
  286.         case DLC_STATE:
  287.             sd->state = (int)data;
  288.         case DLC_UPDATE:
  289.             DoMethod(gui->uwin, UPLOAD_UPDATE, sd);
  290.             break;
  291.         default:
  292.             gui_debugf("upload thread c: %d, d: %ld", com, data);
  293.     }
  294. }
  295.  
  296.  
  297. /* Upload thread */
  298.  
  299. __asm __saveds void UploadThread(void)
  300. {
  301.     thread t;
  302.     songtrans sd;
  303.     struct Library *DosBase;
  304.     struct Library *SocketBase;
  305.     char *buffer, *path;
  306.     long tmp;
  307.     long s;
  308.     thmsg m;
  309.     int len;
  310.  
  311.     t = thr_init();
  312.     if (!t) return;
  313.     sd = t->data;
  314.  
  315.     if (!InitTransferThread(t, sd)) return;
  316.     s = sd->s;
  317.     buffer = sd->buffer;
  318.     DosBase = sd->DosBase;
  319.     SocketBase = sd->SocketBase;
  320.  
  321.     while (1) {
  322.         u_long sigs;
  323.  
  324.         sigs = Wait(sd->nsigm|sd->msigm);
  325.         if (sigs&(sd->msigm)) {
  326.             m = (thmsg)GetMsg(t->port);
  327.             if(m) {
  328.                 if (m->com == THC_EXIT) {
  329.                     thr_message(t, DLC_STATE, (APTR)DLS_ABORT);
  330.                     ExitTransferThread(sd, 0);
  331.                     return;
  332.                 }
  333.                 if (!m->isreply) {
  334.                     m->isreply=1;
  335.                     ReplyMsg((struct Message *)m);
  336.                 }
  337.             }
  338.         }
  339.  
  340.         if (sigs&(sd->nsigm)) {
  341.             FD_ZERO(&sd->fds);
  342.             FD_SET(s,&sd->fds);
  343.             sd->tv.tv_sec = 0;
  344.             sd->tv.tv_usec = 0;
  345.  
  346.             switch(sd->state) {
  347.                 case DLS_CON:
  348.                     if (WaitSelect(s+1,NULL,&sd->fds,NULL,&sd->tv,0) != 1) break;
  349.                     {
  350.                         sd->state = DLS_INIT;
  351.                         tmp = 0;
  352.                         IoctlSocket(s, FIONBIO, (char*)&tmp);
  353.                         /* Disable non-blocking I/O to the socket */
  354.                     }
  355.  
  356.                 case DLS_INIT:
  357.                     if (WaitSelect(s+1,&sd->fds,NULL,NULL,&sd->tv,0) != 1) break;
  358.                     {
  359.                         tmp = recv(s, buffer, 1, 0);
  360.                         if (tmp != 1 || (tmp == 1 && buffer[0] != '1')) {
  361.                             ExitTransferThread(sd, 30);
  362.                             return;
  363.                         }
  364.                         thr_message(t, DLC_UPDATE, 0);
  365.                         send(s, "SEND", 4, 0);
  366.  
  367.                         path = MakeWinPath(sd->song->title);
  368.                         sprintf(buffer, "%s \"%s\" %ld", sd->mynick, path, sd->song->size);
  369.                         free(path);
  370.                         send(s, buffer, strlen(buffer),0);
  371.  
  372.                         tmp = recv(s, buffer, 32, 0);
  373.                         if (tmp < 1) {
  374.                             sd->ErrorCode = Errno();
  375.                             ExitTransferThread(sd, ERROR_NET);
  376.                             return;
  377.                         }
  378.                         buffer[tmp] = '\0';
  379.  
  380.                         sd->cur = atoi(buffer);
  381.                         if (sd->cur == 0 && buffer[0] != '0') {
  382. gui_debugf("%s\n", buffer);
  383.                             ExitTransferThread(sd, 31);
  384.                             return;
  385.                         }
  386.  
  387.                         sd->f = Open(sd->song->title, MODE_OLDFILE);
  388.                         if (!sd->f) {
  389.                             sd->ErrorCode = IoErr();
  390.                             ExitTransferThread(sd, ERROR_FILEOPEN);
  391.                             return;
  392.                         }
  393.  
  394.                         Seek(sd->f, sd->cur, OFFSET_BEGINNING);
  395.                         sd->state = DLS_UP;
  396.                         sd->starttime = time(NULL);
  397.                         sd->resumestart = sd->cur;
  398.                         thr_message(t, DLC_UPDATE, 0);
  399.                     }
  400.  
  401.                 case DLS_UP:
  402.                     if (WaitSelect(s+1,NULL,&sd->fds,NULL,&sd->tv,0) != 1) break;
  403.                     while (sd->cur < sd->size) {
  404.  
  405.                         len = Read(sd->f, buffer, 4096);
  406.                         if (len == -1) {    /* Error */
  407.                             sd->ErrorCode = IoErr();
  408.                             ExitTransferThread(sd, ERROR_FILEREAD);
  409.                             return;
  410.                         }
  411.                         if (len != 0) {
  412.                             tmp = send(s, buffer, len, 0);
  413.                             if (tmp == -1) {
  414.                                 sd->ErrorCode = Errno();
  415.                                 ExitTransferThread(sd, ERROR_NET);
  416.                                 return;
  417.                             }
  418.                             if (tmp != len) {
  419. gui_debugf("WARNING (please notify Laursen): all data from Read() was not send() - %ld/%ld.\n", len, tmp);
  420.                             }
  421.                             sd->cur += len;
  422.                         }
  423.  
  424.                         if (len < 4096 && sd->cur < sd->size) {
  425.                             /* Read buffer wasn't filled and file is not finished */
  426.                             thr_message(t, DLC_STATE, (APTR)DLS_ERROR);
  427.                             ExitTransferThread(sd, 33);
  428.                             return;
  429.                         }
  430.  
  431.                         m = (thmsg)GetMsg(t->port);
  432.                         if (m) {
  433.                             if (m->com == THC_EXIT) {
  434.                                 thr_message(t, DLC_STATE, (APTR)DLS_ABORT);
  435.                                 ExitTransferThread(sd, 0);
  436.                                 return;
  437.                             }
  438.                             if (!m->isreply) {
  439.                                 m->isreply=1;
  440.                                 ReplyMsg((struct Message *)m);
  441.                             }
  442.                         }
  443.  
  444.                         FD_ZERO(&sd->fds);
  445.                         FD_SET(s,&sd->fds);
  446.                     }
  447.  
  448.                     thr_message(t, DLC_STATE, (APTR)DLS_FIN);
  449.                     ExitTransferThread(sd, 0);
  450.                     return;
  451.  
  452.             }
  453.         }
  454.     }
  455.  
  456.     ExitTransferThread(sd, 0);
  457. }
  458.