]> icculus.org git repositories - taylor/freespace2.git/blob - src/network/multi_xfer.cpp
a few NDEBUG updates.
[taylor/freespace2.git] / src / network / multi_xfer.cpp
1 /*
2  * $Logfile: /Freespace2/code/Network/multi_xfer.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * $Log$
8  * Revision 1.4  2002/06/01 07:12:33  relnev
9  * a few NDEBUG updates.
10  *
11  * removed a few warnings.
12  *
13  * Revision 1.3  2002/05/26 20:22:48  theoddone33
14  * Most of network/ works
15  *
16  * Revision 1.2  2002/05/07 03:16:47  theoddone33
17  * The Great Newline Fix
18  *
19  * Revision 1.1.1.1  2002/05/03 03:28:10  root
20  * Initial import.
21  *
22  * 
23  * 11    3/10/99 6:50p Dave
24  * Changed the way we buffer packets for all clients. Optimized turret
25  * fired packets. Did some weapon firing optimizations.
26  * 
27  * 10    3/09/99 6:24p Dave
28  * More work on object update revamping. Identified several sources of
29  * unnecessary bandwidth.
30  * 
31  * 9     1/24/99 11:37p Dave
32  * First full rev of beam weapons. Very customizable. Removed some bogus
33  * Int3()'s in low level net code.
34  * 
35  * 8     12/16/98 11:17a Dave
36  * Fixed potential situation where a send and receive to the same player
37  * with the same sig might get confused with each other.
38  * 
39  * 7     12/14/98 4:01p Dave
40  * Got multi_data stuff working well with new xfer stuff. 
41  * 
42  * 6     12/14/98 12:13p Dave
43  * Spiffed up xfer system a bit. Put in support for squad logo file xfer.
44  * Need to test now.
45  * 
46  * 5     11/19/98 8:03a Dave
47  * Full support for D3-style reliable sockets. Revamped packet lag/loss
48  * system, made it receiver side and at the lowest possible level.
49  * 
50  * 4     11/17/98 11:12a Dave
51  * Removed player identification by address. Now assign explicit id #'s.
52  * 
53  * 3     11/05/98 5:55p Dave
54  * Big pass at reducing #includes
55  * 
56  * 2     10/07/98 10:53a Dave
57  * Initial checkin.
58  * 
59  * 1     10/07/98 10:50a Dave
60  * 
61  * 56    9/11/98 9:31a Dave
62  * Fixed file xfer bug regarding checksums.
63  * 
64  * 55    8/12/98 4:53p Dave
65  * Put in 32 bit checksumming for PXO missions. No validation on the
66  * actual tracker yet, though.
67  * 
68  * 54    6/13/98 9:32p Mike
69  * Kill last character in file which caused "Find in Files" to report the
70  * file as "not a text file."
71  * 
72  * 53    6/13/98 6:01p Hoffoss
73  * Externalized all new (or forgot to be added) strings to all the code.
74  * 
75  * 52    6/13/98 3:19p Hoffoss
76  * NOX()ed out a bunch of strings that shouldn't be translated.
77  * 
78  * 51    5/21/98 1:52a Dave
79  * Remove obsolete command line functions. Reduce shield explosion packets
80  * drastically. Tweak PXO screen even more. Fix file xfer system so that
81  * we can guarantee file uniqueness.
82  * 
83  * 50    4/30/98 4:53p John
84  * Restructured and cleaned up cfile code.  Added capability to read off
85  * of CD-ROM drive and out of multiple pack files.
86  * 
87  * 49    4/23/98 6:18p Dave
88  * Store ETS values between respawns. Put kick feature in the text
89  * messaging system. Fixed text messaging system so that it doesn't
90  * process or trigger ship controls. Other UI fixes.
91  * 
92  * 48    4/22/98 5:53p Dave
93  * Large reworking of endgame sequencing. Updated multi host options
94  * screen for new artwork. Put in checks for host or team captains leaving
95  * midgame.
96  * 
97  * 47    4/21/98 4:44p Dave
98  * Implement Vasudan ships in multiplayer. Added a debug function to bash
99  * player rank. Fixed a few rtvoice buffer overrun problems. Fixed ui
100  * problem in options screen. 
101  * 
102  * 46    4/20/98 6:04p Dave
103  * Implement multidata cache flushing and xferring mission files to
104  * multidata. Make sure observers can't change hud config. Fix pilot image
105  * viewing in popup. Put in game status field. Tweaked multi options. 
106  * 
107  * 45    4/08/98 2:51p Dave
108  * Fixed pilot image xfer once again. Solidify team selection process in
109  * pre-briefing multiplayer.
110  * 
111  * 44    4/04/98 4:22p Dave
112  * First rev of UDP reliable sockets is done. Seems to work well if not
113  * overly burdened.
114  * 
115  * 43    4/03/98 1:03a Dave
116  * First pass at unreliable guaranteed delivery packets.
117  * 
118  * 42    4/01/98 11:19p Dave
119  * Put in auto-loading of xferred pilot pic files. Grey out background
120  * behind pinfo popup. Put a chatbox message in when players are kicked.
121  * Moved mission title down in briefing. Other ui fixes.
122  * 
123  * 41    3/31/98 4:51p Dave
124  * Removed medals screen and multiplayer buttons from demo version. Put in
125  * new pilot popup screen. Make ships in mp team vs. team have proper team
126  * ids. Make mp respawns a permanent option saved in the player file.
127  * 
128  * 40    3/30/98 8:46a Allender
129  * fix an optimized build compiler warning
130  * 
131  * 39    3/26/98 6:01p Dave
132  * Put in file checksumming routine in cfile. Made pilot pic xferring more
133  * robust. Cut header size of voice data packets in half. Put in
134  * restricted game host query system.
135  * 
136  * 38    3/25/98 2:16p Dave
137  * Select random default image for newly created pilots. Fixed several
138  * multi-pause messaging bugs. Begin work on online help for multiplayer
139  * keys.
140  * 
141  * 37    3/24/98 5:00p Dave
142  * Fixed several ui bugs. Put in pre and post voice stream playback sound
143  * fx. Put in error specific popups for clients getting dropped from games
144  * through actions other than their own.
145  * 
146  * 36    3/23/98 5:42p Dave
147  * Put in automatic xfer of pilot pic files. Changed multi_xfer system so
148  * that it can support multiplayer sends/received between client and
149  * server simultaneously.
150  * 
151  * 35    3/21/98 7:14p Dave
152  * Fixed up standalone player slot switching. Made training missions not
153  * count towards player stats.
154  * 
155  * 34    3/16/98 11:52p Allender
156  * Put in timestamp updates when processing data on both sender and
157  * receiver sides.
158  * 
159  * 33    2/22/98 2:53p Dave
160  * Put in groundwork for advanced multiplayer campaign  options.
161  * 
162  * 32    2/20/98 4:43p Dave
163  * Finished support for multiplayer player data files. Split off
164  * multiplayer campaign functionality.
165  * 
166  * 31    2/19/98 6:26p Dave
167  * Fixed a few file xfer bugs. Tweaked mp team select screen. Put in
168  * initial support for player data uploading.
169  * 
170  * 30    2/18/98 10:21p Dave
171  * Ripped out old file xfer system. Put in brand new xfer system.
172  * 
173  * $NoKeywords: $
174  */
175
176 #ifndef PLAT_UNIX
177 #include <winsock.h>
178 #include <io.h>
179 #endif
180 #include "multi_xfer.h"
181 #include "cfile.h"
182 #include "multimsgs.h"
183 #include "psnet.h"
184 #include "popup.h"
185 #include "multi_endgame.h"
186 #include "timer.h"
187 #include "multi.h"
188 #include "multiutil.h"
189 #include "multi_log.h"
190
191 // ------------------------------------------------------------------------------------------
192 // MULTI XFER DEFINES/VARS
193 //
194
195 #define MULTI_XFER_VERBOSE                                                                              // keep this defined for verbose debug output
196
197 #define MULTI_XFER_INVALID_HANDLE(handle) ( (handle < 0) || (handle > (MAX_XFER_ENTRIES-1)) || !(Multi_xfer_entry[handle].flags & MULTI_XFER_FLAG_USED) || (strlen(Multi_xfer_entry[handle].filename) <= 0) )
198
199 // packet codes
200 #define MULTI_XFER_CODE_ACK                                     0                               // simple response to the last request
201 #define MULTI_XFER_CODE_NAK                                     1                               // simple response to the last request
202 #define MULTI_XFER_CODE_HEADER                          2                               // file xfer header information follows, requires a HEADER_RESPONSE
203 #define MULTI_XFER_CODE_DATA                                    3                               // data block follows, requires an ack
204 #define MULTI_XFER_CODE_FINAL                                   4                               // indication from sender that xfer is complete, requires an ack
205
206 // entry flags
207 #define MULTI_XFER_FLAG_USED                                    (1<<0)          // this entry is in use 
208 #define MULTI_XFER_FLAG_SEND                                    (1<<1)          // this entry is sending a file
209 #define MULTI_XFER_FLAG_RECV                                    (1<<2)          // this entry is receiving a file
210 #define MULTI_XFER_FLAG_PENDING                         (1<<3)          // this entry is ready to send a header and start the process
211 #define MULTI_XFER_FLAG_WAIT_ACK                                (1<<4)          // waiting for an ack/nak
212 #define MULTI_XFER_FLAG_WAIT_DATA                       (1<<5)          // waiting for another block of data 
213 #define MULTI_XFER_FLAG_UNKNOWN                         (1<<6)          // xfer final has been sent, and we are waiting for a response
214 #define MULTI_XFER_FLAG_SUCCESS                         (1<<7)          // finished xfer
215 #define MULTI_XFER_FLAG_FAIL                                    (1<<8)          // xfer failed
216 #define MULTI_XFER_FLAG_TIMEOUT                         (1<<9)          // xfer has timed-out
217 #define MULTI_XFER_FLAG_QUEUE_CURRENT           (1<<10)         // for a set of XFER_FLAG_QUEUE'd files, this is the current one sending
218
219 // packet size for file xfer
220 #define MULTI_XFER_MAX_DATA_SIZE                                490                     // this will keep us within the MULTI_XFER_MAX_SIZE_LIMIT
221
222 // timeout for a given xfer operation
223 #define MULTI_XFER_TIMEOUT                                              10000           
224
225 //XSTR:OFF
226
227 // temp filename header for xferring files
228 #define MULTI_XFER_FNAME_PREFIX                         "_fsx_"
229
230 //XSTR:ON
231
232 // xfer entries/events
233 #define MAX_XFER_ENTRIES                                                60                              // the max allowed file xfer entries
234 typedef struct xfer_entry {
235         int flags;                                                                                                              // status flags for this entry
236         char filename[MAX_FILENAME_LEN+1];                                              // filename of the currently xferring file
237         char ex_filename[MAX_FILENAME_LEN+10];                                  // filename with xfer prefix tacked on to the front
238         CFILE *file;                                                                                                    // file handle of the current xferring file
239         int file_size;                                                                                                  // total size of the file being xferred
240         int file_ptr;                                                                                                   // total bytes we're received so far
241         ushort file_chksum;                                                                                     // used for checking successfully xferred files
242         PSNET_SOCKET_RELIABLE file_socket;                                              // socket used to xfer the file 
243         int xfer_stamp;                                                                                         // timestamp for the current operation          
244         int force_dir;                                                                                                  // force the file to go to this directory on receive (will override Multi_xfer_force_dir)       
245         ushort sig;                                                                                                             // identifying sig - sender specifies this
246 } xfer_entry;
247 xfer_entry Multi_xfer_entry[MAX_XFER_ENTRIES];                  // the file xfer entries themselves
248
249 // callback function pointer for when we start receiving a file
250 void (*Multi_xfer_recv_notify)(int handle);
251
252 // lock for the xfer system
253 int Multi_xfer_locked;
254
255 // force directory type for receives
256 int Multi_xfer_force_dir; 
257
258 // unique file signature - this along with a socket # is enough to identify all xfers
259 ushort Multi_xfer_sig = 0;
260
261
262 // ------------------------------------------------------------------------------------------
263 // MULTI XFER FORWARD DECLARATIONS
264 //
265
266 // evaluate the condition of the entry
267 void multi_xfer_eval_entry(xfer_entry *xe);
268
269 // set an entry to be "failed"
270 void multi_xfer_fail_entry(xfer_entry *xe);
271
272 // get a valid xfer entry handle
273 int multi_xfer_get_free_handle();
274
275 // process an ack for this entry
276 void multi_xfer_process_ack(xfer_entry *xe);
277
278 // process a nak for this entry
279 void multi_xfer_process_nak(xfer_entry *xe);
280                 
281 // process a "final" packet     
282 void multi_xfer_process_final(xfer_entry *xe);          
283
284 // process a data packet
285 void multi_xfer_process_data(xfer_entry *xe, ubyte *data, int data_size);
286         
287 // process a header
288 void multi_xfer_process_header(ubyte *data, PSNET_SOCKET_RELIABLE who, ushort sig, char *filename, int file_size, ushort file_checksum);                
289
290 // send the next block of outgoing data or a "final" packet if we're done
291 void multi_xfer_send_next(xfer_entry *xe);
292
293 // send an ack to the sender
294 void multi_xfer_send_ack(PSNET_SOCKET_RELIABLE socket, ushort sig);
295
296 // send a nak to the sender
297 void multi_xfer_send_nak(PSNET_SOCKET_RELIABLE socket, ushort sig);
298
299 // send a "final" packet
300 void multi_xfer_send_final(xfer_entry *xe);
301
302 // send the header to begin a file transfer
303 void multi_xfer_send_header(xfer_entry *xe);
304
305 // convert the filename into the prefixed ex_filename
306 void multi_xfer_conv_prefix(char *filename, char *ex_filename);
307
308 // get a new xfer sig
309 ushort multi_xfer_get_sig();
310
311 // ------------------------------------------------------------------------------------------
312 // MULTI XFER FUNCTIONS
313 //
314
315 // initialize all file xfer transaction stuff, call in multi_level_init()
316 void multi_xfer_init(void (*multi_xfer_recv_callback)(int handle))
317 {
318         // blast all the entries
319         memset(Multi_xfer_entry,0,sizeof(xfer_entry) * MAX_XFER_ENTRIES);
320
321         // assign the receive callback function pointer
322         Multi_xfer_recv_notify = multi_xfer_recv_callback;
323
324         // unlocked
325         Multi_xfer_locked = 0;
326
327         // no forced directory
328         Multi_xfer_force_dir = CF_TYPE_MULTI_CACHE;     
329 }
330
331 // do frame for all file xfers, call in multi_do_frame()
332 void multi_xfer_do()
333 {
334         int idx;
335
336         // process all valid xfer entries
337         for(idx=0;idx<MAX_XFER_ENTRIES;idx++){
338                 // if this one is actually in use and has not finished for one reason or another
339                 if((Multi_xfer_entry[idx].flags & MULTI_XFER_FLAG_USED) && !(Multi_xfer_entry[idx].flags & (MULTI_XFER_FLAG_SUCCESS | MULTI_XFER_FLAG_FAIL | MULTI_XFER_FLAG_TIMEOUT))){
340                         // evaluate the condition of this entry (fail, timeout, etc)
341                         multi_xfer_eval_entry(&Multi_xfer_entry[idx]);                  
342                 }
343         }
344 }
345
346 // close down the file xfer system
347 void multi_xfer_close()
348 {
349         int idx;
350
351         // go through all active entries and abort them
352         for(idx=0;idx<MAX_XFER_ENTRIES;idx++){
353                 if(Multi_xfer_entry[idx].flags & MULTI_XFER_FLAG_USED){
354                         multi_xfer_abort(idx);
355                 }
356         }
357
358         // now blast all the memory free
359         memset(Multi_xfer_entry,0,sizeof(xfer_entry) * MAX_XFER_ENTRIES);
360 }
361
362 // reset the xfer system, including shutting down/killing all active xfers
363 void multi_xfer_reset()
364 {
365         int idx;
366
367         // shut down all active xfers
368         for(idx=0;idx<MAX_XFER_ENTRIES;idx++){
369                 if(Multi_xfer_entry[idx].flags & MULTI_XFER_FLAG_USED){
370                         multi_xfer_abort(idx);
371                 }
372         }
373
374         // blast all the memory clean
375         memset(Multi_xfer_entry,0,sizeof(xfer_entry) * MAX_XFER_ENTRIES);
376 }
377
378 // send a file to the specified player, return a handle
379 int multi_xfer_send_file(PSNET_SOCKET_RELIABLE who, char *filename, int cfile_flags, int flags)
380 {
381         xfer_entry temp_entry;  
382         int handle;
383
384         // if the system is locked, return -1
385         if(Multi_xfer_locked){
386                 return -1;
387         }
388
389         // attempt to get a free handle
390         handle = multi_xfer_get_free_handle();
391         if(handle == -1){
392                 return -1;
393         }
394
395         // clear the temp entry
396         memset(&temp_entry,0,sizeof(xfer_entry));
397
398         // set the filename
399         strcpy(temp_entry.filename,filename);   
400
401         // attempt to open the file
402         temp_entry.file = NULL;
403         temp_entry.file = cfopen(filename,"rb",CFILE_NORMAL,cfile_flags);
404         if(temp_entry.file == NULL){
405 #ifdef MULTI_XFER_VERBOSE
406                 nprintf(("Network","MULTI XFER : Could not open file %s on xfer send!\n",filename));
407 #endif
408
409                 return -1;
410         }
411
412         // set the file size
413         temp_entry.file_size = -1;
414         temp_entry.file_size = cfilelength(temp_entry.file);
415         if(temp_entry.file_size == -1){
416 #ifdef MULTI_XFER_VERBOSE
417                 nprintf(("Network","MULTI XFER : Could not get file length for file %s on xfer send\n",filename));
418 #endif
419                 return -1;
420         }
421         temp_entry.file_ptr = 0;
422
423         // get the file checksum
424         if(!cf_chksum_short(temp_entry.file,&temp_entry.file_chksum)){
425 #ifdef MULTI_XFER_VERBOSE
426                 nprintf(("Network","MULTI XFER : Could not get file checksum for file %s on xfer send\n",filename));
427 #endif
428                 return -1;
429         } 
430 #ifdef MULTI_XFER_VERBOSE
431         nprintf(("Network","MULTI XFER : Got file %s checksum of %d\n",temp_entry.filename,(int)temp_entry.file_chksum));
432 #endif
433         // rewind the file pointer to the beginning of the file
434         cfseek(temp_entry.file,0,CF_SEEK_SET);
435
436         // set the flags
437         temp_entry.flags |= (MULTI_XFER_FLAG_USED | MULTI_XFER_FLAG_SEND | MULTI_XFER_FLAG_PENDING);
438         temp_entry.flags |= flags;
439
440         // set the socket       
441         temp_entry.file_socket = who;           
442
443         // set the signature
444         temp_entry.sig = multi_xfer_get_sig();
445
446         // copy to the global array
447         memset(&Multi_xfer_entry[handle],0,sizeof(xfer_entry));
448         memcpy(&Multi_xfer_entry[handle],&temp_entry,sizeof(xfer_entry));
449         
450         return handle;
451 }
452
453 // get the status of the current file xfer
454 int multi_xfer_get_status(int handle)
455 {
456         // if this is an invalid or an unused handle, notify as such
457         if((handle < 0) || (handle > (MAX_XFER_ENTRIES-1)) || !(Multi_xfer_entry[handle].flags & MULTI_XFER_FLAG_USED) ){
458                 return MULTI_XFER_NONE;
459         }       
460         
461         // if the xfer has timed-out
462         if(Multi_xfer_entry[handle].flags & MULTI_XFER_FLAG_TIMEOUT){
463                 return MULTI_XFER_TIMEDOUT;
464         }
465
466         // if the xfer has failed for one reason or another (not timeout)
467         if(Multi_xfer_entry[handle].flags & MULTI_XFER_FLAG_FAIL){
468                 return MULTI_XFER_FAIL;
469         }
470
471         // if the xfer has succeeded
472         if(Multi_xfer_entry[handle].flags & MULTI_XFER_FLAG_SUCCESS){
473                 return MULTI_XFER_SUCCESS;
474         }
475
476         // if the xfer is queued
477         if((Multi_xfer_entry[handle].flags & MULTI_XFER_FLAG_QUEUE) && !(Multi_xfer_entry[handle].flags & MULTI_XFER_FLAG_QUEUE_CURRENT)){
478                 return MULTI_XFER_QUEUED;
479         }
480
481         // otherwise the xfer is still in progress
482         return MULTI_XFER_IN_PROGRESS;
483 }
484
485 // abort a transferring file
486 void multi_xfer_abort(int handle)
487 {
488         xfer_entry *xe;
489
490         // don't do anything if this is an invalid handle
491         if(MULTI_XFER_INVALID_HANDLE(handle)){
492                 return;
493         }
494
495         // get e handle to the entry
496         xe = &Multi_xfer_entry[handle];
497
498         // close any open file and delete it 
499         if(xe->file != NULL){
500                 cfclose(xe->file);
501                 xe->file = NULL;
502
503                 // delete it if there isn't some problem with the filename
504                 if((xe->flags & MULTI_XFER_FLAG_RECV) && (strlen(xe->filename) > 0)){
505                         cf_delete(xe->ex_filename, xe->force_dir);
506                 }
507         }
508
509         // zero the socket
510         xe->file_socket = INVALID_SOCKET;
511
512         // blast the entry
513         memset(xe,0,sizeof(xfer_entry));
514 }
515
516 // release an xfer handle
517 void multi_xfer_release_handle(int handle)
518 {
519         xfer_entry *xe;
520
521         // don't do anything if this is an invalid handle
522         if(MULTI_XFER_INVALID_HANDLE(handle)){
523                 return;
524         }
525
526         // get e handle to the entry
527         xe = &Multi_xfer_entry[handle];
528
529         // close any open file and delete it 
530         if(xe->file != NULL){
531                 cfclose(xe->file);
532                 xe->file = NULL;
533
534                 // delete it if the file was not successfully received
535                 if(!(xe->flags & MULTI_XFER_FLAG_SUCCESS) && (xe->flags & MULTI_XFER_FLAG_RECV) && (strlen(xe->filename) > 0)){
536                         cf_delete(xe->ex_filename,xe->force_dir);
537                 }
538         }
539
540         // zero the socket
541         xe->file_socket = INVALID_SOCKET;       
542
543         // blast the entry
544         memset(xe,0,sizeof(xfer_entry));
545 }
546
547 // get the filename of the xfer for the given handle
548 char *multi_xfer_get_filename(int handle)
549 {
550         // if this is an invalid handle, return NULL
551         if(MULTI_XFER_INVALID_HANDLE(handle)){
552                 return NULL;
553         }
554
555         // otherwise return the string
556         return Multi_xfer_entry[handle].filename;
557 }
558
559 // lock the xfer system (don't accept incoming files, don't allow outgoing files)
560 void multi_xfer_lock()
561 {
562         Multi_xfer_locked = 1;
563 }
564
565 // unlock the xfer system
566 void multi_xfer_unlock()
567 {
568         Multi_xfer_locked = 0;
569 }
570
571 // force all receives to go into the specified directory by cfile type
572 void multi_xfer_force_dir(int cf_type)
573 {
574         Multi_xfer_force_dir = cf_type;
575         Assert(Multi_xfer_force_dir > CF_TYPE_ANY);
576 }
577
578 // forces the given xfer entry to the specified directory type (only valid when called from the recv_callback function)
579 void multi_xfer_handle_force_dir(int handle,int cf_type)
580 {
581         // if this is an invalid handle, return NULL
582         if(MULTI_XFER_INVALID_HANDLE(handle)){
583                 return;
584         }
585
586         // force to go to the given directory
587         Multi_xfer_entry[handle].force_dir = cf_type;
588         Assert(Multi_xfer_entry[handle].force_dir > CF_TYPE_ANY);
589 }
590
591 // or the flag on a given entry
592 void multi_xfer_xor_flags(int handle,int flags)
593 {
594         // if this is an invalid handle, return NULL
595         if(MULTI_XFER_INVALID_HANDLE(handle)){
596                 return;
597         }
598
599         // xor the flags
600         Multi_xfer_entry[handle].flags ^= flags;
601 }
602
603 // get the flags for a given entry
604 int multi_xfer_get_flags(int handle)
605 {
606         // if this is an invalid handle, return NULL
607         if(MULTI_XFER_INVALID_HANDLE(handle)){
608                 return -1;
609         }
610
611         // return the flags
612         return Multi_xfer_entry[handle].flags;
613 }
614
615 // if the passed filename is being xferred, return the xfer handle, otherwise return -1
616 int multi_xfer_lookup(char *filename)
617 {
618         int idx;
619
620         // if we have an invalid filename, do nothing
621         if((filename == NULL) || (strlen(filename) <= 0)){
622                 return 0;
623         }
624
625         // otherwise, perform a lookup
626         for(idx=0;idx<MAX_XFER_ENTRIES;idx++){
627                 // if we found a matching filename
628                 if((Multi_xfer_entry[idx].flags & MULTI_XFER_FLAG_USED) && !stricmp(filename,Multi_xfer_entry[idx].filename)){
629                         return idx;
630                 }
631         }
632
633         // did not find a match
634         return -1;
635 }
636
637 // get the % of completion of the passed file handle, return < 0 if invalid
638 float multi_xfer_pct_complete(int handle)
639 {
640         // if this is an invalid handle, return invalid
641         if(MULTI_XFER_INVALID_HANDLE(handle)){
642                 return -1.0f;
643         }
644
645         // if the file size is 0, return invalid
646         if(Multi_xfer_entry[handle].file_size == 0){
647                 return -1.0f;
648         }
649
650         // return the pct completion
651         return (float)Multi_xfer_entry[handle].file_ptr / (float)Multi_xfer_entry[handle].file_size;
652 }
653
654 // get the socket of the file xfer (useful for identifying players)
655 uint multi_xfer_get_sock(int handle)
656 {
657         // if this is an invalid handle, return NULL
658         if(MULTI_XFER_INVALID_HANDLE(handle)){
659                 return INVALID_SOCKET;
660         }
661
662         return Multi_xfer_entry[handle].file_socket;
663 }
664
665 // get the CF_TYPE of the directory this file is going to
666 int multi_xfer_get_force_dir(int handle)
667 {
668         // if this is an invalid handle, return NULL
669         if(MULTI_XFER_INVALID_HANDLE(handle)){
670                 return INVALID_SOCKET;
671         }
672
673         return Multi_xfer_entry[handle].force_dir;
674 }
675
676
677 // ------------------------------------------------------------------------------------------
678 // MULTI XFER FORWARD DECLARATIONS
679 //
680
681 // evaluate the condition of the entry
682 void multi_xfer_eval_entry(xfer_entry *xe)
683 {       
684         int idx;
685         int found;
686         xfer_entry *xe_c;
687
688         // if the entry is marked as successful, then don't do anything
689         if(xe->flags & MULTI_XFER_FLAG_SUCCESS){
690                 return;
691         }
692
693         // if the entry is queued
694         if(xe->flags & MULTI_XFER_FLAG_QUEUE){
695                 // if the entry is not current
696                 if(!(xe->flags & MULTI_XFER_FLAG_QUEUE_CURRENT)){
697                         // see if there are any other queued up xfers to this target. if not, make me current and start sending
698                         found = 0;
699                         for(idx=0; idx<MAX_XFER_ENTRIES; idx++){
700                                 xe_c = &Multi_xfer_entry[idx];
701
702                                 // if this is a valid entry and is a queued entry and is going to the same target
703                                 if((xe_c->flags & MULTI_XFER_FLAG_USED) && (xe_c->file_socket == xe->file_socket) && (xe_c->flags & MULTI_XFER_FLAG_SEND) && 
704                                         (xe_c->flags & MULTI_XFER_FLAG_QUEUE) && (xe_c->flags & MULTI_XFER_FLAG_QUEUE_CURRENT)){
705                                         
706                                         found = 1;
707                                         break;
708                                 }                               
709                         }
710
711                         // if we found no other entries, make this guy current and pending
712                         if(!found){
713                                 xe->flags |= MULTI_XFER_FLAG_QUEUE_CURRENT;
714                                 xe->flags |= MULTI_XFER_FLAG_PENDING;
715
716 #ifdef MULTI_XFER_VERBOSE
717                                 nprintf(("Network","MULTI_XFER : Starting xfer send for queued entry %s\n", xe->filename));
718 #endif
719                         } 
720                         // otherwise, do nothing for him - he has to still wait
721                         else {
722                                 return;
723                         }
724                 }
725         }
726
727         // if the entry is marked as pending - send out the header to get the ball rolling
728         if(xe->flags & MULTI_XFER_FLAG_PENDING){                
729                 // send the header to begin the transfer
730                 multi_xfer_send_header(xe);
731
732                 // set the timestamp
733                 xe->xfer_stamp = timestamp(MULTI_XFER_TIMEOUT); 
734
735                 // unset the pending flag
736                 xe->flags &= ~(MULTI_XFER_FLAG_PENDING);
737
738                 // set the ack/wait flag
739                 xe->flags |= MULTI_XFER_FLAG_WAIT_ACK;
740         }
741         
742         // see if the entry has timed-out for one reason or another
743         if((xe->xfer_stamp != -1) && timestamp_elapsed(xe->xfer_stamp)){
744                 xe->flags |= MULTI_XFER_FLAG_TIMEOUT;                   
745
746                 // if we should be auto-destroying this entry, do so
747                 if(xe->flags & MULTI_XFER_FLAG_AUTODESTROY){
748                         multi_xfer_fail_entry(xe);                      
749                 }
750         }               
751 }
752
753 // lookup a file xfer entry by player
754 xfer_entry *multi_xfer_find_entry(PSNET_SOCKET_RELIABLE who, ushort sig, int sender_side)
755 {
756         int idx;
757
758         // look through all valid xfer entries
759         for(idx=0;idx<MAX_XFER_ENTRIES;idx++){
760                 // if we're looking for sending entries
761                 if(sender_side && !(Multi_xfer_entry[idx].flags & MULTI_XFER_FLAG_SEND)){
762                         continue;
763                 }
764                 // if we're looking for recv entries
765                 if(!sender_side && !(Multi_xfer_entry[idx].flags & MULTI_XFER_FLAG_RECV)){
766                         continue;
767                 }
768
769                 // if we found a match
770                 if((Multi_xfer_entry[idx].file_socket == who) && (Multi_xfer_entry[idx].sig == sig)){
771                         return &Multi_xfer_entry[idx];
772                 }
773         }
774
775         return NULL;
776 }
777
778 // set an entry to be "failed"
779 void multi_xfer_fail_entry(xfer_entry *xe)
780 {
781         // set its flags appropriately
782         xe->flags &= ~(MULTI_XFER_FLAG_WAIT_ACK | MULTI_XFER_FLAG_WAIT_DATA | MULTI_XFER_FLAG_UNKNOWN);
783         xe->flags |= MULTI_XFER_FLAG_FAIL;
784
785         // close the file pointer
786         if(xe->file != NULL){
787                 cfclose(xe->file);
788                 xe->file = NULL;
789         }
790
791         // delete the file
792         if((xe->flags & MULTI_XFER_FLAG_RECV) && (strlen(xe->filename) > 0)){
793                 cf_delete(xe->ex_filename,xe->force_dir);
794         }
795                 
796         // null the timestamp
797         xe->xfer_stamp = -1;
798
799         // if we should be auto-destroying this entry, do so
800         if(xe->flags & MULTI_XFER_FLAG_AUTODESTROY){
801                 multi_xfer_release_handle(xe - Multi_xfer_entry);
802         }
803
804         // blast the memory clean
805         memset(xe,0,sizeof(xfer_entry));
806 }
807
808 // get a valid xfer entry handle
809 int multi_xfer_get_free_handle()
810 {
811         int idx;
812
813         // look for a free entry
814         for(idx=0;idx<MAX_XFER_ENTRIES;idx++){
815                 if(!(Multi_xfer_entry[idx].flags & MULTI_XFER_FLAG_USED)){
816                         return idx;
817                 }
818         }
819
820         return -1;
821 }
822
823
824 // ------------------------------------------------------------------------------------------
825 // MULTI XFER PACKET HANDLERS
826 //
827
828 // process an incoming file xfer data packet, return bytes processed, guaranteed to process the entire
829 // packet regardless of error conditions
830 int multi_xfer_process_packet(unsigned char *data, PSNET_SOCKET_RELIABLE who)
831 {       
832         ubyte val;      
833         xfer_entry *xe;
834         char filename[255];
835         ushort data_size = 0;
836         int file_size = -1;
837         ushort file_checksum = 0;
838         int offset = 0;
839         ubyte xfer_data[600];
840         ushort sig;
841         int sender_side = 1;
842
843         // read in all packet data
844         GET_DATA(val);  
845         GET_DATA(sig);
846         switch(val){
847         // RECV side
848         case MULTI_XFER_CODE_DATA:                              
849                 GET_DATA(data_size);            
850                 memcpy(xfer_data, data + offset, data_size);
851                 offset += data_size;
852                 sender_side = 0;
853                 break;
854
855         // RECV side
856         case MULTI_XFER_CODE_HEADER:            
857                 GET_STRING(filename);
858                 GET_DATA(file_size);                                    
859                 GET_DATA(file_checksum);
860                 sender_side = 0;
861                 break;
862
863         // SEND side
864         case MULTI_XFER_CODE_ACK:
865         case MULTI_XFER_CODE_NAK:
866                 break;
867
868         // RECV side
869         case MULTI_XFER_CODE_FINAL:
870                 sender_side = 0;
871                 break;
872
873         default:
874                 Int3();
875         }                       
876
877         // at this point we've read all the data in the packet
878
879         // at this point, we should process code-specific data  
880         xe = NULL;
881         if(val != MULTI_XFER_CODE_HEADER){              
882                 // if the code is not a request or a header, we need to look up the existing xfer_entry
883                 xe = NULL;
884                         
885                 xe = multi_xfer_find_entry(who, sig, sender_side);
886                 if(xe == NULL){                                         
887 #ifdef MULTI_XFER_VERBOSE
888                         nprintf(("Network","MULTI XFER : Could not find xfer entry for incoming data!\n"));
889
890                         // this is a rare case - I'm not overly concerned about it. But it _does_ happen. So blech
891 #ifndef NDEBUG
892                         int np_index = find_player_socket(who);
893                         ml_string("MULTI XFER : Could not find xfer entry for incoming data :");
894                         ml_printf(": sig == %d", sig);
895                         ml_printf(": xfer header == %d", val);
896                         if(np_index < 0){
897                                 ml_string(": player == unknown");
898                         } else {
899                                 ml_printf(": player == %s", Net_players[np_index].player->callsign);
900                         }
901                         if(sender_side){
902                                 ml_string(": sending");
903                         } else {
904                                 ml_string(": receiving");
905                         }
906 #endif
907 #endif
908                 //      Int3();
909                         return offset;
910                 }
911         }
912
913         switch((int)val){
914         // process an ack for this entry
915         case MULTI_XFER_CODE_ACK :
916                 Assert(xe != NULL);
917                 multi_xfer_process_ack(xe);
918                 break;
919         
920         // process a nak for this entry
921         case MULTI_XFER_CODE_NAK :
922                 Assert(xe != NULL);
923                 multi_xfer_process_nak(xe);
924                 break;
925
926         // process a "final" packet
927         case MULTI_XFER_CODE_FINAL :
928                 Assert(xe != NULL);
929                 multi_xfer_process_final(xe);
930                 break;
931
932         // process a data packet
933         case MULTI_XFER_CODE_DATA :
934                 Assert(xe != NULL);
935                 multi_xfer_process_data(xe, xfer_data, data_size);
936                 break;
937         
938         // process a header
939         case MULTI_XFER_CODE_HEADER :
940                 // send on my reliable socket
941                 multi_xfer_process_header(xfer_data, who, sig, filename, file_size, file_checksum);
942                 break;
943         }               
944         return offset;
945 }
946
947 // process an ack for this entry
948 void multi_xfer_process_ack(xfer_entry *xe)
949 {                       
950         // if we are a sender
951         if(xe->flags & MULTI_XFER_FLAG_SEND){
952                 // if we are waiting on a final ack, then the transfer has completed successfully
953                 if(xe->flags & MULTI_XFER_FLAG_UNKNOWN){
954                         xe->flags &= ~(MULTI_XFER_FLAG_UNKNOWN);
955                         xe->flags |= MULTI_XFER_FLAG_SUCCESS;
956
957 #ifdef MULTI_XFER_VERBOSE
958                         nprintf(("Network", "MULTI XFER : Successfully sent file %s\n", xe->filename));
959 #endif
960
961                         // if we should be auto-destroying this entry, do so
962                         if(xe->flags & MULTI_XFER_FLAG_AUTODESTROY){
963                                 multi_xfer_release_handle(xe - Multi_xfer_entry);
964                         }
965                 } 
966                 // otherwise if we're waiting for an ack, we should send the next chunk of data or a "final" packet if we're done
967                 else if(xe->flags & MULTI_XFER_FLAG_WAIT_ACK){
968                         multi_xfer_send_next(xe);
969                 }
970         }
971 }
972
973 // process a nak for this entry
974 void multi_xfer_process_nak(xfer_entry *xe)
975 {               
976         // if we get an ack at any time we should simply set the xfer to failed
977         multi_xfer_fail_entry(xe);
978 }
979                 
980 // process a "final" packet     
981 void multi_xfer_process_final(xfer_entry *xe)
982 {       
983         ushort chksum;
984
985         // make sure we skip a line
986         nprintf(("Network","\n"));
987         
988         // close the file
989         if(xe->file != NULL){
990                 cflush(xe->file);
991                 cfclose(xe->file);
992                 xe->file = NULL;
993         }       
994
995         // check to make sure the file checksum is the same
996         chksum = 0;
997         if(!cf_chksum_short(xe->ex_filename, &chksum, -1, xe->force_dir) || (chksum != xe->file_chksum)){
998                 // mark as failed
999                 xe->flags |= MULTI_XFER_FLAG_FAIL;
1000
1001 #ifdef MULTI_XFER_VERBOSE
1002                 nprintf(("Network","MULTI XFER : file %s failed checksum %d %d!\n",xe->ex_filename, (int)xe->file_chksum, (int)chksum));
1003 #endif
1004
1005                 // abort the xfer
1006                 multi_xfer_abort(xe - Multi_xfer_entry);
1007                 return;
1008         }
1009         // checksums check out, so rename the file and be done with it
1010         else {
1011 #ifdef MULTI_XFER_VERBOSE
1012                 nprintf(("Network","MULTI XFER : renaming xferred file from %s to %s (chksum %d %d)\n", xe->ex_filename, xe->filename, (int)xe->file_chksum, (int)chksum));
1013 #endif
1014                 // rename the file properly
1015                 if(cf_rename(xe->ex_filename,xe->filename, xe->force_dir) == CF_RENAME_SUCCESS){
1016                         // mark the xfer as being successful
1017                         xe->flags |= MULTI_XFER_FLAG_SUCCESS;   
1018
1019                         nprintf(("Network","MULTI XFER : SUCCESSFULLY TRANSFERRED FILE %s (%d bytes)\n", xe->filename, xe->file_size));         
1020
1021                         // send an ack to the sender
1022                         multi_xfer_send_ack(xe->file_socket, xe->sig);
1023                 } else {
1024                         // mark it as failing
1025                         xe->flags |= MULTI_XFER_FLAG_FAIL;
1026                         nprintf(("Network","FAILED TO TRANSFER FILE (could not rename temp file %s)\n", xe->ex_filename));
1027
1028                         // delete the tempfile
1029                         cf_delete(xe->ex_filename, xe->force_dir);
1030
1031                         // send an nak to the sender
1032                         multi_xfer_send_nak(xe->file_socket, xe->sig);
1033                 }
1034
1035                 // if we should be auto-destroying this entry, do so
1036                 if(xe->flags & MULTI_XFER_FLAG_AUTODESTROY){
1037                         multi_xfer_release_handle(xe - Multi_xfer_entry);
1038                 }
1039         }
1040 }
1041
1042 // process a data packet
1043 void multi_xfer_process_data(xfer_entry *xe, ubyte *data, int data_size)        
1044 {                       
1045         // print out a crude progress indicator
1046         nprintf(("Network","."));               
1047
1048         // attempt to write the rest of the data string to the file
1049         if((xe->file == NULL) || !cfwrite(data, data_size, 1, xe->file)){
1050                 // inform the sender we had a problem
1051                 multi_xfer_send_nak(xe->file_socket, xe->sig);
1052
1053                 // fail this entry
1054                 multi_xfer_fail_entry(xe);
1055
1056                 xe->file_ptr += data_size;              
1057                 return;
1058         }
1059
1060         // increment the file pointer
1061         xe->file_ptr += data_size;
1062
1063         // send an ack to the sender
1064         multi_xfer_send_ack(xe->file_socket, xe->sig);
1065
1066         // set the timestmp
1067         xe->xfer_stamp = timestamp(MULTI_XFER_TIMEOUT); 
1068 }
1069         
1070 // process a header, return bytes processed
1071 void multi_xfer_process_header(ubyte *data, PSNET_SOCKET_RELIABLE who, ushort sig, char *filename, int file_size, ushort file_checksum)
1072 {               
1073         xfer_entry *xe;         
1074         int handle;     
1075
1076         // if the xfer system is locked, send a nak
1077         if(Multi_xfer_locked){          
1078                 multi_xfer_send_nak(who, sig);
1079                 return;
1080         }
1081
1082         // try and get a free xfer handle
1083         handle = multi_xfer_get_free_handle();
1084         if(handle == -1){               
1085                 multi_xfer_send_nak(who, sig);
1086                 return;
1087         } else {
1088                 xe = &Multi_xfer_entry[handle];
1089                 memset(xe,0,sizeof(xfer_entry));
1090         }               
1091
1092         // set the recv and used flags
1093         xe->flags |= (MULTI_XFER_FLAG_USED | MULTI_XFER_FLAG_RECV);
1094
1095         // get the header data  
1096         xe->file_size = file_size;
1097
1098         // get the file chksum
1099         xe->file_chksum = file_checksum;        
1100
1101         // set the socket
1102         xe->file_socket = who;  
1103
1104         // set the timeout timestamp
1105         xe->xfer_stamp = timestamp(MULTI_XFER_TIMEOUT);
1106
1107         // set the sig
1108         xe->sig = sig;
1109
1110         // copy the filename and get the prefixed xfer filename
1111         strcpy(xe->filename, filename);
1112         multi_xfer_conv_prefix(xe->filename, xe->ex_filename);
1113 #ifdef MULTI_XFER_VERBOSE
1114         nprintf(("Network","MULTI XFER : converted filename %s to %s\n",xe->filename, xe->ex_filename));
1115 #endif
1116
1117         // determine what directory to place the file in
1118         // individual xfer entries take precedence over the global multi xfer force entry       
1119         xe->force_dir = Multi_xfer_force_dir;   
1120
1121         // call the callback function
1122         Multi_xfer_recv_notify(handle); 
1123
1124         // if the notify function invalidated this xfer handle, then cancel the whole thing
1125         if(xe->flags & MULTI_XFER_FLAG_REJECT){         
1126                 multi_xfer_send_nak(who, sig);
1127                 
1128                 // clear the data
1129                 memset(xe, 0, sizeof(xfer_entry));
1130                 return;
1131         }                       
1132
1133         // delete the old file (if it exists)
1134         cf_delete( xe->filename, CF_TYPE_MULTI_CACHE );
1135         cf_delete( xe->filename, CF_TYPE_MISSIONS );
1136
1137         // attempt to open the file (using the prefixed filename)
1138         xe->file = NULL;
1139         xe->file = cfopen(xe->ex_filename, "wb", CFILE_NORMAL, xe->force_dir);
1140         if(xe->file == NULL){           
1141                 multi_xfer_send_nak(who, sig);          
1142
1143                 // clear the data
1144                 memset(xe, 0, sizeof(xfer_entry));
1145                 return;
1146         }
1147         
1148         // set the waiting for data flag
1149         xe->flags |= MULTI_XFER_FLAG_WAIT_DATA;         
1150
1151         // send an ack to the server            
1152         multi_xfer_send_ack(who, sig);  
1153
1154 #ifdef MULTI_XFER_VERBOSE
1155         nprintf(("Network","MULTI XFER : AFTER HEADER %s\n",xe->filename));
1156 #endif  
1157 }
1158
1159 // send the next block of outgoing data or a "final" packet if we're done
1160 void multi_xfer_send_next(xfer_entry *xe)
1161 {
1162         ubyte data[MAX_PACKET_SIZE],code;
1163         ushort data_size;
1164         int flen;
1165         int packet_size = 0;    
1166
1167         // print out a crude progress indicator
1168         nprintf(("Network", "+"));              
1169
1170         // if we've sent all the data, then we should send a "final" packet
1171         if(xe->file_ptr >= xe->file_size){
1172                 // mark the entry as unknown 
1173                 xe->flags |= MULTI_XFER_FLAG_UNKNOWN;
1174
1175                 // set the timestmp
1176                 xe->xfer_stamp = timestamp(MULTI_XFER_TIMEOUT);
1177
1178                 // send the packet
1179                 multi_xfer_send_final(xe);              
1180
1181                 return;
1182         }
1183
1184         // build the header 
1185         BUILD_HEADER(XFER_PACKET);      
1186
1187         // length of the added string
1188         flen = strlen(xe->filename) + 4;
1189
1190         // determine how much data we are going to send with this packet and add it in
1191         if((xe->file_size - xe->file_ptr) >= (MULTI_XFER_MAX_DATA_SIZE - flen)){
1192                 data_size = (ushort)(MULTI_XFER_MAX_DATA_SIZE - flen);
1193         } else {
1194                 data_size = (unsigned short)(xe->file_size - xe->file_ptr);
1195         }
1196         // increment the file pointer
1197         xe->file_ptr += data_size;      
1198
1199         // add the opcode
1200         code = MULTI_XFER_CODE_DATA;
1201         ADD_DATA(code);
1202
1203         // add the sig
1204         ADD_DATA(xe->sig);
1205
1206         // add in the size of the rest of the packet    
1207         ADD_DATA(data_size);
1208         
1209         // copy in the data
1210         if(cfread(data+packet_size,1,(int)data_size,xe->file) == 0){
1211                 // send a nack to the receiver
1212                 multi_xfer_send_nak(xe->file_socket, xe->sig);
1213
1214                 // fail this send
1215                 multi_xfer_fail_entry(xe);              
1216                 return;
1217         }
1218
1219         // increment the packet size
1220         packet_size += (int)data_size;
1221
1222         // set the timestmp
1223         xe->xfer_stamp = timestamp(MULTI_XFER_TIMEOUT);
1224
1225         // otherwise send the data      
1226         psnet_rel_send(xe->file_socket, data, packet_size);
1227 }
1228
1229 // send an ack to the sender
1230 void multi_xfer_send_ack(PSNET_SOCKET_RELIABLE socket, ushort sig)
1231 {
1232         ubyte data[MAX_PACKET_SIZE],code;       
1233         int packet_size = 0;
1234
1235         // build the header and add 
1236         BUILD_HEADER(XFER_PACKET);      
1237
1238         // add the opcode
1239         code = MULTI_XFER_CODE_ACK;
1240         ADD_DATA(code);
1241
1242         // add the sig
1243         ADD_DATA(sig);
1244         
1245         // send the data        
1246         psnet_rel_send(socket, data, packet_size);
1247 }
1248
1249 // send a nak to the sender
1250 void multi_xfer_send_nak(PSNET_SOCKET_RELIABLE socket, ushort sig)
1251 {
1252         ubyte data[MAX_PACKET_SIZE],code;       
1253         int packet_size = 0;
1254
1255         // build the header and add the code
1256         BUILD_HEADER(XFER_PACKET);      
1257
1258         // add the opcode
1259         code = MULTI_XFER_CODE_NAK;
1260         ADD_DATA(code);
1261
1262         // add the sig
1263         ADD_DATA(sig);
1264
1265         // send the data        
1266         psnet_rel_send(socket, data, packet_size);
1267 }
1268
1269 // send a "final" packet
1270 void multi_xfer_send_final(xfer_entry *xe)
1271 {
1272         ubyte data[MAX_PACKET_SIZE],code;       
1273         int packet_size = 0;
1274
1275         // build the header
1276         BUILD_HEADER(XFER_PACKET);      
1277
1278         // add the code
1279         code = MULTI_XFER_CODE_FINAL;
1280         ADD_DATA(code);
1281
1282         // add the sig
1283         ADD_DATA(xe->sig);
1284
1285         // send the data        
1286         psnet_rel_send(xe->file_socket, data, packet_size);
1287 }
1288
1289 // send the header to begin a file transfer
1290 void multi_xfer_send_header(xfer_entry *xe)
1291 {
1292         ubyte data[MAX_PACKET_SIZE],code;       
1293         int packet_size = 0;
1294
1295         // build the header and add the opcode
1296         BUILD_HEADER(XFER_PACKET);      
1297         code = MULTI_XFER_CODE_HEADER;
1298         ADD_DATA(code);
1299
1300         // add the sig
1301         ADD_DATA(xe->sig);
1302
1303         // add the filename
1304         ADD_STRING(xe->filename);
1305                 
1306         // add the id #
1307         ADD_DATA(xe->file_size);
1308
1309         // add the file checksum
1310         ADD_DATA(xe->file_chksum);
1311
1312         // send the packet      
1313         psnet_rel_send(xe->file_socket, data, packet_size);
1314 }
1315
1316 // convert the filename into the prefixed ex_filename
1317 void multi_xfer_conv_prefix(char *filename,char *ex_filename)
1318 {
1319         char temp[MAX_FILENAME_LEN+50];
1320         
1321         // blast the memory clean
1322         memset(temp, 0, MAX_FILENAME_LEN+50);
1323
1324         // copy in the prefix
1325         strcpy(temp, MULTI_XFER_FNAME_PREFIX);
1326
1327         // stick on the original name
1328         strcat(temp, filename);
1329
1330         // copy the whole thing to the outgoing filename
1331         strcpy(ex_filename, temp);
1332 }
1333
1334 // get a new xfer sig
1335 ushort multi_xfer_get_sig()
1336 {
1337         ushort ret = Multi_xfer_sig;
1338
1339         // new one
1340         if(Multi_xfer_sig == 0xffff){
1341                 Multi_xfer_sig = 0;
1342         } else {
1343                 Multi_xfer_sig++;
1344         }
1345
1346         return ret;
1347 }