fusilli-client: add recipe
[openpandora.oe.git] / recipes / fusilli-client / files / sparrowNet.c
1  /* This file is part of sparrow3d.
2   * Sparrow3d is free software: you can redistribute it and/or modify
3   * it under the terms of the GNU General Public License as published by
4   * the Free Software Foundation, either version 2 of the License, or
5   * (at your option) any later version.
6   * 
7   * Sparrow3d is distributed in the hope that it will be useful,
8   * but WITHOUT ANY WARRANTY; without even the implied warranty of
9   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10   * GNU General Public License for more details.
11   * 
12   * You should have received a copy of the GNU General Public License
13   * along with Foobar.  If not, see <http://www.gnu.org/licenses/>
14   * 
15   * For feedback and questions about my Files and Projects please mail me,
16   * Alexander Matthes (Ziz) , zizsdl_at_googlemail.com */
17
18 #include "sparrowNet.h"
19 #include <stdio.h>
20 #include <errno.h>
21
22 //This is a copy of spReadOneLine sparrowFile. However, I don't want the
23 //extra dependency of libSparrow3d or linking sparrowFile twice.
24 int internal_spNet_spReadOneLine( SDL_RWops* file , char* buffer, int buffer_len)
25 {
26         int pos = 0;
27         buffer[pos] = 0;
28         while (pos < buffer_len)
29         {
30                 if (SDL_RWread( file, &(buffer[pos]), 1, 1 ) <= 0)
31                         return 1; //EOF
32                 if ( buffer[pos] == '\n' )
33                         break;
34                 if (buffer[pos] != '\r') //fucking windows line break
35                         pos++;
36         }
37         buffer[pos] = 0;
38         return 0; //not EOF
39 }
40
41 spNetC4ATaskPointer spGlobalC4ATask = NULL;
42 SDL_mutex* spCacheMutex = NULL;
43
44 spNetC4ATaskPointer createNewC4ATask()
45 {
46         spNetC4ATaskPointer task = (spNetC4ATaskPointer)malloc(sizeof(spNetC4ATask));
47         task->statusMutex = SDL_CreateMutex();
48         task->status = 0;
49         task->dataPointer = NULL;
50         task->timeOut = 0;
51         task->thread = NULL;
52         task->result = 0;
53         task->threadStatus = 0;
54         task->message = 0;
55         return task;
56 }
57
58 void spNetC4ADeleteTask(spNetC4ATaskPointer task)
59 {
60         SDL_DestroyMutex(task->statusMutex);
61         free(task);
62 }
63
64 PREFIX void spInitNet()
65 {
66         if(SDLNet_Init()==-1)
67                 printf("SDLNet_Init: %s\n", SDLNet_GetError());
68         spGlobalC4ATask = createNewC4ATask();
69         spCacheMutex = SDL_CreateMutex();
70 }
71
72 void fill_ip_struct(spNetIPPointer ip)
73 {
74         ip->type = IPV4;
75         ip->address.ipv4 = ip->sdl_address.host; //bytes are set automaticly, yeah!
76         ip->port = ip->sdl_address.port;        
77 }
78
79 PREFIX spNetIP spNetResolve(char* host,Uint16 port)
80 {
81         spNetIP result;
82         SDLNet_ResolveHost(&(result.sdl_address), host, port);
83         fill_ip_struct(&result);
84         return result;
85 }
86
87 PREFIX char* spNetResolveHost(spNetIP ip,char* host,int host_len)
88 {
89         const char* sdlHost = SDLNet_ResolveIP(&(ip.sdl_address));
90         if (strlen(sdlHost) >= host_len)
91         {
92                 host = NULL;
93                 return NULL;
94         }
95         sprintf(host,"%s",sdlHost);
96         return host;
97 }
98
99 PREFIX spNetTCPConnection spNetOpenClientTCP(spNetIP ip)
100 {
101         spNetTCPConnection result;
102
103         result=SDLNet_TCP_Open(&(ip.sdl_address));
104         if(!result) {
105                 printf("SDLNet_TCP_Open: %s\n", SDLNet_GetError());
106                 return NULL;
107         }
108         return result;
109 }
110
111 PREFIX spNetTCPServer spNetOpenServerTCP(Uint16 port)
112 {
113         IPaddress ip;
114         spNetTCPServer result;
115
116         if(SDLNet_ResolveHost(&ip,NULL,port)==-1) {
117                 printf("SDLNet_ResolveHost: %s\n", SDLNet_GetError());
118                 return NULL;
119         }
120         result=SDLNet_TCP_Open(&ip);
121         if(!result) {
122                 printf("SDLNet_TCP_Open: %s\n", SDLNet_GetError());
123                 return NULL;
124         }
125         return result;
126 }
127
128 PREFIX spNetTCPConnection spNetAcceptTCP(spNetTCPServer server)
129 {
130         return SDLNet_TCP_Accept(server);
131 }
132
133 PREFIX spNetIP spNetGetConnectionIP(spNetTCPConnection connection)
134 {
135         IPaddress *temp_ip;
136         temp_ip=SDLNet_TCP_GetPeerAddress(connection);
137         spNetIP result;
138         if(!temp_ip) {
139                 printf("SDLNet_TCP_GetPeerAddress: %s\n", SDLNet_GetError());
140                 printf("This may be a server socket.\n");
141                 printf("However, the ip may not be valid!\n");
142         }
143         result.sdl_address = *temp_ip;
144         fill_ip_struct(&result);
145         return result;
146 }
147
148 PREFIX int spNetSendTCP(spNetTCPConnection connection,void* data,int length)
149 {
150         return SDLNet_TCP_Send(connection,data,length);
151 }
152
153 PREFIX int spNetSendHTTP(spNetTCPConnection connection,char* data)
154 {
155         return spNetSendTCP(connection,data,strlen(data)+1);
156 }
157
158 typedef struct receivingStruct *receivingPointer;
159 typedef struct receivingStruct {
160         spNetTCPConnection connection;
161         void* data;
162         int length;
163         SDL_mutex* mutex;
164         int done;
165         SDL_Thread* thread;
166         int result;
167         receivingPointer next;
168 } receivingType;
169
170 int tcpReceiveThread(void* data)
171 {
172         receivingPointer tcpData = (receivingPointer)data;
173         int res=spNetReceiveTCP(tcpData->connection,tcpData->data,tcpData->length);
174         SDL_mutexP(tcpData->mutex);
175         tcpData->done = 1;
176         tcpData->result = res;
177         SDL_mutexV(tcpData->mutex);
178         return res;
179 }
180
181 int tcpReceiveThread_http(void* data)
182 {
183         receivingPointer tcpData = (receivingPointer)data;
184         int res=spNetReceiveHTTP(tcpData->connection,(char*)tcpData->data,tcpData->length);
185         SDL_mutexP(tcpData->mutex);
186         tcpData->done = 1;
187         tcpData->result = res;
188         SDL_mutexV(tcpData->mutex);
189         return res;
190 }
191
192 receivingPointer firstReceiving = NULL;
193
194 SDL_Thread* allreadyReceiving(spNetTCPConnection connection)
195 {
196         receivingPointer before = NULL;
197         receivingPointer mom = firstReceiving;
198         while (mom)
199         {
200                 if (mom->connection == connection)
201                 {
202                         SDL_mutexP(mom->mutex);
203                         if (mom->done)
204                         {
205                                 SDL_mutexV(mom->mutex); //The Thread lost the interest on this struct
206                                 //Removing mom
207                                 if (before)
208                                 {
209                                         SDL_mutexP(before->mutex);
210                                         before->next = mom->next;
211                                         SDL_mutexV(before->mutex);
212                                 }
213                                 else
214                                         firstReceiving = mom->next;
215                                 SDL_DestroyMutex(mom->mutex);
216                                 if (mom->result<=0) //connection destroyed!
217                                 {
218                                         free(mom);
219                                         return (SDL_Thread*)(-1);
220                                 }
221                                 free(mom);
222                                 return NULL;
223                         }
224                         SDL_mutexV(mom->mutex);
225                         return mom->thread;
226                 }
227                 before = mom;
228                 mom = mom->next;
229         }       
230         return NULL;
231 }
232
233 PREFIX int spNetReceiveTCP(spNetTCPConnection connection,void* data,int length)
234 {
235         char* data_pointer = (char*)data;
236         return SDLNet_TCP_Recv(connection,&(data_pointer[0]),length);
237 }
238
239 PREFIX SDL_Thread* spNetReceiveTCPUnblocked(spNetTCPConnection connection,void* data,int length)
240 {
241         SDL_Thread* thread;
242         if (thread = allreadyReceiving(connection))
243                 return thread;
244         receivingPointer tcpData = (receivingPointer)malloc(sizeof(receivingType));
245         tcpData->connection = connection;
246         tcpData->data = data;
247         tcpData->length = length;
248         tcpData->connection = connection;
249         tcpData->done = 0;
250         tcpData->mutex = SDL_CreateMutex();
251         tcpData->next = firstReceiving;
252         firstReceiving = tcpData;
253         tcpData->thread = SDL_CreateThread(tcpReceiveThread,tcpData);
254         return tcpData->thread;
255 }
256
257 PREFIX int spNetReceiveHTTP(spNetTCPConnection connection,char* data,int length)
258 {
259         int received = 0;
260         while (length > 0)
261         {
262                 int new_received = spNetReceiveTCP(connection,&(data[received]),length);
263                 received+=new_received;
264                 length-=new_received;
265                 if (new_received == 0)
266                         return received;
267         }
268         return received;
269 }
270
271 PREFIX SDL_Thread* spNetReceiveHTTPUnblocked(spNetTCPConnection connection,char* data,int length)
272 {
273         SDL_Thread* thread;
274         if (thread = allreadyReceiving(connection))
275                 return thread;
276         receivingPointer tcpData = (receivingPointer)malloc(sizeof(receivingType));
277         tcpData->connection = connection;
278         tcpData->data = data;
279         tcpData->length = length;
280         tcpData->connection = connection;
281         tcpData->done = 0;
282         tcpData->mutex = SDL_CreateMutex();
283         tcpData->next = firstReceiving;
284         firstReceiving = tcpData;
285         tcpData->thread = SDL_CreateThread(tcpReceiveThread_http,tcpData);
286         return tcpData->thread;
287 }
288
289 PREFIX int spNetReceiveStillWaiting(SDL_Thread* thread)
290 {
291         receivingPointer before = NULL;
292         receivingPointer mom = firstReceiving;
293         while (mom)
294         {
295                 if (mom->thread == thread)
296                 {
297                         SDL_mutexP(mom->mutex);
298                         if (mom->done)
299                         {
300                                 SDL_mutexV(mom->mutex); //The Thread lost the interest on this struct
301                                 //Removing mom
302                                 if (before)
303                                 {
304                                         SDL_mutexP(before->mutex);
305                                         before->next = mom->next;
306                                         SDL_mutexV(before->mutex);
307                                 }
308                                 else
309                                         firstReceiving = mom->next;
310                                 SDL_DestroyMutex(mom->mutex);
311                                 free(mom);
312                                 return 0;
313                         }
314                         SDL_mutexV(mom->mutex);
315                         return 1;
316                 }
317                 before = mom;
318                 mom = mom->next;
319         }       
320         return 0;
321 }
322
323 PREFIX void spNetCloseTCP(spNetTCPConnection connection)
324 {
325         SDLNet_TCP_Close(connection);
326 }
327
328 PREFIX void spQuitNet()
329 {
330         spNetC4ADeleteTask(spGlobalC4ATask);
331         spGlobalC4ATask = NULL;
332         SDL_mutexP(spCacheMutex);
333         SDL_DestroyMutex(spCacheMutex);
334         SDLNet_Quit();
335 }
336
337 #ifdef PANDORA
338         #include "pnd_locate.h"
339 #endif
340
341 typedef struct getgenericStruct *getgenericPointer;
342 typedef struct getgenericStruct {
343         spNetC4ATaskPointer task;
344         int ( *function )( void* data );
345 } getgenericType;
346
347 typedef struct getgameStruct *getgamePointer;
348 typedef struct getgameStruct {
349         spNetC4ATaskPointer task;
350         int ( *function )( void* data );
351         spNetC4AGamePointer* game;
352 } getgameType;
353
354 typedef struct getscoreStruct *getscorePointer;
355 typedef struct getscoreStruct {
356         spNetC4ATaskPointer task;
357         int ( *function )( void* data );
358         spNetC4AScorePointer* score;
359         spNetC4AProfilePointer profile;
360         int year;
361         int month;
362         char game[256];
363 } getscoreType;
364
365 typedef struct commitStruct *commitPointer;
366 typedef struct commitStruct {
367         spNetC4ATaskPointer task;
368         int ( *function )( void* data );
369         spNetC4AProfilePointer profile;
370         char game[256];
371         int score;
372         char system[256];
373         spNetC4AScorePointer* scoreList;
374 } commitType;
375
376 typedef struct createStruct *createPointer;
377 typedef struct createStruct {
378         spNetC4ATaskPointer task;
379         int ( *function )( void* data );
380         spNetC4AProfilePointer* profile;
381         char longname[256];
382         char shortname[256];
383         char password[256];
384         char email[256];
385         int deleteFile;
386 } createType;
387
388 int spNetC4ACaching = 0;
389 char spCacheFilename[256] = "";
390
391 //This is usefull for debugging without threading influences:
392 /*#define SDL_CreateThread SDL_CreateThreadWithoutThreading
393 SDL_Thread* SDL_CreateThreadWithoutThreading(int (*fn)(void *),void* data)
394 {
395         fn(data);
396         return NULL;
397 }*/
398
399
400 typedef struct cacheStruct *cachePointer;
401 typedef struct cacheStruct {
402         char game[256];
403         char system[256];
404         char prid[256];
405         int score;
406         cachePointer next;
407 } cacheType;
408
409 cachePointer read_cache()
410 {
411         SDL_RWops *file = SDL_RWFromFile(spCacheFilename, "rb");
412         if (file)
413         {
414                 char game[256];
415                 char system[256];
416                 char prid[256];
417                 int score;
418                 cachePointer cache = NULL;
419                 cachePointer last = NULL;
420                 while (1)
421                 {
422                         if (SDL_RWread(file,game,256,1) <= 0)
423                                 break;
424                         if (SDL_RWread(file,system,256,1) <= 0)
425                                 break;
426                         if (SDL_RWread(file,prid,256,1) <= 0)
427                                 break;
428                         if (SDL_RWread(file,&score,sizeof(int),1) <= 0)
429                                 break;
430                         cachePointer new_cache = (cachePointer)malloc(sizeof(cacheType));
431                         memcpy(new_cache->game,game,256);
432                         memcpy(new_cache->system,system,256);
433                         memcpy(new_cache->prid,prid,256);
434                         new_cache->score = score;
435                         new_cache->next = NULL;
436                         if (last)
437                                 last->next = new_cache;
438                         else
439                                 cache = new_cache;
440                         last = new_cache;
441                 }
442                 SDL_RWclose(file);
443                 return cache;
444         }
445         return NULL;
446 }
447
448 void write_to_cache(char* game,char* system,char* prid,int score,int lock)
449 {
450         if (lock)
451                 SDL_mutexP(spCacheMutex);
452         cachePointer cache = NULL;
453         if (spNetC4ACaching != 1)
454                 cache = read_cache();
455         //Searching one of game
456         cachePointer mom = cache;
457         int nr = 0;
458         while (mom)
459         {
460                 if (strcmp(mom->game,game) == 0)
461                         break;
462                 nr++;
463                 mom = mom->next;
464         }
465         if (mom)
466         {
467                 if  ((spNetC4ACaching == 2 && mom->score < score) ||
468                         (spNetC4ACaching == 3 && mom->score > score))
469                 {
470                         //Seek and rewrite
471                         SDL_RWops *file = SDL_RWFromFile(spCacheFilename, "r+b");
472                         SDL_RWseek(file,nr*(256*3+sizeof(int))+256*3,SEEK_SET);
473                         SDL_RWwrite(file,&score,sizeof(int),1);
474                         SDL_RWclose(file);
475                 }
476         }
477         else
478         {
479                 SDL_RWops *file = SDL_RWFromFile(spCacheFilename, "ab");
480                 SDL_RWwrite(file,game,256,1);
481                 SDL_RWwrite(file,system,256,1);
482                 SDL_RWwrite(file,prid,256,1);
483                 SDL_RWwrite(file,&score,sizeof(int),1);
484                 SDL_RWclose(file);
485         }               
486         while (cache)
487         {
488                 mom = cache->next;
489                 free(cache);
490                 cache = mom;
491         }
492         if (lock)
493                 SDL_mutexV(spCacheMutex);
494 }
495
496 int spNetC4AUberThread(getgenericPointer data)
497 {
498         int startTime = SDL_GetTicks();
499         SDL_Thread* thread = SDL_CreateThread(data->function,data);
500         while (1)
501         {
502         #ifdef REALGP2X
503                 //TODO: Implement!
504                 SDL_Delay(100);
505         #elif defined WIN32
506                 SDL_Delay(100); 
507         #else
508                 usleep(100000);
509         #endif
510                 int newTime = SDL_GetTicks();
511                 int diff = newTime - startTime;
512                 startTime = newTime;
513                 data->task->timeOut -= diff;
514                 SDL_mutexP(data->task->statusMutex);
515                 int status = data->task->status;
516                 SDL_mutexV(data->task->statusMutex);
517                 //only 1 second left, lets send a message
518                 if (data->task->message == 0 && (status == SP_C4A_CANCELED || data->task->timeOut <= 1000))
519                         data->task->message = 1;
520                 //time is over. If the message is reset we assume the thread will finish, otherwise...
521                 if (data->task->message == 1 && (status == SP_C4A_CANCELED || data->task->timeOut <= 0))
522                 {
523                         //Waiting for the write cache mutex ANYWAY.
524                         SDL_mutexP(spCacheMutex);
525                         SDL_KillThread(thread);
526                         SDL_mutexV(spCacheMutex);
527                         data->task->result = 1;
528                         SDL_mutexP(data->task->statusMutex);
529                         if (data->task->timeOut <= 0)
530                                 data->task->status = SP_C4A_TIMEOUT;
531                         data->task->threadStatus = 0;
532                         SDL_mutexV(data->task->statusMutex);
533                         int result = data->task->result;
534                         data->task->dataPointer = NULL;
535                         free(data);
536                         return result;
537                 }
538                 if (status <= 0) //finished somehow
539                 {                       
540                         SDL_WaitThread(thread,&(data->task->result));
541                         SDL_mutexP(data->task->statusMutex);
542                         data->task->threadStatus = 0;
543                         SDL_mutexV(data->task->statusMutex);
544                         int result = data->task->result;
545                         data->task->dataPointer = NULL;
546                         free(data);
547                         return result;
548                 }
549         }
550 }
551
552 char* my_strchr(char* buffer, char c, char ignore)
553 {
554         int i;
555         int in_ignore = 0;
556         for (i = 0; buffer[i]!=0; i++)
557         {
558                 if (buffer[i] == ignore)
559                         in_ignore = 1-in_ignore;
560                 if (!in_ignore && buffer[i] == c)
561                         return &(buffer[i]);
562         }
563         return NULL;
564 }
565
566 void fill_between_paraphrases(char* buffer, char* dest, int max_size)
567 {
568         int i,j = 0;
569         int in_paraphrases = 0;
570         for (i = 0; buffer[i]!=0; i++)
571         {
572                 if (buffer[i] == '\"')
573                 {
574                         switch (in_paraphrases)
575                         {
576                                 case 0: in_paraphrases = 1; break;
577                                 case 1: dest[j]=0;return;
578                         }
579                         continue;
580                 }
581                 if (in_paraphrases)
582                 {
583                         dest[j] = buffer[i];
584                         j++;
585                         if (j == max_size)
586                         {
587                                 dest[j-1] = 0;
588                                 return;
589                         }
590                 }
591         }
592 }
593
594 void internal_CreateDirectoryChain( const char* directories)
595 {
596         //Creating copy:
597         int len = strlen(directories)+1;
598         #ifdef __GNUC__
599                 char directoriesCopy[len];
600         #else
601                 char* directoriesCopy = (char*)malloc( len * sizeof(char) );
602         #endif
603         memcpy(directoriesCopy,directories,len);
604         //Splitting in subdirectories
605         char* subString = directoriesCopy;
606         char* endOfString = strchr(subString,'/');
607         if (endOfString == NULL)
608                 endOfString = strchr(subString,0);
609         while (endOfString)
610         {
611                 char oldChar = endOfString[0];
612                 endOfString[0] = 0;
613                 #ifdef WIN32
614
615                         if (CreateDirectory(directoriesCopy,NULL))
616                         {}
617                         else
618                         if (GetLastError() != ERROR_ALREADY_EXISTS)
619                                 break;
620                 #else
621                         int error = mkdir(directoriesCopy,0777);
622                         if (errno == 0 || errno == EEXIST || errno == ENOENT) //thats okay :)
623                         {}
624                         else //not okay
625                                 break;
626                 #endif
627                 endOfString[0] = oldChar;
628                 if (oldChar == 0)
629                         break;
630                 subString = &(endOfString[1]);
631                 endOfString = strchr(subString,'/');
632                 if (endOfString == NULL)
633                         endOfString = strchr(subString,0);
634         }
635         #ifndef __GNUC__
636                 free(directoriesCopy);
637         #endif
638 }
639
640 #ifdef PANDORA
641         #define PROFILE_FILENAME_MAKRO char *locate_filename = pnd_locate_filename ( "/media/*/pandora/appdata/c4a-mame/:.", "c4a-prof" ); \
642                 char filename[256] = "./c4a-prof"; \
643                 if (locate_filename) \
644                         sprintf(filename,"%s",locate_filename); \
645                 else \
646                 { \
647                         locate_filename = pnd_locate_filename ( "/media/*/pandora/:.", "appdata" ); \
648                         if (locate_filename) \
649                         { \
650                                 sprintf(filename,"%s/c4a-mame",locate_filename); \
651                                 internal_CreateDirectoryChain(filename); \
652                                 sprintf(filename,"%s/c4a-mame/c4a-prof",locate_filename); \
653                         } \
654                 }
655 #elif defined GCW || (defined X86CPU && !defined WIN32)
656         #define PROFILE_FILENAME_MAKRO char filename[256]; \
657                 sprintf(filename,"%s/.config/compo4all",getenv("HOME"));\
658                 internal_CreateDirectoryChain(filename);\
659                 sprintf(filename,"%s/.config/compo4all/c4a-prof",getenv("HOME"));
660 #else
661         #define PROFILE_FILENAME_MAKRO char filename[256] = "./c4a-prof";
662 #endif
663
664 PREFIX void spNetC4ASetCaching(int value)
665 {
666         spNetC4ACaching = value;
667 }
668
669 void set_cache_filename()
670 {
671         PROFILE_FILENAME_MAKRO
672         sprintf(spCacheFilename,"%s",filename);
673         sprintf(&spCacheFilename[strlen(spCacheFilename)-4],"cache");
674 }
675
676 PREFIX spNetC4AProfilePointer spNetC4AGetProfile()
677 {
678         set_cache_filename();
679         spNetC4AProfilePointer profile = NULL;
680         PROFILE_FILENAME_MAKRO
681         //Parsing the file
682         SDL_RWops *file=SDL_RWFromFile(filename,"rb");
683         if (file == NULL)
684                 return NULL;
685         profile = (spNetC4AProfilePointer)malloc(sizeof(spNetC4AProfile));
686         char buffer[2048];
687         internal_spNet_spReadOneLine(file,buffer,2048);
688         internal_spNet_spReadOneLine(file,buffer,2048);
689         char* pos = strstr( buffer, "\"longname\":");
690         pos+=11;
691         fill_between_paraphrases( pos, profile->longname, 256);
692         
693         pos = strstr( buffer, "\"shortname\":");
694         pos+=12;
695         fill_between_paraphrases( pos, profile->shortname, 256);
696         
697         pos = strstr( buffer, "\"prid\":");
698         pos+=7;
699         fill_between_paraphrases( pos, profile->prid, 256);
700
701         pos = strstr( buffer, "\"email\":");
702         pos+=8;
703         fill_between_paraphrases( pos, profile->email, 256);
704
705         pos = strstr( buffer, "\"password\":");
706         pos+=11;
707         fill_between_paraphrases( pos, profile->password, 256);
708         SDL_RWclose(file);
709         return profile;
710 }
711
712 PREFIX void spNetC4AFreeProfile(spNetC4AProfilePointer profile)
713 {
714         if (profile)
715                 free(profile);
716 }
717
718 int c4a_getgame_thread(void* data)
719 {
720         getgamePointer gameData = ((getgamePointer)data);
721         spNetIP ip = spNetResolve("skeezix.wallednetworks.com",13001);
722         if (ip.address.ipv4 == SP_INVALID_IP)
723         {
724                 SDL_mutexP(gameData->task->statusMutex);
725                 gameData->task->status = SP_C4A_ERROR;
726                 SDL_mutexV(gameData->task->statusMutex);
727                 return 1;
728         }       
729         spNetTCPConnection connection = spNetOpenClientTCP(ip);
730         if (connection == NULL)
731         {
732                 SDL_mutexP(gameData->task->statusMutex);
733                 gameData->task->status = SP_C4A_ERROR;
734                 SDL_mutexV(gameData->task->statusMutex);
735                 return 1;
736         }
737         char get_string[512] = "GET /curgamelist_1\n\n";
738         if (spNetSendHTTP(connection,get_string) == 0)
739         {
740                 spNetCloseTCP(connection);
741                 SDL_mutexP(gameData->task->statusMutex);
742                 gameData->task->status = SP_C4A_ERROR;
743                 SDL_mutexV(gameData->task->statusMutex);
744                 return 1;
745         }
746         //skeezix saves the top500. So 100 byte should be enough...
747         //Haha. NOT! minislug had 50950 with a top 500...
748         char buffer[100001]; 
749         int length;
750         if ((length = spNetReceiveHTTP(connection,buffer,100000)) == 0)
751         {
752                 spNetCloseTCP(connection);
753                 SDL_mutexP(gameData->task->statusMutex);
754                 gameData->task->status = SP_C4A_ERROR;
755                 SDL_mutexV(gameData->task->statusMutex);
756                 return 1;
757         }
758         buffer[length] = 0;
759         spNetCloseTCP(connection);
760         //Searching the first [
761         char* found = strchr( buffer, '[' );
762         if (found == NULL)
763         {
764                 SDL_mutexP(gameData->task->statusMutex);
765                 gameData->task->status = SP_C4A_ERROR;
766                 SDL_mutexV(gameData->task->statusMutex);
767                 return 1;
768         }
769         //Reading game by game
770         //Searching the starting {
771         while (found)
772         {
773                 char* start = strchr( found, '{' );
774                 if (start == NULL)
775                 {
776                         SDL_mutexP(gameData->task->statusMutex);
777                         gameData->task->status = SP_C4A_ERROR;
778                         SDL_mutexV(gameData->task->statusMutex);
779                         return 1;
780                 }
781                 char* end = my_strchr( start, '}', '\"'); //ignore "text}"-parts
782                 if (start == NULL)
783                 {
784                         SDL_mutexP(gameData->task->statusMutex);
785                         gameData->task->status = SP_C4A_ERROR;
786                         SDL_mutexV(gameData->task->statusMutex);
787                         return 1;
788                 }
789                 //Creating substring:
790                 end[0] = 0;
791                 //Now we search in the substring
792                 //Search for the long name:
793                 char* pos = strstr( start, "\"longname\":");
794                 pos+=11;
795                 char longname[256];
796                 fill_between_paraphrases( pos, longname, 128);
797                 
798                 pos = strstr( start, "\"gamename\":");
799                 pos+=11;
800                 char shortname[256];
801                 fill_between_paraphrases( pos, shortname, 128);
802                 
803                 pos = strstr( start, "\"genre\":");
804                 pos+=8;
805                 char genre[256];
806                 fill_between_paraphrases( pos, genre, 128);
807                 
808                 pos = strstr( start, "\"field\":");
809                 pos+=8;
810                 char field[256];
811                 fill_between_paraphrases( pos, field, 128);
812                 
813                 pos = strstr( start, "\"status\":");
814                 pos+=9;
815                 char status[256];
816                 fill_between_paraphrases( pos, status, 128);
817                 
818                 //Re"inserting" substring:
819                 end[0] = '}';
820                 found = strchr( end, '{' );
821                 
822                 //Adding the found stuff to the array:
823                 spNetC4AGamePointer new_game = (spNetC4AGamePointer)malloc(sizeof(spNetC4AGame));
824                 sprintf(new_game->longname,"%s",longname);
825                 sprintf(new_game->shortname,"%s",shortname);
826                 sprintf(new_game->genre,"%s",genre);
827                 if (strcmp(status,"available") == 0)
828                         new_game->status = 1;
829                 else
830                 if (strcmp(status,"active") == 0)
831                         new_game->status = 2;
832                 else
833                         new_game->status = 0;
834                 if (strcmp(field,"arcade") == 0)
835                         new_game->field = 1;
836                 else
837                 if (strcmp(field,"indie") == 0)
838                         new_game->field = 0;
839                 else
840                         new_game->field = -1;
841                 
842                 //sorted insert
843                 //Searching the next and before element:
844                 spNetC4AGamePointer before = NULL;
845                 spNetC4AGamePointer next = *(gameData->game);
846                 while (next)
847                 {
848                         if (strcmp(new_game->longname,next->longname) < 0)
849                                 break;
850                         before = next;
851                         next = next->next;
852                 }
853                 if (before == NULL) //new first element!
854                 {
855                         new_game->next = next;
856                         (*(gameData->game)) = new_game;
857                 }
858                 else
859                 {
860                         before->next = new_game;
861                         new_game->next = next;
862                 }
863         }       
864         SDL_mutexP(gameData->task->statusMutex);
865         gameData->task->status = SP_C4A_OK;
866         SDL_mutexV(gameData->task->statusMutex);
867         return 0;
868 }
869
870 PREFIX int spNetC4AGetGame(spNetC4AGamePointer* gameList,int timeOut)
871 {
872         (*gameList) = NULL;
873         SDL_mutexP(spGlobalC4ATask->statusMutex);
874         if (spGlobalC4ATask->status != SP_C4A_PROGRESS)
875         {
876                 spGlobalC4ATask->status = SP_C4A_PROGRESS;
877                 SDL_mutexV(spGlobalC4ATask->statusMutex);
878                 //Starting a background thread, which does the fancy stuff
879                 getgamePointer data = (getgamePointer)malloc(sizeof(getgameType));
880                 data->function = c4a_getgame_thread;
881                 data->task = spGlobalC4ATask;
882                 data->game = gameList;
883                 spGlobalC4ATask->dataPointer = data;
884                 spGlobalC4ATask->timeOut = timeOut;
885                 spGlobalC4ATask->threadStatus = 1;
886                 #ifdef _MSC_VER
887                         spGlobalC4ATask->thread = SDL_CreateThread((int (__cdecl *)(void *))spNetC4AUberThread,data);
888                 #else
889                         spGlobalC4ATask->thread = SDL_CreateThread(spNetC4AUberThread,data);
890                 #endif
891                 return 0;
892         }
893         SDL_mutexV(spGlobalC4ATask->statusMutex);
894         return 1;       
895 }
896
897 PREFIX spNetC4ATaskPointer spNetC4AGetGameParallel(spNetC4AGamePointer* gameList,int timeOut)
898 {
899         (*gameList) = NULL;
900         spNetC4ATaskPointer task = createNewC4ATask();
901         task->status = SP_C4A_PROGRESS;
902         //Starting a background thread, which does the fancy stuff
903         getgamePointer data = (getgamePointer)malloc(sizeof(getgameType));
904         data->function = c4a_getgame_thread;
905         data->task = task;
906         data->game = gameList;
907         task->dataPointer = data;
908         task->timeOut = timeOut;
909         task->threadStatus = 1;
910         #ifdef _MSC_VER
911                 task->thread = SDL_CreateThread((int (__cdecl *)(void *))spNetC4AUberThread,data);
912         #else
913                 task->thread = SDL_CreateThread(spNetC4AUberThread,data);
914         #endif
915         return task;
916 }
917
918 int c4a_getscore_thread(void* data)
919 {
920         getscorePointer scoreData = (getscorePointer)data;
921         spNetIP ip = spNetResolve("skeezix.wallednetworks.com",13001);
922         if (ip.address.ipv4 == SP_INVALID_IP)
923         {
924                 SDL_mutexP(scoreData->task->statusMutex);
925                 scoreData->task->status = SP_C4A_ERROR;
926                 SDL_mutexV(scoreData->task->statusMutex);
927                 return 1;
928         }       
929         spNetTCPConnection connection = spNetOpenClientTCP(ip);
930         if (connection == NULL)
931         {
932                 SDL_mutexP(scoreData->task->statusMutex);
933                 scoreData->task->status = SP_C4A_ERROR;
934                 SDL_mutexV(scoreData->task->statusMutex);
935                 return 1;
936         }
937         char get_string[512];
938         if (scoreData->year && scoreData->month)
939                 sprintf(get_string,"GET /json_1/%s/%i%02i/\n\n",scoreData->game,scoreData->year,scoreData->month);
940         else
941                 sprintf(get_string,"GET /json_1/%s/all\n\n",scoreData->game);
942         if (spNetSendHTTP(connection,get_string) == 0)
943         {
944                 spNetCloseTCP(connection);
945                 SDL_mutexP(scoreData->task->statusMutex);
946                 scoreData->task->status = SP_C4A_ERROR;
947                 SDL_mutexV(scoreData->task->statusMutex);
948                 return 1;
949         }
950         //skeezix saves the top500. So 100 byte should be enough...
951         //Haha. NOT! minislug had 50950 with a top 500...
952         char buffer[100001]; 
953         int length;
954         if ((length = spNetReceiveHTTP(connection,buffer,100000)) == 0)
955         {
956                 spNetCloseTCP(connection);
957                 SDL_mutexP(scoreData->task->statusMutex);
958                 scoreData->task->status = SP_C4A_ERROR;
959                 SDL_mutexV(scoreData->task->statusMutex);
960                 return 1;
961         }
962         buffer[length] = 0;
963         spNetCloseTCP(connection);
964         //Searching the first [
965         char* found = strchr( buffer, '[' );
966         if (found == NULL)
967         {
968                 SDL_mutexP(scoreData->task->statusMutex);
969                 scoreData->task->status = SP_C4A_ERROR;
970                 SDL_mutexV(scoreData->task->statusMutex);
971                 return 1;
972         }
973         //Reading score by score
974         //Searching the starting {
975         int rank = 1;
976         spNetC4AScorePointer lastScore = NULL;
977         while (found)
978         {
979                 char* start = strchr( found, '{' );
980                 if (start == NULL)
981                 {
982                         SDL_mutexP(scoreData->task->statusMutex);
983                         scoreData->task->status = SP_C4A_ERROR;
984                         SDL_mutexV(scoreData->task->statusMutex);
985                         return 1;
986                 }
987                 char* end = my_strchr( start, '}', '\"'); //ignore "text}"-parts
988                 if (start == NULL)
989                 {
990                         SDL_mutexP(scoreData->task->statusMutex);
991                         scoreData->task->status = SP_C4A_ERROR;
992                         SDL_mutexV(scoreData->task->statusMutex);
993                         return 1;
994                 }
995                 //Creating substring:
996                 end[0] = 0;
997                 //Now we search in the substring
998                 //Search for the long name:
999                 char* pos = strstr( start, "\"longname\":");
1000                 pos+=11;
1001                 char longname[128];
1002                 fill_between_paraphrases( pos, longname, 128);
1003                 
1004                 pos = strstr( start, "\"shortname\":");
1005                 pos+=12;
1006                 char shortname[128];
1007                 fill_between_paraphrases( pos, shortname, 128);
1008                 
1009                 pos = strstr( start, "\"score\":");
1010                 pos+=8;
1011                 int score = atoi(pos);
1012                 
1013                 pos = strstr( start, "\"time\":");
1014                 pos+=7;
1015                 Uint64 commitTime = (Uint64)(atof(pos)); //float becase of bigger numbers
1016                 
1017                 //Re"inserting" substring:
1018                 end[0] = '}';
1019                 found = strchr( end, '{' );
1020                 
1021                 //Adding the found stuff to the array:
1022                 if (longname[0] == 0 || shortname[0] == 0)
1023                         continue;
1024                 if (scoreData->profile && (strcmp(scoreData->profile->longname,longname) != 0 || strcmp(scoreData->profile->shortname,shortname) != 0))
1025                         continue;
1026                 spNetC4AScorePointer new_score = (spNetC4AScorePointer)malloc(sizeof(spNetC4AScore));
1027                 sprintf(new_score->longname,"%s",longname);
1028                 sprintf(new_score->shortname,"%s",shortname);
1029                 new_score->score = score;
1030                 new_score->commitTime = commitTime;
1031                 new_score->next = NULL;
1032                 new_score->rank = rank;
1033                 if (lastScore == NULL)
1034                         (*(scoreData->score)) = new_score;
1035                 else
1036                         lastScore->next = new_score;
1037                 lastScore = new_score;
1038                 rank++;
1039         }       
1040         
1041         SDL_mutexP(scoreData->task->statusMutex);
1042         scoreData->task->status = SP_C4A_OK;
1043         SDL_mutexV(scoreData->task->statusMutex);
1044         return 0;
1045 }
1046
1047 PREFIX void spNetC4ADeleteGames(spNetC4AGamePointer* gameList)
1048 {
1049         if (gameList == NULL)
1050                 return;
1051         while (*gameList)
1052         {
1053                 spNetC4AGamePointer next = (*gameList)->next;
1054                 free(*gameList);
1055                 (*gameList) = next;
1056         }
1057 }
1058
1059 PREFIX int spNetC4AGetScore(spNetC4AScorePointer* scoreList,spNetC4AProfilePointer profile,char* game,int timeOut)
1060 {
1061         (*scoreList) = NULL;
1062         SDL_mutexP(spGlobalC4ATask->statusMutex);
1063         if (spGlobalC4ATask->status != SP_C4A_PROGRESS)
1064         {
1065                 spGlobalC4ATask->status = SP_C4A_PROGRESS;
1066                 SDL_mutexV(spGlobalC4ATask->statusMutex);
1067                 //Starting a background thread, which does the fancy stuff
1068                 getscorePointer data = (getscorePointer)malloc(sizeof(getscoreType));
1069                 data->function = c4a_getscore_thread;
1070                 data->task = spGlobalC4ATask;
1071                 data->score = scoreList;
1072                 data->profile = profile;
1073                 data->year = 0;
1074                 data->month = 0;
1075                 sprintf(data->game,"%s",game);
1076                 spGlobalC4ATask->dataPointer = data;
1077                 spGlobalC4ATask->timeOut = timeOut;
1078                 spGlobalC4ATask->threadStatus = 1;
1079                 #ifdef _MSC_VER
1080                         spGlobalC4ATask->thread = SDL_CreateThread((int (__cdecl *)(void *))spNetC4AUberThread,data);
1081                 #else
1082                         spGlobalC4ATask->thread = SDL_CreateThread(spNetC4AUberThread,data);
1083                 #endif
1084                 return 0;
1085         }
1086         SDL_mutexV(spGlobalC4ATask->statusMutex);
1087         return 1;
1088 }
1089
1090 PREFIX int spNetC4AGetScoreOfMonth(spNetC4AScorePointer* scoreList,spNetC4AProfilePointer profile,char* game,int year,int month,int timeOut)
1091 {
1092         (*scoreList) = NULL;
1093         if (month < 1 || month > 12)
1094                 return 1;
1095         SDL_mutexP(spGlobalC4ATask->statusMutex);
1096         if (spGlobalC4ATask->status != SP_C4A_PROGRESS)
1097         {
1098                 spGlobalC4ATask->status = SP_C4A_PROGRESS;
1099                 SDL_mutexV(spGlobalC4ATask->statusMutex);
1100                 //Starting a background thread, which does the fancy stuff
1101                 getscorePointer data = (getscorePointer)malloc(sizeof(getscoreType));
1102                 data->function = c4a_getscore_thread;
1103                 data->task = spGlobalC4ATask;
1104                 data->score = scoreList;
1105                 data->profile = profile;
1106                 data->year = year;
1107                 data->month = month;
1108                 sprintf(data->game,"%s",game);
1109                 spGlobalC4ATask->dataPointer = data;
1110                 spGlobalC4ATask->timeOut = timeOut;
1111                 spGlobalC4ATask->threadStatus = 1;
1112                 #ifdef _MSC_VER
1113                         spGlobalC4ATask->thread = SDL_CreateThread((int (__cdecl *)(void *))spNetC4AUberThread,data);
1114                 #else
1115                         spGlobalC4ATask->thread = SDL_CreateThread(spNetC4AUberThread,data);
1116                 #endif
1117                 return 0;
1118         }
1119         SDL_mutexV(spGlobalC4ATask->statusMutex);
1120         return 1;
1121 }
1122
1123 PREFIX spNetC4ATaskPointer spNetC4AGetScoreParallel(spNetC4AScorePointer* scoreList,spNetC4AProfilePointer profile,char* game,int timeOut)
1124 {
1125         (*scoreList) = NULL;
1126         spNetC4ATaskPointer task = createNewC4ATask();
1127         task->status = SP_C4A_PROGRESS;
1128         //Starting a background thread, which does the fancy stuff
1129         getscorePointer data = (getscorePointer)malloc(sizeof(getscoreType));
1130         data->function = c4a_getscore_thread;
1131         data->task = task;
1132         data->score = scoreList;
1133         data->profile = profile;
1134         data->year = 0;
1135         data->month = 0;
1136         sprintf(data->game,"%s",game);
1137         task->dataPointer = data;
1138         task->timeOut = timeOut;
1139         task->threadStatus = 1;
1140         #ifdef _MSC_VER
1141                 task->thread = SDL_CreateThread((int (__cdecl *)(void *))spNetC4AUberThread,data);
1142         #else
1143                 task->thread = SDL_CreateThread(spNetC4AUberThread,data);
1144         #endif
1145         return task;
1146 }
1147
1148 PREFIX spNetC4ATaskPointer spNetC4AGetScoreOfMonthParallel(spNetC4AScorePointer* scoreList,spNetC4AProfilePointer profile,char* game,int year,int month,int timeOut)
1149 {
1150         (*scoreList) = NULL;
1151         if (month < 1 || month > 12)
1152                 return NULL;
1153         spNetC4ATaskPointer task = createNewC4ATask();
1154         task->status = SP_C4A_PROGRESS;
1155         SDL_mutexV(task->statusMutex);
1156         //Starting a background thread, which does the fancy stuff
1157         getscorePointer data = (getscorePointer)malloc(sizeof(getscoreType));
1158         data->function = c4a_getscore_thread;
1159         data->task = task;
1160         data->score = scoreList;
1161         data->profile = profile;
1162         data->year = year;
1163         data->month = month;
1164         sprintf(data->game,"%s",game);
1165         task->dataPointer = data;
1166         task->timeOut = timeOut;
1167         task->threadStatus = 1;
1168         #ifdef _MSC_VER
1169                 task->thread = SDL_CreateThread((int (__cdecl *)(void *))spNetC4AUberThread,data);
1170         #else
1171                 task->thread = SDL_CreateThread(spNetC4AUberThread,data);
1172         #endif
1173         return task;
1174 }
1175
1176 PREFIX void spNetC4AFilterScore(spNetC4AScorePointer* scoreList)
1177 {
1178         spNetC4AScorePointer mom = *scoreList;
1179         spNetC4AScorePointer before = NULL;
1180         while (mom)
1181         {
1182                 //Search for mom:
1183                 spNetC4AScorePointer inner = *scoreList;
1184                 while (inner != NULL && inner != mom)
1185                 {
1186                         if (strcmp(mom->longname,inner->longname) == 0 &&
1187                                 strcmp(mom->shortname,inner->shortname) == 0)
1188                                 break;
1189                         inner = inner->next;
1190                 }
1191                 spNetC4AScorePointer next = mom->next;
1192                 //already there!
1193                 if (inner != mom)
1194                 {
1195                         if (before)
1196                                 before->next = next;
1197                         free(mom);
1198                 }
1199                 else
1200                         before = mom;
1201                 mom = next;
1202         }
1203 }
1204
1205 static int do_the_real_c4a_commit(spNetIP ip,commitPointer commitData,char* game,char* system,char* prid,int score)
1206 {
1207         spNetTCPConnection connection = spNetOpenClientTCP(ip);
1208         if (connection == NULL)
1209                 return 1;
1210         char commit_string[2048];
1211         sprintf(commit_string,"PUT /plugtally_1/scoreonly/%s/%s/%s?score=%i HTTP/1.1\r\nHost: skeezix.wallednetworks.com:13001\r\nAccept: */*\r\nContent-Length: 0\r\nExpect: 100-continue\r\n",game,system,prid,score);
1212         if (spNetSendHTTP(connection,commit_string) == 0)
1213         {
1214                 spNetCloseTCP(connection);
1215                 return 1;
1216         }
1217         spNetCloseTCP(connection);
1218         //Adding to scoreList ;)
1219         if (commitData->scoreList)
1220         {
1221                 spNetC4AScorePointer new_score = (spNetC4AScorePointer)malloc(sizeof(spNetC4AScore));
1222                 sprintf(new_score->longname,"%s",commitData->profile->longname);
1223                 sprintf(new_score->shortname,"%s",commitData->profile->shortname);
1224                 new_score->score = score;
1225                 new_score->commitTime = time(NULL);
1226                 new_score->next = (*(commitData->scoreList));
1227                 (*(commitData->scoreList)) = new_score;
1228         }
1229         return 0;
1230 }
1231
1232
1233 #ifndef __GNUC__
1234         #include <windows.h>
1235         #include <tchar.h>
1236 #else
1237         #include <dirent.h>
1238         #include <sys/types.h>
1239         #include <sys/stat.h>
1240         #include <unistd.h>
1241 #endif
1242
1243 int c4a_commit_thread(void* data)
1244 {
1245         commitPointer commitData = (commitPointer)data;
1246         spNetIP ip = spNetResolve("skeezix.wallednetworks.com",13001);
1247         if (ip.address.ipv4 == SP_INVALID_IP)
1248         {
1249                 if (spNetC4ACaching && commitData->game[0] != 0)
1250                         write_to_cache(commitData->game,commitData->system,commitData->profile->prid,commitData->score,1);
1251                 SDL_mutexP(commitData->task->statusMutex);
1252                 commitData->task->status = SP_C4A_ERROR;
1253                 SDL_mutexV(commitData->task->statusMutex);
1254                 return 1;
1255         }
1256         if (commitData->game[0] != 0)
1257         {
1258                 if (do_the_real_c4a_commit(ip,commitData,commitData->game,commitData->system,commitData->profile->prid,commitData->score))
1259                 {
1260                         if (spNetC4ACaching)
1261                                 write_to_cache(commitData->game,commitData->system,commitData->profile->prid,commitData->score,1);
1262                         SDL_mutexP(commitData->task->statusMutex);
1263                         commitData->task->status = SP_C4A_ERROR;
1264                         SDL_mutexV(commitData->task->statusMutex);
1265                         return 1;
1266                 }
1267         }
1268         //Checking for stuff in the cache
1269         SDL_mutexP(spCacheMutex);
1270         cachePointer cache = read_cache();
1271         if (cache)
1272         {
1273                 while (cache)
1274                 {
1275                         cachePointer next = cache->next;
1276                         if (do_the_real_c4a_commit(ip,commitData,cache->game,cache->system,cache->prid,cache->score))
1277                                 break;
1278                         free(cache);
1279                         cache = next;
1280                         if (commitData->task->message == 1)
1281                         {
1282                                 commitData->task->message = 2;
1283                                 break;
1284                         }
1285                 }
1286                 #ifdef WIN32
1287                         DeleteFile(spCacheFilename);
1288                 #else
1289                         remove(spCacheFilename);
1290                 #endif
1291                 //if cache is still existing, we need to write back the rest of the cache
1292                 while (cache)
1293                 {
1294                         cachePointer next = cache->next;
1295                         write_to_cache(cache->game,cache->system,cache->prid,cache->score,0);
1296                         free(cache);
1297                         cache = next;
1298                 }
1299                         
1300         }
1301         SDL_mutexV(spCacheMutex);
1302         
1303         SDL_mutexP(commitData->task->statusMutex);
1304         commitData->task->status = SP_C4A_OK;
1305         SDL_mutexV(commitData->task->statusMutex);
1306         return 0;
1307 }
1308
1309 PREFIX int spNetC4AHowManyCached()
1310 {
1311         int result = 0;
1312         SDL_mutexP(spCacheMutex);
1313         SDL_RWops *file = SDL_RWFromFile(spCacheFilename, "rb");
1314         if (file)
1315         {
1316                 char buffer[256*3+sizeof(int)];
1317                 while (1)
1318                 {
1319                         if (SDL_RWread(file,buffer,256*3+sizeof(int),1) <= 0)
1320                                 break;
1321                         result++;
1322                 }
1323                 SDL_RWclose(file);
1324         }
1325         SDL_mutexV(spCacheMutex);
1326         return result;
1327 }
1328
1329 int already_in_highscore(spNetC4AScorePointer scoreList,spNetC4AProfilePointer profile,int score)
1330 {
1331         if (scoreList == NULL)
1332                 return 0;
1333         while (scoreList)
1334         {
1335                 if (strcmp(scoreList->longname,profile->longname) == 0 &&
1336                     strcmp(scoreList->shortname,profile->shortname) == 0 &&
1337                     scoreList->score == score)
1338                         return 1;
1339                 scoreList = scoreList->next;
1340         }
1341         return 0;
1342 }
1343
1344 #ifdef GP2X
1345         #define SET_SYSTEM(system) sprintf(system,"gp2x");
1346 #elif defined(CAANOO)
1347         #define SET_SYSTEM(system) sprintf(system,"caanoo");
1348 #elif defined(WIZ)
1349         #define SET_SYSTEM(system) sprintf(system,"wiz");
1350 #elif defined(DINGUX)
1351         #define SET_SYSTEM(system) sprintf(system,"dingux");
1352 #elif defined(GCW)      
1353         #define SET_SYSTEM(system) sprintf(system,"gcw");
1354 #elif defined(PANDORA)  
1355         #define SET_SYSTEM(system) sprintf(system,"pandora");
1356 #elif defined(WIN32)
1357         #define SET_SYSTEM(system) sprintf(system,"win32");
1358 #else
1359         #define SET_SYSTEM(system) sprintf(system,"linux");
1360 #endif
1361
1362
1363 PREFIX int spNetC4ACommitScore(spNetC4AProfilePointer profile,char* game,int score,spNetC4AScorePointer* scoreList,int timeOut)
1364 {
1365         if (profile == NULL && game[0]!=0)
1366                 return 1;
1367         int already = 0;
1368         if (scoreList && already_in_highscore(*scoreList,profile,score))
1369                 already = 1;
1370         if (timeOut == 0)
1371         {
1372                 if (already == 0 && spNetC4ACaching)
1373                 {
1374                         char system[256];
1375                         SET_SYSTEM(system);
1376                         write_to_cache(game,system,profile->prid,score,1);                      
1377                 }
1378                 return 1;
1379         }
1380         SDL_mutexP(spGlobalC4ATask->statusMutex);
1381         if (spGlobalC4ATask->status != SP_C4A_PROGRESS)
1382         {
1383                 spGlobalC4ATask->status = SP_C4A_PROGRESS;
1384                 SDL_mutexV(spGlobalC4ATask->statusMutex);
1385                 //Starting a background thread, which does the fancy stuff
1386                 commitPointer data = (commitPointer)malloc(sizeof(commitType));
1387                 data->task = spGlobalC4ATask;
1388                 data->function = c4a_commit_thread;
1389                 data->score = score;
1390                 data->profile = profile;
1391                 data->scoreList = scoreList;
1392                 if (already)
1393                         data->game[0] = 0;
1394                 else
1395                         sprintf(data->game,"%s",game);
1396                 SET_SYSTEM(data->system);
1397                 spGlobalC4ATask->dataPointer = data;
1398                 spGlobalC4ATask->timeOut = timeOut;
1399                 spGlobalC4ATask->threadStatus = 1;
1400                 #ifdef _MSC_VER
1401                         spGlobalC4ATask->thread = SDL_CreateThread((int (__cdecl *)(void *))spNetC4AUberThread,data);
1402                 #else
1403                         spGlobalC4ATask->thread = SDL_CreateThread(spNetC4AUberThread,data);
1404                 #endif
1405                 return already;
1406         }
1407         SDL_mutexV(spGlobalC4ATask->statusMutex);
1408         return 1;
1409 }
1410
1411 PREFIX spNetC4ATaskPointer spNetC4ACommitScoreParallel(spNetC4AProfilePointer profile,char* game,int score,spNetC4AScorePointer* scoreList,int timeOut)
1412 {
1413         if (profile == NULL)
1414                 return NULL;
1415         int already = 0;
1416         if (scoreList && already_in_highscore(*scoreList,profile,score))
1417                 already = 1;
1418         if (timeOut == 0)
1419         {
1420                 if (already == 0 && spNetC4ACaching)
1421                 {
1422                         char system[256];
1423                         SET_SYSTEM(system);
1424                         write_to_cache(game,system,profile->prid,score,1);                      
1425                 }
1426                 return NULL;
1427         }
1428         spNetC4ATaskPointer task = createNewC4ATask();
1429         task->status = SP_C4A_PROGRESS;
1430         //Starting a background thread, which does the fancy stuff
1431         commitPointer data = (commitPointer)malloc(sizeof(commitType));
1432         data->task = task;
1433         data->function = c4a_commit_thread;
1434         data->score = score;
1435         data->profile = profile;
1436         data->scoreList = scoreList;
1437         if (already)
1438                 data->game[0] = 0;
1439         else
1440                 sprintf(data->game,"%s",game);
1441         SET_SYSTEM(data->system);
1442         task->dataPointer = data;
1443         task->timeOut = timeOut;
1444         task->threadStatus = 1;
1445         #ifdef _MSC_VER
1446                 task->thread = SDL_CreateThread((int (__cdecl *)(void *))spNetC4AUberThread,data);
1447         #else
1448                 task->thread = SDL_CreateThread(spNetC4AUberThread,data);
1449         #endif
1450         return task;
1451 }
1452
1453 PREFIX void spNetC4ACopyScoreList(spNetC4AScorePointer* scoreList,spNetC4AScorePointer* newList)
1454 {
1455         if (scoreList == NULL)
1456                 return;
1457         if (newList == NULL)
1458                 return;
1459         spNetC4AScorePointer mom = *scoreList;
1460         spNetC4AScorePointer last = NULL;
1461         while (mom)
1462         {
1463                 spNetC4AScorePointer copy_score = (spNetC4AScorePointer)malloc(sizeof(spNetC4AScore));
1464                 sprintf(copy_score->longname,"%s",mom->longname);
1465                 sprintf(copy_score->shortname,"%s",mom->shortname);
1466                 copy_score->score = mom->score;
1467                 copy_score->commitTime = mom->commitTime;
1468                 copy_score->rank = mom->rank;
1469                 if (last)
1470                         last->next = copy_score;
1471                 else
1472                         *newList = copy_score;
1473                 last = copy_score;
1474                 mom = mom->next;
1475         }
1476         if (last)
1477                 last->next = NULL;
1478         else
1479                 *newList = NULL;
1480 }
1481
1482 typedef struct __ScoreNameStruct *__ScoreNamePointer;
1483 typedef struct __ScoreNameStruct {
1484         char longname[256];
1485         char shortname[256];
1486         __ScoreNamePointer next;
1487 } __ScoreName;
1488
1489 PREFIX void spNetC4AMakeScoresUnique(spNetC4AScorePointer* scoreList)
1490 {
1491         if (scoreList == NULL)
1492                 return;
1493         spNetC4AScorePointer mom = *scoreList;
1494         spNetC4AScorePointer before = NULL;
1495         __ScoreNamePointer name = NULL;
1496         __ScoreNamePointer searchStart = NULL;
1497         while (mom)
1498         {
1499                 //search mom in name:
1500                 __ScoreNamePointer search = searchStart;
1501                 while (search)
1502                 {
1503                         if (strcmp(mom->shortname,search->shortname) == 0 &&
1504                                 strcmp(mom->longname,search->longname) == 0 )
1505                                 break; //found
1506                         search = search->next;
1507                 }
1508                 if (search) //found -> remove
1509                 {
1510                         spNetC4AScorePointer next = mom->next;
1511                         before->next = next;
1512                         free(mom);
1513                         mom = next;
1514                 }
1515                 else //add
1516                 {
1517                         __ScoreNamePointer add = (__ScoreNamePointer)malloc(sizeof(__ScoreName));
1518                         sprintf(add->longname,"%s",mom->longname);
1519                         sprintf(add->shortname,"%s",mom->shortname);
1520                         add->next = searchStart;
1521                         searchStart = add;
1522                         before = mom;
1523                         mom = mom->next;
1524                 }
1525         }
1526         while (searchStart)
1527         {
1528                 __ScoreNamePointer next = searchStart->next;
1529                 free(searchStart);
1530                 searchStart = next;
1531         }
1532 }
1533
1534 PREFIX void spNetC4ADeleteScores(spNetC4AScorePointer* scoreList)
1535 {
1536         if (scoreList == NULL)
1537                 return;
1538         while (*scoreList)
1539         {
1540                 spNetC4AScorePointer next = (*scoreList)->next;
1541                 free(*scoreList);
1542                 (*scoreList) = next;
1543         }
1544 }
1545
1546 void fill_with_random_hex(char* buffer,int count)
1547 {
1548         int i;
1549         for (i = 0; i < count; i++)
1550         {
1551                 int c = rand()%16;
1552                 char cha;
1553                 if (c < 10)
1554                         cha = c+'0';
1555                 else
1556                         cha = c-10+'a';
1557                 buffer[i] = cha;
1558         }
1559 }
1560
1561 int c4a_create_thread(void* data)
1562 {
1563         createPointer createData = (createPointer)data;
1564         spNetIP ip = spNetResolve("skeezix.wallednetworks.com",13001);
1565         if (ip.address.ipv4 == SP_INVALID_IP)
1566         {
1567                 SDL_mutexP(createData->task->statusMutex);
1568                 createData->task->status = SP_C4A_ERROR;
1569                 SDL_mutexV(createData->task->statusMutex);
1570                 return 1;
1571         }       
1572         spNetTCPConnection connection = spNetOpenClientTCP(ip);
1573         if (connection == NULL)
1574         {
1575                 SDL_mutexP(createData->task->statusMutex);
1576                 createData->task->status = SP_C4A_ERROR;
1577                 SDL_mutexV(createData->task->statusMutex);
1578                 return 1;
1579         }
1580         char create_string[2048];
1581         char buffer[2048];
1582         char prid[37] = "";
1583         //generating a new, random prid:
1584         fill_with_random_hex(prid,8);
1585         prid[ 8]='-';
1586         fill_with_random_hex(&(prid[ 9]),4);
1587         prid[13]='-';
1588         fill_with_random_hex(&(prid[14]),4);
1589         prid[18]='-';
1590         fill_with_random_hex(&(prid[19]),4);
1591         prid[23]='-';
1592         fill_with_random_hex(&(prid[24]),12);
1593         prid[36]=0;
1594         sprintf(create_string,"{\"email\": \"%s\", \"shortname\": \"%s\", \"password\": \"%s\", \"prid\": \"%s\", \"longname\": \"%s\"}",createData->email,createData->shortname,createData->password,prid,createData->longname);
1595         sprintf(buffer,"PUT /setprofile_1 HTTP/1.1\r\nUser-Agent: sparrowNet/1.0\r\nHost: %i.%i.%i.%i:13001\r\nAccept: */*\r\nContent-Length: %i\r\nExpect: 100-continue\r\n\r\n",ip.address.ipv4_bytes[0],ip.address.ipv4_bytes[1],ip.address.ipv4_bytes[2],ip.address.ipv4_bytes[3],strlen(create_string));
1596         if (spNetSendTCP(connection,buffer,strlen(buffer)) == 0)
1597         {
1598                 spNetCloseTCP(connection);
1599                 SDL_mutexP(createData->task->statusMutex);
1600                 createData->task->status = SP_C4A_ERROR;
1601                 SDL_mutexV(createData->task->statusMutex);
1602                 return 1;
1603         }
1604         if (spNetSendTCP(connection,create_string,strlen(create_string)) == 0)
1605         {
1606                 spNetCloseTCP(connection);
1607                 SDL_mutexP(createData->task->statusMutex);
1608                 createData->task->status = SP_C4A_ERROR;
1609                 SDL_mutexV(createData->task->statusMutex);
1610                 return 1;
1611         }
1612         spNetCloseTCP(connection);
1613         PROFILE_FILENAME_MAKRO
1614         SDL_RWops *file=SDL_RWFromFile(filename,"wb");
1615         SDL_RWwrite(file,prid,36,1);
1616         char c = '\n';
1617         SDL_RWwrite(file,&c,1,1);
1618         SDL_RWwrite(file,create_string,strlen(create_string),1);
1619         SDL_RWclose(file);
1620         (*(createData->profile)) = (spNetC4AProfilePointer)malloc(sizeof(spNetC4AProfile));
1621         sprintf((*(createData->profile))->longname,"%s",createData->longname);
1622         sprintf((*(createData->profile))->shortname,"%s",createData->shortname);
1623         sprintf((*(createData->profile))->password,"%s",createData->password);
1624         sprintf((*(createData->profile))->email,"%s",createData->email);
1625         sprintf((*(createData->profile))->prid,"%s",prid);
1626         SDL_mutexP(createData->task->statusMutex);
1627         createData->task->status = SP_C4A_OK;
1628         SDL_mutexV(createData->task->statusMutex);
1629         return 0;       
1630 }
1631
1632 PREFIX int spNetC4ACreateProfile(spNetC4AProfilePointer* profile, char* longname,char* shortname,char* password,char* email,int timeOut)
1633 {
1634         if (profile == NULL)
1635                 return 1;
1636         SDL_mutexP(spGlobalC4ATask->statusMutex);
1637         if (spGlobalC4ATask->status != SP_C4A_PROGRESS)
1638         {
1639                 spGlobalC4ATask->status = SP_C4A_PROGRESS;
1640                 SDL_mutexV(spGlobalC4ATask->statusMutex);
1641                 //Starting a background thread, which does the fancy stuff
1642                 createPointer data = (createPointer)malloc(sizeof(createType));
1643                 data->task = spGlobalC4ATask;
1644                 data->function = c4a_create_thread;
1645                 data->profile = profile;
1646                 sprintf(data->longname,"%s",longname);
1647                 sprintf(data->shortname,"%s",shortname);
1648                 sprintf(data->password,"%s",password);
1649                 sprintf(data->email,"%s",email);
1650                 spGlobalC4ATask->dataPointer = data;
1651                 spGlobalC4ATask->timeOut = timeOut;
1652                 spGlobalC4ATask->threadStatus = 1;
1653                 #ifdef _MSC_VER
1654                         spGlobalC4ATask->thread = SDL_CreateThread((int (__cdecl *)(void *))spNetC4AUberThread,data);
1655                 #else
1656                         spGlobalC4ATask->thread = SDL_CreateThread(spNetC4AUberThread,data);
1657                 #endif
1658                 return 0;
1659         }
1660         SDL_mutexV(spGlobalC4ATask->statusMutex);
1661         return 1;
1662 }
1663
1664 int c4a_delete_thread(void* data)
1665 {
1666         createPointer createData = (createPointer)data;
1667         spNetIP ip = spNetResolve("skeezix.wallednetworks.com",13001);
1668         if (ip.address.ipv4 == SP_INVALID_IP)
1669         {
1670                 SDL_mutexP(createData->task->statusMutex);
1671                 createData->task->status = SP_C4A_ERROR;
1672                 SDL_mutexV(createData->task->statusMutex);
1673                 return 1;
1674         }       
1675         spNetTCPConnection connection = spNetOpenClientTCP(ip);
1676         if (connection == NULL)
1677         {
1678                 SDL_mutexP(createData->task->statusMutex);
1679                 createData->task->status = SP_C4A_ERROR;
1680                 SDL_mutexV(createData->task->statusMutex);
1681                 return 1;
1682         }
1683         char create_string[2048];
1684         char buffer[2048];
1685         sprintf(create_string,"{\"email\": \"%s\", \"shortname\": \"%s\", \"password\": \"%s\", \"prid\": \"%s\", \"longname\": \"%s\"}",(*(createData->profile))->email,(*(createData->profile))->shortname,(*(createData->profile))->password,(*(createData->profile))->prid,(*(createData->profile))->longname);
1686         sprintf(buffer,"PUT /delprofile_1 HTTP/1.1\r\nUser-Agent: sparrowNet/1.0\r\nHost: %i.%i.%i.%i:13001\r\nAccept: */*\r\nContent-Length: %i\r\nExpect: 100-continue\r\n\r\n",ip.address.ipv4_bytes[0],ip.address.ipv4_bytes[1],ip.address.ipv4_bytes[2],ip.address.ipv4_bytes[3],strlen(create_string));
1687         if (spNetSendTCP(connection,buffer,strlen(buffer)) == 0)
1688         {
1689                 spNetCloseTCP(connection);
1690                 SDL_mutexP(createData->task->statusMutex);
1691                 createData->task->status = SP_C4A_ERROR;
1692                 SDL_mutexV(createData->task->statusMutex);
1693                 return 1;
1694         }
1695         if (spNetSendTCP(connection,create_string,strlen(create_string)) == 0)
1696         {
1697                 spNetCloseTCP(connection);
1698                 SDL_mutexP(createData->task->statusMutex);
1699                 createData->task->status = SP_C4A_ERROR;
1700                 SDL_mutexV(createData->task->statusMutex);
1701                 return 1;
1702         }
1703         spNetCloseTCP(connection);
1704         (*(createData->profile)) = NULL;        
1705         if (createData->deleteFile)
1706                 spNetC4ADeleteProfileFile();
1707         SDL_mutexP(createData->task->statusMutex);
1708         createData->task->status = SP_C4A_OK;
1709         SDL_mutexV(createData->task->statusMutex);
1710         return 0;
1711 }
1712
1713 PREFIX int spNetC4ADeleteAccount(spNetC4AProfilePointer* profile,int deleteFile,int timeOut)
1714 {
1715         if (profile == NULL)
1716                 return 1;
1717         SDL_mutexP(spGlobalC4ATask->statusMutex);
1718         if (spGlobalC4ATask->status != SP_C4A_PROGRESS)
1719         {
1720                 spGlobalC4ATask->status = SP_C4A_PROGRESS;
1721                 SDL_mutexV(spGlobalC4ATask->statusMutex);
1722                 //Starting a background thread, which does the fancy stuff
1723                 createPointer data = (createPointer)malloc(sizeof(createType));
1724                 data->task = spGlobalC4ATask;
1725                 data->function = c4a_delete_thread;
1726                 data->profile = profile;
1727                 data->deleteFile = deleteFile;
1728                 spGlobalC4ATask->dataPointer = data;
1729                 spGlobalC4ATask->timeOut = timeOut;
1730                 spGlobalC4ATask->threadStatus = 1;
1731                 #ifdef _MSC_VER
1732                         spGlobalC4ATask->thread = SDL_CreateThread((int (__cdecl *)(void *))spNetC4AUberThread,c4a_delete_thread);
1733                 #else
1734                         spGlobalC4ATask->thread = SDL_CreateThread(spNetC4AUberThread,c4a_delete_thread);
1735                 #endif
1736                 return 0;
1737         }
1738         SDL_mutexV(spGlobalC4ATask->statusMutex);
1739         return 1;
1740 }
1741
1742 PREFIX void spNetC4ADeleteProfileFile()
1743 {
1744         PROFILE_FILENAME_MAKRO
1745 //Copied from spRemoveFile to avoid dependencies
1746 #ifdef WIN32
1747         DeleteFile(filename);
1748 #else
1749         remove(filename);
1750 #endif  
1751 }
1752
1753 int c4a_edit_thread(void* data)
1754 {
1755         createPointer createData = (createPointer)data;
1756         spNetIP ip = spNetResolve("skeezix.wallednetworks.com",13001);
1757         if (ip.address.ipv4 == SP_INVALID_IP)
1758         {
1759                 SDL_mutexP(createData->task->statusMutex);
1760                 createData->task->status = SP_C4A_ERROR;
1761                 SDL_mutexV(createData->task->statusMutex);
1762                 return 1;
1763         }       
1764         spNetTCPConnection connection = spNetOpenClientTCP(ip);
1765         if (connection == NULL)
1766         {
1767                 SDL_mutexP(createData->task->statusMutex);
1768                 createData->task->status = SP_C4A_ERROR;
1769                 SDL_mutexV(createData->task->statusMutex);
1770                 return 1;
1771         }
1772         char create_string[2048];
1773         char buffer[2048];
1774         sprintf(create_string,"{\"email\": \"%s\", \"shortname\": \"%s\", \"password\": \"%s\", \"prid\": \"%s\", \"longname\": \"%s\"}",createData->email,createData->shortname,createData->password,(*(createData->profile))->prid,createData->longname);
1775         sprintf(buffer,"PUT /setprofile_1 HTTP/1.1\r\nUser-Agent: sparrowNet/1.0\r\nHost: %i.%i.%i.%i:13001\r\nAccept: */*\r\nContent-Length: %i\r\nExpect: 100-continue\r\n\r\n",ip.address.ipv4_bytes[0],ip.address.ipv4_bytes[1],ip.address.ipv4_bytes[2],ip.address.ipv4_bytes[3],strlen(create_string));
1776         if (spNetSendTCP(connection,buffer,strlen(buffer)) == 0)
1777         {
1778                 spNetCloseTCP(connection);
1779                 SDL_mutexP(createData->task->statusMutex);
1780                 createData->task->status = SP_C4A_ERROR;
1781                 SDL_mutexV(createData->task->statusMutex);
1782                 return 1;
1783         }
1784         if (spNetSendTCP(connection,create_string,strlen(create_string)) == 0)
1785         {
1786                 spNetCloseTCP(connection);
1787                 SDL_mutexP(createData->task->statusMutex);
1788                 createData->task->status = SP_C4A_ERROR;
1789                 SDL_mutexV(createData->task->statusMutex);
1790                 return 1;
1791         }
1792         spNetCloseTCP(connection);
1793         PROFILE_FILENAME_MAKRO
1794         SDL_RWops *file=SDL_RWFromFile(filename,"wb");
1795         SDL_RWwrite(file,(*(createData->profile))->prid,strlen((*(createData->profile))->prid),1);
1796         char c = '\n';
1797         SDL_RWwrite(file,&c,1,1);
1798         SDL_RWwrite(file,create_string,strlen(create_string),1);
1799         SDL_RWclose(file);
1800         sprintf((*(createData->profile))->longname,"%s",createData->longname);
1801         sprintf((*(createData->profile))->shortname,"%s",createData->shortname);
1802         sprintf((*(createData->profile))->password,"%s",createData->password);
1803         sprintf((*(createData->profile))->email,"%s",createData->email);
1804         SDL_mutexP(createData->task->statusMutex);
1805         createData->task->status = SP_C4A_OK;
1806         SDL_mutexV(createData->task->statusMutex);
1807         return 0;       
1808 }
1809
1810 PREFIX int spNetC4AEditProfile(spNetC4AProfilePointer* profile,char* longname,char* shortname,char* password,char* email,int timeOut)
1811 {
1812         if (profile == NULL)
1813                 return 1;
1814         SDL_mutexP(spGlobalC4ATask->statusMutex);
1815         if (spGlobalC4ATask->status != SP_C4A_PROGRESS)
1816         {
1817                 spGlobalC4ATask->status = SP_C4A_PROGRESS;
1818                 SDL_mutexV(spGlobalC4ATask->statusMutex);
1819                 //Starting a background thread, which does the fancy stuff
1820                 createPointer data = (createPointer)malloc(sizeof(createType));
1821                 data->task = spGlobalC4ATask;
1822                 data->function = c4a_edit_thread;
1823                 data->profile = profile;
1824                 sprintf(data->longname,"%s",longname);
1825                 sprintf(data->shortname,"%s",shortname);
1826                 sprintf(data->password,"%s",password);
1827                 sprintf(data->email,"%s",email);
1828                 spGlobalC4ATask->dataPointer = data;
1829                 spGlobalC4ATask->timeOut = timeOut;
1830                 spGlobalC4ATask->threadStatus = 1;
1831                 #ifdef _MSC_VER
1832                         spGlobalC4ATask->thread = SDL_CreateThread((int (__cdecl *)(void *))spNetC4AUberThread,data);
1833                 #else
1834                         spGlobalC4ATask->thread = SDL_CreateThread(spNetC4AUberThread,data);
1835                 #endif
1836                 return 0;
1837         }
1838         SDL_mutexV(spGlobalC4ATask->statusMutex);
1839         return 1;
1840 }
1841
1842 PREFIX int spNetC4AGetStatusParallel(spNetC4ATaskPointer task)
1843 {
1844         SDL_mutexP(task->statusMutex);
1845         if (task->threadStatus)
1846         {
1847                 SDL_mutexV(task->statusMutex);
1848                 return SP_C4A_PROGRESS;
1849         }
1850         int status = task->status;
1851         SDL_mutexV(task->statusMutex);
1852         return status;
1853 }
1854
1855 PREFIX int spNetC4AGetStatus()
1856 {
1857         return spNetC4AGetStatusParallel(spGlobalC4ATask);
1858 }
1859
1860 PREFIX void spNetC4ACancelTaskParallel(spNetC4ATaskPointer task)
1861 {
1862         SDL_mutexP(task->statusMutex);
1863         if (task->status > 0)
1864         {
1865                 task->status = SP_C4A_CANCELED;
1866                 SDL_mutexV(task->statusMutex);
1867                 SDL_WaitThread(task->thread,NULL);
1868         }
1869         else
1870                 SDL_mutexV(task->statusMutex);
1871 }
1872
1873 PREFIX void spNetC4ACancelTask()
1874 {
1875         spNetC4ACancelTaskParallel(spGlobalC4ATask);
1876 }
1877
1878 PREFIX int spNetC4AGetTaskResult()
1879 {
1880         return spGlobalC4ATask->result;
1881 }
1882
1883 PREFIX int spNetC4AGetTaskResultParallel(spNetC4ATaskPointer task)
1884 {
1885         return task->result;
1886 }
1887
1888 PREFIX int spNetC4AGetTimeOut()
1889 {
1890         return spGlobalC4ATask->timeOut;
1891 }
1892
1893 PREFIX int spNetC4AGetTimeOutParallel(spNetC4ATaskPointer task)
1894 {
1895         return task->timeOut;
1896 }