5 class ConnectionSocket;
7 define ECOMMUNICATOR_PROTOCOL_VERSION = 1;
9 enum PacketType { Connect = 1, Send, Receive, Message, Name, Data, DataAck };
10 enum Status { Ok, Done, Abort, OutOfSpace };
25 // File Name (dataSize BYTEs)
38 // File Data (dataSize BYTEs)
43 // Message Data (dataSize BYTEs)
45 // Name : Name (dataSize BYTEs)
49 // define DATA_BLOCK_SIZE = 4096;
50 define DATA_BLOCK_SIZE = 65536;
52 class Connection : Window
54 borderStyle = sizable, hasClose = true, hasMinimize = true, showInTaskBar = true, size = Size { 580, 600 },
55 minClientSize = Size { 300, 440 }, tabCycle = true, background = activeBorder;
59 this, text = "Close", size = Size { 80, 0 }, anchor = Anchor { right = 10, bottom = 5 }, hotKey = altC;
60 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
66 Label { this, text = "[=== UPLOAD ===]", position = Point { 10, 10 } };
69 this, textHorzScroll = true, text = "Send File", size.h = 20, anchor = Anchor { left = 10, top = 40, right = 190 };
71 void NotifyUpdate(EditBox editBox)
73 send.disabled = fileSend || !FileExists(sendFile.line.text).isFile;
79 this, text = "Browse", size = Size { 80,20 }, anchor = Anchor { right = 100, top = 40 }, hotKey = altB;
81 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
83 if(fileList.Modal() == ok)
86 sendFile.PutS(fileList.filePath);
93 this, text = "Send", size = Size { 80, 20 }, anchor = Anchor { right = 10, top = 40 }, hotKey = altS, disabled = true;
94 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
96 const char * fileName = sendFile.line.text;
98 fileSend = FileOpen(fileName, read);
101 char outputFile[MAX_FILENAME];
104 GetLastDirectory(fileName, outputFile);
105 size = strlen(outputFile);
106 packet = (eComPacket *)new byte[sizeof(eComPacket) + size];
107 strcpy(sendFileName, outputFile);
111 packet->dataSize = size;
112 FileGetSize(fileName, &packet->send.fileSize);
113 CopyBytes(packet + 1, outputFile, size);
115 socket.Send(packet, sizeof(eComPacket) + packet->dataSize);
117 sendProgress.range = packet->send.fileSize;
118 sendProgress.progress = 0;
124 sending.Printf("Sending %s at", outputFile);
126 send.disabled = fileSend || !FileExists(sendFile.line.text).isFile;
127 sendCancel.disabled = fileSend ? false : true;
132 EditBox sending { this, textHorzScroll = true, readOnly = true, borderStyle = deep, inactive = true, size.h = 20, anchor = Anchor { left = 10, top = 70, right = 190 }, opacity = 0 };
133 Label sendSpeed { this, borderStyle = deep, anchor = Anchor { right = 100, top = 70 }, size = Size { 80, 20 } };
136 this, text = "Cancel", anchor = Anchor { right = 10, top = 70 }, size = Size { 80,20 }, disabled = true;
138 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
141 sendCancel.disabled = true;
145 ProgressBar sendProgress { this, borderStyle = deep, inactive = true, size.h = 20, anchor = Anchor { left = 10, top = 100, right = 10 } };
146 Label { this, text = "[=== DOWNLOAD ===]", position = Point { 10, 140 } };
147 EditBox receiving { this, textHorzScroll = true, readOnly = true, borderStyle = deep, inactive = true, anchor = Anchor { left = 10, top = 170, right = 190 }, size.h = 20, opacity = 0 };
148 Label recvSpeed { this, borderStyle = deep, anchor = Anchor { right = 100, top = 170 }, size = Size { 80, 20 } };
151 this, text = "Cancel", size = Size { 80, 20 }, anchor = Anchor { top = 168, right = 12 }, disabled = true;
153 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
156 recvCancel.disabled = true;
160 ProgressBar recvProgress { this, borderStyle = deep, inactive = true, anchor = Anchor { left = 10, top = 200, right = 10 }, size.h = 20 };
163 this, readOnly = true, multiLine = true, autoEmpty = true, text = "Conversation", inactive = true, size = Size { 560, 226 }, anchor = Anchor { left = 10, top = 270, right = 10, bottom = 100 }, hasHorzScroll = true, hasVertScroll = true
165 Label { this, position = Point { 10, 250 }, labeledWindow = log };
168 this, text = "Clear", anchor = Anchor { left = 10, bottom = 5 }, size = Size { 80, 0 }, hotKey = altR;
170 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
178 this, text = "Background...", anchor = Anchor { bottom = 5 }, size = Size { 100, 0 }, hotKey = altK;
180 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
182 ColorPicker picker { hasClose = true, text = "Select a color/opacity value...", color = background };
184 background = picker.color;
190 this, multiLine = true, text = "Message", size = Size { 0, 50 }, anchor = Anchor { left = 10, right = 10, bottom = 32 }, disabled = true, hasHorzScroll = true, hasVertScroll = true, size.h = 50;
192 bool NotifyKeyDown(EditBox editBox, Key key, unichar ch)
194 if((SmartKey)key == ctrlEnter)
203 for(line = message.firstLine; line; line = line.next)
206 const char * string = line.text;
207 int size = strlen(string);
209 packet = (eComPacket *)new byte[sizeof(eComPacket) + size];
212 packet->type = Message;
213 packet->dataSize = size;
214 packet->msg.over = (line == message.lastLine);
215 CopyBytes(packet + 1, string, size);
217 socket.Send(packet, sizeof(eComPacket) + packet->dataSize);
221 if(line != message.firstLine)
225 log.SetViewToCursor(false);
233 ConnectionSocket socket;
237 borderStyle = sizable, text = "Select a file to send...", size = Size { 300,400 }, master = this
242 char * incomingMessage;
243 unsigned int incomingMsgLen;
249 char sendFileName[MAX_FILENAME];
255 char recvFileName[MAX_FILENAME];
257 char * displayedName;
258 const char * localName;
260 void SendBlock(uint blockSize)
262 eComPacket * packet = (eComPacket *)new byte[sizeof(eComPacket) + blockSize];
263 uint size = abortSend ? 0 : fileSend.Read(packet + 1, 1, blockSize);
267 packet->dataSize = size;
269 packet->data.status = Abort;
271 packet->data.status = (size < blockSize) ? Done : Ok;
273 sendProgress.progress += size;
274 sendTime = GetTime();
275 socket.Send(packet, sizeof(eComPacket) + packet->dataSize);
280 void SendName(const char * name)
282 eComPacket * namePacket = (eComPacket *)new byte[sizeof(eComPacket) + strlen(name)];
286 namePacket->type = Name;
287 namePacket->dataSize = strlen(name);
289 CopyBytes(namePacket + 1, name, namePacket->dataSize);
291 socket.Send(namePacket, sizeof(eComPacket) + namePacket->dataSize);
299 ((MainPanel)master).ConnectionDestroyed(this);
302 socket.connection = null;
303 socket.Disconnect(0);
306 delete incomingMessage;
307 delete displayedName;
314 //eComPacket packet = { Connect, 0, { ECOMMUNICATOR_PROTOCOL_VERSION } };
315 eComPacket packet { Connect, 0, { ECOMMUNICATOR_PROTOCOL_VERSION } };
316 socket.Send(&packet, sizeof(eComPacket));
320 property ConnectionSocket socket { set { socket = value; } }
323 class ConnectionSocket : Socket
325 Connection connection;
328 uint OnReceive(const byte * buffer, uint count)
330 if(count >= sizeof(eComPacket))
332 eComPacket packet = *(eComPacket *) buffer;
333 if(count - sizeof(eComPacket) >= packet.dataSize)
335 byte * data = (byte *)buffer + sizeof(eComPacket);
342 if(packet.connect.version == ECOMMUNICATOR_PROTOCOL_VERSION)
344 char address[256] = "";
345 connection.send.disabled = !FileExists(connection.sendFile.line.text).isFile;
346 connection.message.disabled = false;
347 GetNameFromAddress(inetAddress, address);
348 connection.log.End();
349 connection.log.Printf("* Connected to %s (%s), protocol version %d.", inetAddress, address, packet.connect.version);
357 char fileName[MAX_LOCATION];
358 FileSize resumePosition = 0;
359 char string[MAX_LOCATION + 40];
360 eComPacket recvPacket;
362 CopyBytes(fileName, data, packet.dataSize);
363 fileName[packet.dataSize] = '\0';
365 if(FileExists(fileName))
367 FileGetSize(fileName, &resumePosition);
369 recvPacket.type = Receive;
370 recvPacket.dataSize = 0;
371 recvPacket.recv.position = resumePosition;
373 strcpy(connection.recvFileName, fileName);
374 connection.fileRecv = FileOpen(fileName, append);
375 connection.recvCancel.disabled = connection.fileRecv ? false : true;
377 connection.receiving.Clear();
378 connection.receiving.Printf("Receiving %s at", fileName);
380 connection.recvProgress.range = packet.send.fileSize;
381 connection.recvProgress.progress = resumePosition;
383 connection.log.End();
386 PrintSize(string, resumePosition, 2);
387 connection.log.Printf("\n* Resuming download of %s from %s", connection.recvFileName, string);
390 connection.log.Printf("\n* Downloading %s", connection.recvFileName);
392 connection.abortRecv = false;
394 connection.recvTime = GetTime();
395 Send(&recvPacket, sizeof(eComPacket));
401 connection.fileSend.Seek(packet.recv.position, start);
402 connection.SendBlock(DATA_BLOCK_SIZE);
403 connection.log.End();
404 if(packet.recv.position)
406 PrintSize(string, packet.recv.position, 2);
407 connection.log.Printf("\n* Resuming upload of %s from %s", connection.sendFileName, string);
410 connection.log.Printf("\n* Uploading %s", connection.sendFileName);
411 connection.sendProgress.progress = packet.recv.position;
416 if(connection.incomingMsgLen)
417 connection.incomingMessage[connection.incomingMsgLen++] = '\n';
418 connection.incomingMessage = renew connection.incomingMessage char[connection.incomingMsgLen + packet.dataSize + 1];
419 CopyBytes(connection.incomingMessage + connection.incomingMsgLen, data, packet.dataSize);
420 connection.incomingMessage[connection.incomingMsgLen + packet.dataSize] = '\0';
422 connection.incomingMsgLen += packet.dataSize;
426 connection.log.End();
427 connection.log.AddS("\n<");
428 connection.log.AddS(connection.displayedName);
429 connection.log.AddS("> ");
430 connection.log.AddS(connection.incomingMessage);
431 connection.log.SetViewToCursor(false);
432 delete connection.incomingMessage;
433 connection.incomingMessage = null;
434 connection.incomingMsgLen = 0;
440 char address[256] = "", title[256];
442 delete connection.displayedName;
443 connection.displayedName = new char[packet.dataSize + 1];
444 CopyBytes(connection.displayedName, data, packet.dataSize);
445 connection.displayedName[packet.dataSize] = '\0';
447 GetNameFromAddress(inetAddress, address);
448 sprintf(title, service ? "%s [<-%s]" : "%s [->%s]", connection.displayedName, address);
450 connection.text = title;
455 eComPacket ackPacket { DataAck };
458 if(connection.abortRecv)
459 ackPacket.data.status = Abort;
460 else if(packet.dataSize)
462 if(!connection.fileRecv.Write(data, packet.dataSize, 1))
463 ackPacket.data.status = OutOfSpace;
465 else if(packet.data.status)
466 ackPacket.data.status = packet.data.status;
468 connection.recvProgress.progress += packet.dataSize;
470 diffTime = GetTime() - connection.recvTime;
474 PrintSize(string, (int)(packet.dataSize / diffTime), 1);
475 strcat(string, "/s");
476 connection.recvSpeed.text = string;
479 if(ackPacket.data.status)
481 connection.log.End();
482 switch(ackPacket.data.status)
485 connection.log.Printf("\n* %s received successfully.", connection.recvFileName);
488 connection.log.Printf("\n* Download of %s cancelled.", connection.recvFileName);
491 connection.log.Printf("\n* Out of disk space receiving %s.", connection.recvFileName);
494 connection.receiving.Clear();
495 connection.recvSpeed.text = "";
496 delete connection.fileRecv;
497 connection.recvProgress.range = 0;
500 connection.recvCancel.disabled = connection.fileRecv ? false : true;
501 connection.recvTime = GetTime();
502 Send(&ackPacket, sizeof(eComPacket));
508 if(packet.ack.status)
510 connection.log.End();
511 switch(packet.ack.status)
514 connection.log.Printf("\n* %s uploaded successfully.", connection.sendFileName);
517 connection.log.Printf("\n* Upload of %s cancelled.", connection.sendFileName);
520 connection.log.Printf("\n* Remote ran out of disk space receiving %s.", connection.sendFileName);
524 connection.sendProgress.range = 0;
525 delete connection.fileSend;
527 connection.sending.Clear();
528 connection.sendSpeed.text = "";
530 connection.send.disabled = connection.fileSend || !FileExists(connection.sendFile.line.text).isFile;
531 connection.sendCancel.disabled = connection.fileSend ? false : true;
535 diffTime = GetTime() - connection.sendTime;
539 PrintSize(string, (int)(DATA_BLOCK_SIZE / diffTime), 1);
540 strcat(string, "/s");
541 connection.sendSpeed.text = string;
543 connection.SendBlock(DATA_BLOCK_SIZE);
549 return sizeof(eComPacket) + packet.dataSize;
557 char address[256] = "";
559 GetNameFromAddress(inetAddress, address);
561 connection = Connection { text = "Connecting...", socket = this, master = mainPanel };
563 mainPanel.OnConnect(connection, inetAddress, address);
566 void OnDisconnect(int code)
570 connection.socket = null;
571 connection.Destroy(0);
576 property MainPanel mainPanel { set { mainPanel = value; } }
577 property Connection connection { set { connection = value; } }