fusilli-client: update
[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 DESKTOP && !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                 if (cache)
1293                 {
1294                         SDL_RWops *file = SDL_RWFromFile(spCacheFilename, "ab");
1295                         while (cache)
1296                         {
1297                                 cachePointer next = cache->next;
1298                                 SDL_RWwrite(file,cache->game,256,1);
1299                                 SDL_RWwrite(file,cache->system,256,1);
1300                                 SDL_RWwrite(file,cache->prid,256,1);
1301                                 SDL_RWwrite(file,&(cache->score),sizeof(int),1);
1302                                 free(cache);
1303                                 cache = next;
1304                         }
1305                         SDL_RWclose(file);
1306                 }
1307                         
1308         }
1309         SDL_mutexV(spCacheMutex);
1310         
1311         SDL_mutexP(commitData->task->statusMutex);
1312         commitData->task->status = SP_C4A_OK;
1313         SDL_mutexV(commitData->task->statusMutex);
1314         return 0;
1315 }
1316
1317 PREFIX int spNetC4AHowManyCached()
1318 {
1319         int result = 0;
1320         SDL_mutexP(spCacheMutex);
1321         SDL_RWops *file = SDL_RWFromFile(spCacheFilename, "rb");
1322         if (file)
1323         {
1324                 char buffer[256*3+sizeof(int)];
1325                 while (1)
1326                 {
1327                         if (SDL_RWread(file,buffer,256*3+sizeof(int),1) <= 0)
1328                                 break;
1329                         result++;
1330                 }
1331                 SDL_RWclose(file);
1332         }
1333         SDL_mutexV(spCacheMutex);
1334         return result;
1335 }
1336
1337 int already_in_highscore(spNetC4AScorePointer scoreList,spNetC4AProfilePointer profile,int score)
1338 {
1339         if (scoreList == NULL)
1340                 return 0;
1341         while (scoreList)
1342         {
1343                 if (strcmp(scoreList->longname,profile->longname) == 0 &&
1344                     strcmp(scoreList->shortname,profile->shortname) == 0 &&
1345                     scoreList->score == score)
1346                         return 1;
1347                 scoreList = scoreList->next;
1348         }
1349         return 0;
1350 }
1351
1352 #ifdef GP2X
1353         #define SET_SYSTEM(system) sprintf(system,"gp2x");
1354 #elif defined(CAANOO)
1355         #define SET_SYSTEM(system) sprintf(system,"caanoo");
1356 #elif defined(WIZ)
1357         #define SET_SYSTEM(system) sprintf(system,"wiz");
1358 #elif defined(DINGUX)
1359         #define SET_SYSTEM(system) sprintf(system,"dingux");
1360 #elif defined(GCW)      
1361         #define SET_SYSTEM(system) sprintf(system,"gcw");
1362 #elif defined(PANDORA)  
1363         #define SET_SYSTEM(system) sprintf(system,"pandora");
1364 #elif defined(_WIN32)
1365         #define SET_SYSTEM(system) sprintf(system,"win32");
1366 #else
1367         #define SET_SYSTEM(system) sprintf(system,"linux");
1368 #endif
1369
1370
1371 PREFIX int spNetC4ACommitScore(spNetC4AProfilePointer profile,char* game,int score,spNetC4AScorePointer* scoreList,int timeOut)
1372 {
1373         if (profile == NULL && game[0]!=0)
1374                 return 1;
1375         int already = 0;
1376         if (scoreList && already_in_highscore(*scoreList,profile,score))
1377                 already = 1;
1378         if (timeOut == 0)
1379         {
1380                 if (already == 0 && spNetC4ACaching)
1381                 {
1382                         char system[256];
1383                         SET_SYSTEM(system);
1384                         write_to_cache(game,system,profile->prid,score,1);                      
1385                 }
1386                 return 1;
1387         }
1388         SDL_mutexP(spGlobalC4ATask->statusMutex);
1389         if (spGlobalC4ATask->status != SP_C4A_PROGRESS)
1390         {
1391                 spGlobalC4ATask->status = SP_C4A_PROGRESS;
1392                 SDL_mutexV(spGlobalC4ATask->statusMutex);
1393                 //Starting a background thread, which does the fancy stuff
1394                 commitPointer data = (commitPointer)malloc(sizeof(commitType));
1395                 data->task = spGlobalC4ATask;
1396                 data->function = c4a_commit_thread;
1397                 data->score = score;
1398                 data->profile = profile;
1399                 data->scoreList = scoreList;
1400                 if (already)
1401                         data->game[0] = 0;
1402                 else
1403                         sprintf(data->game,"%s",game);
1404                 SET_SYSTEM(data->system);
1405                 spGlobalC4ATask->dataPointer = data;
1406                 spGlobalC4ATask->timeOut = timeOut;
1407                 spGlobalC4ATask->threadStatus = 1;
1408                 #ifdef _MSC_VER
1409                         spGlobalC4ATask->thread = SDL_CreateThread((int (__cdecl *)(void *))spNetC4AUberThread,data);
1410                 #else
1411                         spGlobalC4ATask->thread = SDL_CreateThread(spNetC4AUberThread,data);
1412                 #endif
1413                 return already;
1414         }
1415         SDL_mutexV(spGlobalC4ATask->statusMutex);
1416         return 1;
1417 }
1418
1419 PREFIX spNetC4ATaskPointer spNetC4ACommitScoreParallel(spNetC4AProfilePointer profile,char* game,int score,spNetC4AScorePointer* scoreList,int timeOut)
1420 {
1421         if (profile == NULL)
1422                 return NULL;
1423         int already = 0;
1424         if (scoreList && already_in_highscore(*scoreList,profile,score))
1425                 already = 1;
1426         if (timeOut == 0)
1427         {
1428                 if (already == 0 && spNetC4ACaching)
1429                 {
1430                         char system[256];
1431                         SET_SYSTEM(system);
1432                         write_to_cache(game,system,profile->prid,score,1);                      
1433                 }
1434                 return NULL;
1435         }
1436         spNetC4ATaskPointer task = createNewC4ATask();
1437         task->status = SP_C4A_PROGRESS;
1438         //Starting a background thread, which does the fancy stuff
1439         commitPointer data = (commitPointer)malloc(sizeof(commitType));
1440         data->task = task;
1441         data->function = c4a_commit_thread;
1442         data->score = score;
1443         data->profile = profile;
1444         data->scoreList = scoreList;
1445         if (already)
1446                 data->game[0] = 0;
1447         else
1448                 sprintf(data->game,"%s",game);
1449         SET_SYSTEM(data->system);
1450         task->dataPointer = data;
1451         task->timeOut = timeOut;
1452         task->threadStatus = 1;
1453         #ifdef _MSC_VER
1454                 task->thread = SDL_CreateThread((int (__cdecl *)(void *))spNetC4AUberThread,data);
1455         #else
1456                 task->thread = SDL_CreateThread(spNetC4AUberThread,data);
1457         #endif
1458         return task;
1459 }
1460
1461 PREFIX void spNetC4ACopyScoreList(spNetC4AScorePointer* scoreList,spNetC4AScorePointer* newList)
1462 {
1463         if (scoreList == NULL)
1464                 return;
1465         if (newList == NULL)
1466                 return;
1467         spNetC4AScorePointer mom = *scoreList;
1468         spNetC4AScorePointer last = NULL;
1469         while (mom)
1470         {
1471                 spNetC4AScorePointer copy_score = (spNetC4AScorePointer)malloc(sizeof(spNetC4AScore));
1472                 sprintf(copy_score->longname,"%s",mom->longname);
1473                 sprintf(copy_score->shortname,"%s",mom->shortname);
1474                 copy_score->score = mom->score;
1475                 copy_score->commitTime = mom->commitTime;
1476                 copy_score->rank = mom->rank;
1477                 if (last)
1478                         last->next = copy_score;
1479                 else
1480                         *newList = copy_score;
1481                 last = copy_score;
1482                 mom = mom->next;
1483         }
1484         if (last)
1485                 last->next = NULL;
1486         else
1487                 *newList = NULL;
1488 }
1489
1490 typedef struct __ScoreNameStruct *__ScoreNamePointer;
1491 typedef struct __ScoreNameStruct {
1492         char longname[256];
1493         char shortname[256];
1494         __ScoreNamePointer next;
1495 } __ScoreName;
1496
1497 PREFIX void spNetC4AMakeScoresUnique(spNetC4AScorePointer* scoreList)
1498 {
1499         if (scoreList == NULL)
1500                 return;
1501         spNetC4AScorePointer mom = *scoreList;
1502         spNetC4AScorePointer before = NULL;
1503         __ScoreNamePointer name = NULL;
1504         __ScoreNamePointer searchStart = NULL;
1505         while (mom)
1506         {
1507                 //search mom in name:
1508                 __ScoreNamePointer search = searchStart;
1509                 while (search)
1510                 {
1511                         if (strcmp(mom->shortname,search->shortname) == 0 &&
1512                                 strcmp(mom->longname,search->longname) == 0 )
1513                                 break; //found
1514                         search = search->next;
1515                 }
1516                 if (search) //found -> remove
1517                 {
1518                         spNetC4AScorePointer next = mom->next;
1519                         before->next = next;
1520                         free(mom);
1521                         mom = next;
1522                 }
1523                 else //add
1524                 {
1525                         __ScoreNamePointer add = (__ScoreNamePointer)malloc(sizeof(__ScoreName));
1526                         sprintf(add->longname,"%s",mom->longname);
1527                         sprintf(add->shortname,"%s",mom->shortname);
1528                         add->next = searchStart;
1529                         searchStart = add;
1530                         before = mom;
1531                         mom = mom->next;
1532                 }
1533         }
1534         while (searchStart)
1535         {
1536                 __ScoreNamePointer next = searchStart->next;
1537                 free(searchStart);
1538                 searchStart = next;
1539         }
1540 }
1541
1542 PREFIX void spNetC4ADeleteScores(spNetC4AScorePointer* scoreList)
1543 {
1544         if (scoreList == NULL)
1545                 return;
1546         while (*scoreList)
1547         {
1548                 spNetC4AScorePointer next = (*scoreList)->next;
1549                 free(*scoreList);
1550                 (*scoreList) = next;
1551         }
1552 }
1553
1554 void fill_with_random_hex(char* buffer,int count)
1555 {
1556         int i;
1557         for (i = 0; i < count; i++)
1558         {
1559                 int c = rand()%16;
1560                 char cha;
1561                 if (c < 10)
1562                         cha = c+'0';
1563                 else
1564                         cha = c-10+'a';
1565                 buffer[i] = cha;
1566         }
1567 }
1568
1569 int c4a_create_thread(void* data)
1570 {
1571         createPointer createData = (createPointer)data;
1572         spNetIP ip = spNetResolve("skeezix.wallednetworks.com",13001);
1573         if (ip.address.ipv4 == SP_INVALID_IP)
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         spNetTCPConnection connection = spNetOpenClientTCP(ip);
1581         if (connection == NULL)
1582         {
1583                 SDL_mutexP(createData->task->statusMutex);
1584                 createData->task->status = SP_C4A_ERROR;
1585                 SDL_mutexV(createData->task->statusMutex);
1586                 return 1;
1587         }
1588         char create_string[2048];
1589         char buffer[2048];
1590         char prid[37] = "";
1591         //generating a new, random prid:
1592         fill_with_random_hex(prid,8);
1593         prid[ 8]='-';
1594         fill_with_random_hex(&(prid[ 9]),4);
1595         prid[13]='-';
1596         fill_with_random_hex(&(prid[14]),4);
1597         prid[18]='-';
1598         fill_with_random_hex(&(prid[19]),4);
1599         prid[23]='-';
1600         fill_with_random_hex(&(prid[24]),12);
1601         prid[36]=0;
1602         sprintf(create_string,"{\"email\": \"%s\", \"shortname\": \"%s\", \"password\": \"%s\", \"prid\": \"%s\", \"longname\": \"%s\"}",createData->email,createData->shortname,createData->password,prid,createData->longname);
1603         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));
1604         if (spNetSendTCP(connection,buffer,strlen(buffer)) == 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         if (spNetSendTCP(connection,create_string,strlen(create_string)) == 0)
1613         {
1614                 spNetCloseTCP(connection);
1615                 SDL_mutexP(createData->task->statusMutex);
1616                 createData->task->status = SP_C4A_ERROR;
1617                 SDL_mutexV(createData->task->statusMutex);
1618                 return 1;
1619         }
1620         spNetCloseTCP(connection);
1621         PROFILE_FILENAME_MAKRO
1622         SDL_RWops *file=SDL_RWFromFile(filename,"wb");
1623         SDL_RWwrite(file,prid,36,1);
1624         char c = '\n';
1625         SDL_RWwrite(file,&c,1,1);
1626         SDL_RWwrite(file,create_string,strlen(create_string),1);
1627         SDL_RWclose(file);
1628         (*(createData->profile)) = (spNetC4AProfilePointer)malloc(sizeof(spNetC4AProfile));
1629         sprintf((*(createData->profile))->longname,"%s",createData->longname);
1630         sprintf((*(createData->profile))->shortname,"%s",createData->shortname);
1631         sprintf((*(createData->profile))->password,"%s",createData->password);
1632         sprintf((*(createData->profile))->email,"%s",createData->email);
1633         sprintf((*(createData->profile))->prid,"%s",prid);
1634         SDL_mutexP(createData->task->statusMutex);
1635         createData->task->status = SP_C4A_OK;
1636         SDL_mutexV(createData->task->statusMutex);
1637         return 0;       
1638 }
1639
1640 PREFIX int spNetC4ACreateProfile(spNetC4AProfilePointer* profile, char* longname,char* shortname,char* password,char* email,int timeOut)
1641 {
1642         if (profile == NULL)
1643                 return 1;
1644         SDL_mutexP(spGlobalC4ATask->statusMutex);
1645         if (spGlobalC4ATask->status != SP_C4A_PROGRESS)
1646         {
1647                 spGlobalC4ATask->status = SP_C4A_PROGRESS;
1648                 SDL_mutexV(spGlobalC4ATask->statusMutex);
1649                 //Starting a background thread, which does the fancy stuff
1650                 createPointer data = (createPointer)malloc(sizeof(createType));
1651                 data->task = spGlobalC4ATask;
1652                 data->function = c4a_create_thread;
1653                 data->profile = profile;
1654                 sprintf(data->longname,"%s",longname);
1655                 sprintf(data->shortname,"%s",shortname);
1656                 sprintf(data->password,"%s",password);
1657                 sprintf(data->email,"%s",email);
1658                 spGlobalC4ATask->dataPointer = data;
1659                 spGlobalC4ATask->timeOut = timeOut;
1660                 spGlobalC4ATask->threadStatus = 1;
1661                 #ifdef _MSC_VER
1662                         spGlobalC4ATask->thread = SDL_CreateThread((int (__cdecl *)(void *))spNetC4AUberThread,data);
1663                 #else
1664                         spGlobalC4ATask->thread = SDL_CreateThread(spNetC4AUberThread,data);
1665                 #endif
1666                 return 0;
1667         }
1668         SDL_mutexV(spGlobalC4ATask->statusMutex);
1669         return 1;
1670 }
1671
1672 int c4a_delete_thread(void* data)
1673 {
1674         createPointer createData = (createPointer)data;
1675         spNetIP ip = spNetResolve("skeezix.wallednetworks.com",13001);
1676         if (ip.address.ipv4 == SP_INVALID_IP)
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         spNetTCPConnection connection = spNetOpenClientTCP(ip);
1684         if (connection == NULL)
1685         {
1686                 SDL_mutexP(createData->task->statusMutex);
1687                 createData->task->status = SP_C4A_ERROR;
1688                 SDL_mutexV(createData->task->statusMutex);
1689                 return 1;
1690         }
1691         char create_string[2048];
1692         char buffer[2048];
1693         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);
1694         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));
1695         if (spNetSendTCP(connection,buffer,strlen(buffer)) == 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         if (spNetSendTCP(connection,create_string,strlen(create_string)) == 0)
1704         {
1705                 spNetCloseTCP(connection);
1706                 SDL_mutexP(createData->task->statusMutex);
1707                 createData->task->status = SP_C4A_ERROR;
1708                 SDL_mutexV(createData->task->statusMutex);
1709                 return 1;
1710         }
1711         spNetCloseTCP(connection);
1712         (*(createData->profile)) = NULL;        
1713         if (createData->deleteFile)
1714                 spNetC4ADeleteProfileFile();
1715         SDL_mutexP(createData->task->statusMutex);
1716         createData->task->status = SP_C4A_OK;
1717         SDL_mutexV(createData->task->statusMutex);
1718         return 0;
1719 }
1720
1721 PREFIX int spNetC4ADeleteAccount(spNetC4AProfilePointer* profile,int deleteFile,int timeOut)
1722 {
1723         if (profile == NULL)
1724                 return 1;
1725         SDL_mutexP(spGlobalC4ATask->statusMutex);
1726         if (spGlobalC4ATask->status != SP_C4A_PROGRESS)
1727         {
1728                 spGlobalC4ATask->status = SP_C4A_PROGRESS;
1729                 SDL_mutexV(spGlobalC4ATask->statusMutex);
1730                 //Starting a background thread, which does the fancy stuff
1731                 createPointer data = (createPointer)malloc(sizeof(createType));
1732                 data->task = spGlobalC4ATask;
1733                 data->function = c4a_delete_thread;
1734                 data->profile = profile;
1735                 data->deleteFile = deleteFile;
1736                 spGlobalC4ATask->dataPointer = data;
1737                 spGlobalC4ATask->timeOut = timeOut;
1738                 spGlobalC4ATask->threadStatus = 1;
1739                 #ifdef _MSC_VER
1740                         spGlobalC4ATask->thread = SDL_CreateThread((int (__cdecl *)(void *))spNetC4AUberThread,c4a_delete_thread);
1741                 #else
1742                         spGlobalC4ATask->thread = SDL_CreateThread(spNetC4AUberThread,c4a_delete_thread);
1743                 #endif
1744                 return 0;
1745         }
1746         SDL_mutexV(spGlobalC4ATask->statusMutex);
1747         return 1;
1748 }
1749
1750 PREFIX void spNetC4ADeleteProfileFile()
1751 {
1752         PROFILE_FILENAME_MAKRO
1753 //Copied from spRemoveFile to avoid dependencies
1754 #ifdef _WIN32
1755         DeleteFile(filename);
1756 #else
1757         remove(filename);
1758 #endif  
1759 }
1760
1761 int c4a_edit_thread(void* data)
1762 {
1763         createPointer createData = (createPointer)data;
1764         spNetIP ip = spNetResolve("skeezix.wallednetworks.com",13001);
1765         if (ip.address.ipv4 == SP_INVALID_IP)
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         spNetTCPConnection connection = spNetOpenClientTCP(ip);
1773         if (connection == NULL)
1774         {
1775                 SDL_mutexP(createData->task->statusMutex);
1776                 createData->task->status = SP_C4A_ERROR;
1777                 SDL_mutexV(createData->task->statusMutex);
1778                 return 1;
1779         }
1780         char create_string[2048];
1781         char buffer[2048];
1782         sprintf(create_string,"{\"email\": \"%s\", \"shortname\": \"%s\", \"password\": \"%s\", \"prid\": \"%s\", \"longname\": \"%s\"}",createData->email,createData->shortname,createData->password,(*(createData->profile))->prid,createData->longname);
1783         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));
1784         if (spNetSendTCP(connection,buffer,strlen(buffer)) == 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         if (spNetSendTCP(connection,create_string,strlen(create_string)) == 0)
1793         {
1794                 spNetCloseTCP(connection);
1795                 SDL_mutexP(createData->task->statusMutex);
1796                 createData->task->status = SP_C4A_ERROR;
1797                 SDL_mutexV(createData->task->statusMutex);
1798                 return 1;
1799         }
1800         spNetCloseTCP(connection);
1801         PROFILE_FILENAME_MAKRO
1802         SDL_RWops *file=SDL_RWFromFile(filename,"wb");
1803         SDL_RWwrite(file,(*(createData->profile))->prid,strlen((*(createData->profile))->prid),1);
1804         char c = '\n';
1805         SDL_RWwrite(file,&c,1,1);
1806         SDL_RWwrite(file,create_string,strlen(create_string),1);
1807         SDL_RWclose(file);
1808         sprintf((*(createData->profile))->longname,"%s",createData->longname);
1809         sprintf((*(createData->profile))->shortname,"%s",createData->shortname);
1810         sprintf((*(createData->profile))->password,"%s",createData->password);
1811         sprintf((*(createData->profile))->email,"%s",createData->email);
1812         SDL_mutexP(createData->task->statusMutex);
1813         createData->task->status = SP_C4A_OK;
1814         SDL_mutexV(createData->task->statusMutex);
1815         return 0;       
1816 }
1817
1818 PREFIX int spNetC4AEditProfile(spNetC4AProfilePointer* profile,char* longname,char* shortname,char* password,char* email,int timeOut)
1819 {
1820         if (profile == NULL)
1821                 return 1;
1822         SDL_mutexP(spGlobalC4ATask->statusMutex);
1823         if (spGlobalC4ATask->status != SP_C4A_PROGRESS)
1824         {
1825                 spGlobalC4ATask->status = SP_C4A_PROGRESS;
1826                 SDL_mutexV(spGlobalC4ATask->statusMutex);
1827                 //Starting a background thread, which does the fancy stuff
1828                 createPointer data = (createPointer)malloc(sizeof(createType));
1829                 data->task = spGlobalC4ATask;
1830                 data->function = c4a_edit_thread;
1831                 data->profile = profile;
1832                 sprintf(data->longname,"%s",longname);
1833                 sprintf(data->shortname,"%s",shortname);
1834                 sprintf(data->password,"%s",password);
1835                 sprintf(data->email,"%s",email);
1836                 spGlobalC4ATask->dataPointer = data;
1837                 spGlobalC4ATask->timeOut = timeOut;
1838                 spGlobalC4ATask->threadStatus = 1;
1839                 #ifdef _MSC_VER
1840                         spGlobalC4ATask->thread = SDL_CreateThread((int (__cdecl *)(void *))spNetC4AUberThread,data);
1841                 #else
1842                         spGlobalC4ATask->thread = SDL_CreateThread(spNetC4AUberThread,data);
1843                 #endif
1844                 return 0;
1845         }
1846         SDL_mutexV(spGlobalC4ATask->statusMutex);
1847         return 1;
1848 }
1849
1850 PREFIX int spNetC4AGetStatusParallel(spNetC4ATaskPointer task)
1851 {
1852         SDL_mutexP(task->statusMutex);
1853         if (task->threadStatus)
1854         {
1855                 SDL_mutexV(task->statusMutex);
1856                 return SP_C4A_PROGRESS;
1857         }
1858         int status = task->status;
1859         SDL_mutexV(task->statusMutex);
1860         return status;
1861 }
1862
1863 PREFIX int spNetC4AGetStatus()
1864 {
1865         return spNetC4AGetStatusParallel(spGlobalC4ATask);
1866 }
1867
1868 PREFIX void spNetC4ACancelTaskParallel(spNetC4ATaskPointer task)
1869 {
1870         SDL_mutexP(task->statusMutex);
1871         if (task->status > 0)
1872         {
1873                 task->status = SP_C4A_CANCELED;
1874                 SDL_mutexV(task->statusMutex);
1875                 SDL_WaitThread(task->thread,NULL);
1876         }
1877         else
1878                 SDL_mutexV(task->statusMutex);
1879 }
1880
1881 PREFIX void spNetC4ACancelTask()
1882 {
1883         spNetC4ACancelTaskParallel(spGlobalC4ATask);
1884 }
1885
1886 PREFIX int spNetC4AGetTaskResult()
1887 {
1888         return spGlobalC4ATask->result;
1889 }
1890
1891 PREFIX int spNetC4AGetTaskResultParallel(spNetC4ATaskPointer task)
1892 {
1893         return task->result;
1894 }
1895
1896 PREFIX int spNetC4AGetTimeOut()
1897 {
1898         return spGlobalC4ATask->timeOut;
1899 }
1900
1901 PREFIX int spNetC4AGetTimeOutParallel(spNetC4ATaskPointer task)
1902 {
1903         return task->timeOut;
1904 }