/* ** Transfer */ #include "include/config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "include/mui.h" #include #include "include/download.h" #include "include/upload.h" #include "include/gui.h" #include "include/panel.h" #include "include/prefs.h" #include "include/transfer.h" #include "amster_Cat.h" #include "include/protos.h" MUIF translistdisp(REG(a2) char **array, REG(a1) songtrans sd) { static char buf2[50],buf3[50],buf4[50],buf5[50]; static char *states[] = { (char *)_MSG_TRANS_STAT_PREPARE, (char *)_MSG_TRANS_STAT_QUEUE, (char *)_MSG_TRANS_STAT_WAIT, (char *)_MSG_TRANS_STAT_CONN, (char *)_MSG_TRANS_STAT_REQ, (char *)_MSG_TRANS_STAT_INIT, (char *)_MSG_TRANS_STAT_DL, (char *)_MSG_TRANS_STAT_UL, (char *)_MSG_TRANS_STAT_FIN, (char *)_MSG_TRANS_STAT_ABORT, (char *)_MSG_TRANS_STAT_ERROR, NULL }; static char *errors[] = { (char *)_MSG_TRANS_STAT_ERROR, (char *)_MSG_TRANS_ERROR_FILEOPEN, (char *)_MSG_TRANS_ERROR_FILEREAD, (char *)_MSG_TRANS_ERROR_FILEWRITE, (char *)_MSG_TRANS_ERROR_NET_UNKNOWN, (char *)_MSG_TRANS_ERROR_LOGGEDOUT, (char *)_MSG_TRANS_ERROR_NOTFOUND, (char *)_MSG_TRANS_ERROR_INVALIDREQUEST, (char *)_MSG_TRANS_ERROR_TEASER, (char *)_MSG_TRANS_ERROR_BUSY, NULL }; static char *NetError[] = { (char *)_MSG_TRANS_ERROR_NET_TIMEOUT, (char *)_MSG_TRANS_ERROR_NET_REFUSED, (char *)_MSG_TRANS_ERROR_NET_RESET, (char *)_MSG_TRANS_ERROR_NET_PIPE, NULL }; if(states[0] == (char *)_MSG_TRANS_STAT_PREPARE) localize_array(states); if(errors[0] == (char *)_MSG_TRANS_STAT_ERROR) localize_array(errors); if(NetError[0] == (char *)_MSG_TRANS_ERROR_NET_TIMEOUT) localize_array(NetError); if(sd) { *array++ = nap_strippath(sd->song->title); if (sd->state == DLS_WAIT) { sprintf(buf5, states[sd->state], sd->ErrorCode); *array++ = buf5; } else if (sd->state != DLS_ERROR) *array++ = states[sd->state]; else { switch (sd->error) { case ERROR_FILEOPEN: case ERROR_FILEREAD: case ERROR_FILEWRITE: sprintf(buf5, errors[sd->error], sd->ErrorCode); *array++ = buf5; break; case ERROR_NET: switch (sd->ErrorCode) { case ETIMEDOUT: *array++ = NetError[ERROR_NET_TIMEOUT]; break; case ECONNREFUSED: *array++ = NetError[ERROR_NET_REFUSED]; break; default: sprintf(buf5, errors[sd->error], sd->ErrorCode); *array++ = buf5; } break; default: *array++ = errors[sd->error]; } } if (sd->size > 0) sprintf(buf2,"\33r%ld / %ld (%d%%)", sd->cur, sd->size, (sd->cur*100+5)/sd->size); else sprintf(buf2, "\33r0"); /* Can this happen? */ *array++ = buf2; if (sd->cps > 0) { if (sd->stalltick<5) { /* 5 seconds */ sprintf(buf3,"%d",sd->cps); *array++ = buf3; } else { *array++ = (char *)MSG_TRANS_STAT_STALLED; } sprintf(buf4,"%ld:%02ld / %ld:%02ld",sd->transtime/60,sd->transtime%60,sd->timeleft/60,sd->timeleft%60); *array = buf4; } else { *array++ = "-"; *array = "-"; } } else { *array++ = (char *)MSG_LH_FILE; *array++ = (char *)MSG_LH_STATE; *array++ = (char *)MSG_LH_SIZE; *array++ = (char *)MSG_LH_CPS; *array = (char *)MSG_LH_ETIME; } return(0); } ULONG dl_setup(struct IClass *cl, Object *obj, Msg msg) { struct TransferData *data = INST_DATA(cl,obj); if (!DoSuperMethodA(cl,obj,msg)) return(FALSE); DoMethod(_app(obj), MUIM_Application_AddInputHandler, &data->ihnode); return(TRUE); } ULONG dl_muicleanup(struct IClass *cl, Object *obj, Msg msg) { struct TransferData *data = INST_DATA(cl,obj); DoMethod(_app(obj), MUIM_Application_RemInputHandler, &data->ihnode); return(DoSuperMethodA(cl,obj,msg)); } void CalculateCps(songtrans sd) { if (sd->cur != sd->oldsize) { sd->stalltick = 0; sd->oldsize = sd->cur; } else sd->stalltick++; sd->transtime = time(NULL) - sd->starttime; if (sd->transtime == 0) sd->transtime = 1; sd->cps = (sd->cur - sd->resumestart) / sd->transtime; if (sd->cps > 0) sd->timeleft = (sd->size - sd->cur) / sd->cps; else sd->timeleft = 0; } void TransferSetError(struct TransferData *data, char *title, char *user, int error) { u_long tmp; songtrans sd; long i; for (i=0; ; i++) { DoMethod(data->list, MUIM_NList_GetEntry, i, &tmp); if (!tmp) return; sd = (songtrans)tmp; if (strcmp(sd->song->title, title) == 0 && stricmp(sd->song->user, user) == 0) break; } sd->state = DLS_ERROR; sd->error = error; if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) DoMethod(gui->dwin, DL_UPDATE, sd); else DoMethod(gui->uwin, UPLOAD_UPDATE, sd); } void TransferInfo(struct TransferData *data) { static char buf[600]; u_long tmp; songtrans sd; GetAttr(MUIA_NList_EntryClick, data->list, &tmp); if (tmp == -1 || tmp == -2) return; DoMethod(data->list, MUIM_NList_GetEntry, tmp, &sd); if (!sd) return; if(sd->host[0] == '\0') { sprintf(buf, "%s (%s)", sd->song->user, Inet_NtoA(sd->song->ip)); } else { sprintf(buf, "%s (%s)", sd->song->user, sd->host); } set(data->info, MUIA_Text_Contents, buf); } void TransferCleanup(struct TransferData *data) { u_long item; int i=0, j; while (1) { DoMethod(data->list, MUIM_NList_GetEntry, i, &item); if (!item) break; j = ((songtrans)item)->state; if (j >= DLS_FIN) { DoMethod(data->list,MUIM_NList_Remove,i); nap_songfree(((songtrans)item)->song); if (((songtrans)item)->fname) free(((songtrans)item)->fname); free((songtrans)item); } else i++; } } void TransferHandleError(songtrans sd) { char error[128]; if (sd->error != 0) { sd->state = DLS_ERROR; if (sd->error >= ERROR_FILEOPEN && sd->error <= ERROR_FILEWRITE) { Fault(sd->ErrorCode, "", error, 127); gui_debugf((char *)MSG_INFO_IOERROR, sd->fname, error); } else if (sd->error >= ERROR_OUTOFBOUND) sd->error = ERROR_UNKNOWN; prf_event(PRFE_DLERROR); } else if (sd->state == DLS_FIN) { if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) prf_event(PRFE_DLFINISH); else prf_event(PRFE_ULFINISH); } if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) DoMethod(gui->dwin, DL_UPDATE, sd); else DoMethod(gui->uwin, UPLOAD_UPDATE, sd); } /* Thread stuff */ BOOL InitTransferThread(thread t, songtrans sd) { struct Library *DosBase; struct Library *SocketBase; char *buffer; long s; long tmp; struct hostent *he; sd->state = DLS_PREP; sd->nsig = AllocSignal(-1); if (sd->nsig == -1) { ExitTransferThread(sd, 1); return FALSE; } sd->nsigm = (1L << (sd->nsig)); sd->msigm = (1L << (t->port->mp_SigBit)); DosBase = OpenLibrary("dos.library", 0); if (!DosBase) { ExitTransferThread(sd, 1); return FALSE; } sd->DosBase = DosBase; SocketBase = OpenLibrary("bsdsocket.library", 0); if (!SocketBase) { ExitTransferThread(sd, 1); return FALSE; } sd->SocketBase = SocketBase; SocketBaseTags(SBTM_SETVAL(SBTC_SIGIOMASK), (char *)sd->nsigm, TAG_DONE); buffer = malloc(8192); if (!buffer) { ExitTransferThread(sd, 2); return FALSE; } sd->buffer = buffer; /* Perform DNS-lookup */ he = gethostbyname(Inet_NtoA(sd->song->ip)); he = gethostbyaddr(he->h_addr_list[0], he->h_length, AF_INET); if (he != 0) strcpy(sd->host, he->h_name); else strcpy(sd->host, Inet_NtoA(sd->song->ip)); s = socket(AF_INET, SOCK_STREAM, 0); if (s<0) { ExitTransferThread(sd, 3); return FALSE; } sd->s = s; sd->sin.sin_addr.s_addr = sd->ip; sd->sin.sin_port = sd->port; sd->sin.sin_family = AF_INET; sd->sin.sin_len = sizeof(sd->sin); tmp = 1; IoctlSocket(s, FIOASYNC, (char *)&tmp); IoctlSocket(s, FIONBIO, (char *)&tmp); /* Asynchronous and non-blocking I/O to the socket */ tmp = connect(s, (struct sockaddr *)&sd->sin, sizeof(sd->sin)); if (tmp == -1 && Errno() != EINPROGRESS) { sd->ErrorCode = Errno(); ExitTransferThread(sd, ERROR_NET); return FALSE; } thr_message(t, DLC_STATE, (APTR)DLS_CON); return TRUE; } void ExitTransferThread(songtrans sd, int ret) { struct Library *DosBase=sd->DosBase; struct Library *SocketBase=sd->SocketBase; if (sd->nsig != -1) FreeSignal(sd->nsig); sd->nsig = -1; if (sd->f) Close(sd->f); sd->f = 0; if (sd->s != -1) CloseSocket(sd->s); sd->s = -1; if (sd->buffer) free(sd->buffer); sd->buffer = NULL; if (SocketBase) CloseLibrary(SocketBase); sd->SocketBase = NULL; if (DosBase) CloseLibrary(DosBase); sd->DosBase = NULL; thr_exit(sd->t, ret); }