001 class CDCCTransfer {
002 //bit0 is usage lock
003 //bit1 is done reciveing data flag
004   I64 lock;
005   I64 writer,accept,reader;
006   I64 port;
007   I64 fsz,token;
008   IrcClient *notify_to;
009   U8 name[STR_LEN];
010   U8 username[STR_LEN];
011 };
012 #define DCC_PORT_START 6000
013 #define DCC_PORT_END 6100
014 
015 #define DCC_DIR "T:/GihonFiles"
016 CDCCTransfer dcc_transfers[0x10000];;
017 MemSet(dcc_transfers,0,sizeof(CDCCTransfer)*0x1000);
018 I64 HashFile(U8 *data,I64 len) {
019   I64 res=5381;
020   while (--len>=0)
021     res+=(res<<5)+res+data[len];
022   return res;
023 }
024 U0 FilesTimeoutTask(U8 *dir) {
025   CDirEntry *root,*cur;
026   while(TRUE) {
027     root=FilesFind(dir,FUF_JUST_FILES|FUF_FLATTEN_TREE|FUF_RECURSE);
028     for(cur=root;cur;cur=cur->next) {
029       if(Now>cur->datetime+CDATE_FREQ*(60*60*24)) {
030         DbgPrint("Deleting '%s'\n",cur->full_name);
031         Del(root->full_name);
032       }
033     }
034     DirEntryDel(root);
035     Sleep(10000);
036   }
037 }
038 U8 *DCCSaveFile(U8 *want_name,U8 *data,I64 len) {
039   U8 *ext,*actual;
040   if(!FileFind("T:/HTML/IRC")) {
041     DirMk("T:/HTML");
042     DirMk("T:/HTML/IRC");
043   }
044   if(CDIR_FILENAME_LEN<StrLen(want_name)) {
045     ext=FileExtDot(want_name);
046     if(!ext) ext="";
047     actual=MStrPrint("%X%s",HashFile(data,len),ext);
048     want_name=MStrPrint("T:/HTML/IRC/%s.Z",actual);
049   } else want_name=MStrPrint("T:/HTML/IRC/%s.Z",want_name),actual=StrNew(want_name);
050   FileWrite(want_name,data,len);
051   Free(want_name);
052   return actual;
053 }
054 //Use FramePtr("send_data");
055 U0 DCCSendTask(I64 to_sock) {
056   U8 *data=FramePtr("send_data");
057   I64 flen=FramePtr("send_size"),ptr=0;
058   I64 cnt,written;
059   U32 ass;
060   while(flen-ptr>0) {
061     written=send(to_sock,data+ptr,flen-ptr,0);
062     Sleep(1);
063     if(written<0)
064       break;
065     recv(to_sock,&ass,4,0);
066     written=EndianU32(ass);
067     ptr=written;
068   }
069   Sleep(1000);
070   close(to_sock);
071 }
072 U0 DCCRecvTask(I64 port) {
073   CDCCTransfer *t=&dcc_transfers[port];
074   F64 kill_at=tS+21.;
075   U8 *path;
076   I64 cnt=0,ptr;
077   I64 flen=t->fsz;
078   U8 *data,*file_notice;
079   CFile *f;
080   IrcClient *to_client;
081   path=MStrPrint(DCC_DIR"/%s",t->name);
082   if(!FileFind(DCC_DIR)) DirMk(DCC_DIR);
083 
084   I32 to=EndianU32(NetIP4ByHost(ircd_hostname));
085 DbgPrint("POOPASS:%d\n",to);
086   path=MStrPrint(":%s!%s@0 PRIVMSG %s :\x01DCC SEND %s %d %d %d %d\x01\r\n",
087         t->username,
088         t->username,
089         t->notify_to->nick,
090         t->name,
091         to,
092         port,
093         t->fsz,
094         t->token
095         );
096   GihonFifoIns(
097         t->notify_to->msgs,
098         path
099         );
100 
101 
102   while(TRUE) {
103     if(kill_at<tS) {
104       close(t->accept);
105       LBtr(&t->lock,1);
106       Exit;
107     }
108     t->writer=accept(t->accept,NULL,0);
109     if(t->writer!=-1) 
110       break;
111     else
112       Sleep(10);
113     }
114   U32 poo;
115   data=CAlloc(t->fsz+1);
116   ptr=0;
117   flen=t->fsz;
118   while(flen-ptr>0&&(cnt=recv(t->writer,data+ptr,flen-ptr,0))>0) {
119     ptr+=cnt;
120     poo=EndianU32(ptr); 
121     send(t->writer,&poo,4,0);
122     Sleep(1);
123   }
124 
125   path=DCCSaveFile(t->name,data,t->fsz);
126   file_notice=MStrPrint("File also available at ' %s/IRC/%s ' (Deleted after awhile deleted after 24 hours).",ircd_hostname,path);
127   IrcClientNotice(t->notify_to,file_notice);
128   Free(path);
129 
130   path=MStrPrint(":%s!%s@0 PRIVMSG %s :\x01DCC SEND %s %d %d %d\x01\r\n",
131         t->notify_to->nick,
132         t->notify_to->nick,
133         t->username,
134         t->name,
135         to,
136         port,
137         t->fsz,
138         t->token
139         );
140   close(t->writer);
141   close(t->accept);
142 
143   t->accept=create_server("0.0.0.0",port,21);
144   if(to_client=IrcGetClientByNick(t->username)) {
145     FramePtrAdd("send_data",data);
146     FramePtrAdd("send_size",t->fsz);
147     GihonFifoIns(to_client->msgs,StrNew(path));
148     Free(path);
149 //PRIVMSG the file link to the user 
150     path=MStrPrint(":%s!%s@0 PRIVMSG %s :%s\r\n",
151         t->notify_to->nick,
152         t->notify_to->nick,
153         t->username,
154         file_notice
155         );
156     GihonFifoIns(to_client->msgs,StrNew(path));
157 
158     kill_at=tS+120;
159     while(TRUE) {
160       if(kill_at<tS) {
161         close(t->accept);
162         LBtr(&t->lock,1);
163         Exit;
164       }
165       t->reader=accept(t->accept,NULL,0);
166       if(t->reader!=-1) {
167         Spawn(&DCCSendTask,t->reader,,,Fs);
168       } else
169         Sleep(10);
170       }
171   } else 
172     Free(path); 
173 
174   close(t->accept);
175   Free(data);
176   Free(file_notice);
177   LBtr(&t->lock,1);
178 }
179 Bool DCC_ReverseSendTo(U8 *fn,I64 notify,I64 port=DCC_PORT_START,U8 *to,U8 *fsz,U8 *token) {
180   CDCCTransfer *t=&dcc_transfers[port];
181   LBts(&t->lock,1);
182   I64 writer=-1,reader=-1;
183   I64 sock=create_server("0.0.0.0",port,1);
184   StrCpy(t->name,fn);
185   StrCpy(t->username,to);
186   t->notify_to=notify;
187   t->fsz=Str2I64(fsz);
188   if(token) t->token=Str2I64(token); else t->token=0;
189   t->accept=sock;
190   LBts(&t->lock,1);
191   Spawn(&DCCRecvTask,port,,,Fs);
192   return TRUE;
193 }
194 I64 DCCPickPort() {
195   I64 s=DCC_PORT_START;
196   while(s<DCC_PORT_END) {
197     if(!Bt(&dcc_transfers[s].lock,1))
198       return s;
199     s++;
200   }
201   return -1; //DCC_PORT_END
202 }
203 U0 IrcDCCSend(IrcClient *cl,U8 *to,U8 *fn,U8 *host,U8 *portname,U8 *fsz,U8 *token) {
204   U8 *path;
205   I64 port=Str2I64(portname);
206   I64 sock,len,total;
207   CFile *f;
208   if(!fsz) {
209     IrcClientNotice(to,"Specify a file size");
210     return;
211   }
212   if(!FileFind(DCC_DIR)) DirMk(DCC_DIR);
213   path=MStrPrint(DCC_DIR"/%s",fn);
214      if(Str2I64(fsz)>1000*1000*100)  {
215        IrcClientNotice(to,"Thats a fuckin huge file.");
216        return;
217      }   
218      port=DCCPickPort;
219      if(port!=-1)
220        DCC_ReverseSendTo(fn,cl,port,to,fsz,token);
221   Free(path);
222 }
223 Bool IsDccCommand(IrcClient *cl,U8 *to,U8 *msg) {
224   I64 argc;
225   U8 **argv;
226   Bool ret=FALSE;
227   if(msg[0]==1) {
228     ++msg;
229       if(StrOcc(msg,1)) StrFirstOcc(msg,"\x01")[0]=0;
230       argv=ParseArgs(msg,&argc);
231       if(argc>=6&&!StrCmp(argv[0],"DCC")) {
232         ret=TRUE;
233         if(!StrCmp(argv[1],"SEND")) {
234           if(argc>=6) { //DCC command ip port 
235             DbgPrint("DCC INIT to %s(%s)\n",to,argv[2]);
236             if(argc>=7)
237               IrcDCCSend(cl,to,argv[2],"0","0",argv[5],argv[6]);
238             else
239               IrcDCCSend(cl,to,argv[2],"0","0",argv[5],NULL);
240             ret=TRUE;
241           }
242         }
243       }
244       FreeArgs(argc,argv);
245   }
246   return ret;
247 }
248 Spawn(&FilesTimeoutTask,"T:/HTML/IRC",,,Fs);