summaryrefslogtreecommitdiffstats
path: root/source/main.h
blob: c0e35d7b66abc8387095712239d393c3487aeb61 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
#ifndef CODEFETCH_H
#define CODEFETCH_H

//for directories
#include <errno.h>
#include <sys/stat.h>

#include "gecko.h"

//green for printf
#define ANSI_COLOUR_GREEN   "\x1b[32m"
//set the text colour back to white to reset
#define ANSI_COLOUR_RESET   "\x1b[37m"

//linker complains with .h files
void install_mod(char file[], int row);

//Webservers decide all the time to transmit less than 4096 bytes at once, so "Content-Length:" conversion is required.
#define CHUNK 4096

const static char SERVER[] = "endianness.com";
const static char REQUEST[] =	"GET /root.txt HTTP/1.1\r\n"
				"Host: endianness.com\r\n"
				"User-Agent: Wii/1.0\r\n\r\n";
const static char RESP_OK[] = "HTTP/1.1 200 OK";

int get_content_length(char buf[])
{
char *contentLength = strstr(buf,"Content-Length:");
if (!contentLength){return -1;}//Content-Length not found

return (int)strtol(contentLength+16, (void *) strstr(contentLength, "\r")-1, 10);//convert the found content length number string into an integer
}

//filename is the file+path of file on server. Path is the file+path where it should be saved. Status is set to 0 if no downloading messages are wanted, and to 1 if they are
void download_file(char filename[], char path[], int status)
{
	s32 ret;

	char localip[16] = {0};
	char gateway[16] = {0};
	char netmask[16] = {0};

	ret = if_config(localip,netmask,gateway,TRUE,10);

	if (status)
		{
		printf("\n\n\nDownloading %s...", filename);
		#ifndef GECKO
		gprintf("Downloading %s...", filename);
		#endif
		}

	struct hostent* hostp;
	struct sockaddr_in serveraddr;

	s32 sock;
	sock = net_socket(AF_INET,SOCK_STREAM,0);
	memset(&serveraddr, 0x00,sizeof(struct sockaddr_in));
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_port = htons(80);
	hostp = net_gethostbyname(SERVER);
	//copy the address from the looked up host to serveraddr
	memcpy(&serveraddr.sin_addr,hostp->h_addr,sizeof(serveraddr.sin_addr));

	//connect to the server
	ret = net_connect(sock,(struct sockaddr*) &serveraddr,sizeof(serveraddr));

	//The length of the filename and path is required for later
	int fileLength = strlen(filename)+1;
	int pathLength = strlen(path)+1;

	char fileRequest[strlen(REQUEST)+fileLength];//size of original REQUEST and fileLength is long enough
//	printf("Request Length: %d\n", strlen(REQUEST)+fileLength);

	//generate the request for the requested file
	ssize_t requestLen = sprintf(fileRequest, "GET /%s HTTP/1.1\r\nHost: %s\r\nUser-Agent: Wii/1.0\r\n\r\n", filename, SERVER);

	ret = net_write(sock, fileRequest, requestLen);//send file request to server
	if(ret < 0)
		{
		printf("Write failed!\n");
		gprintf("Write failed!");
        	net_close(sock);
        	exit(1);
		}

	char buff[CHUNK+2];

	ssize_t n = net_read(sock, buff, CHUNK);
	if (!n)
		{
		printf("Recieve failed\n");
		gprintf("Recieve failed");
		exit(1);
		}

//	printf("Length of total header: %d\n", n);

//	buff[n] = '\0'; //add null terminator

//	printf("Header: %s", buff);

	int contentLength = get_content_length(buff);
	if (contentLength < 0)
		{
		printf("Invalid content length recieved!\n");
		gprintf("Invalid content length recieved!");
		exit(1);
		}

	if (status)
		{
		printf("%d bytes to download\n", contentLength);
		gprintf("%d bytes to download", contentLength);
		}
	int total = 0;//total number of bytes read

	if (memcmp(buff, RESP_OK, strlen(RESP_OK)) != 0)//make sure that the file was found
		{
		printf("File not found or another error\n");
		gprintf("File not found or another error");
		exit(1);
		}

	char *startOfData = strstr(buff,"\r\n\r\n")+4; //the start of the data
	if (!startOfData)
		{
		printf("Recieved HTTP header malformed!\n");
		gprintf("Recieved HTTP header malformed!");
		exit(1);
		}

	int len = n - (startOfData-buff);//subtract the amount of bytes in the header from n to get the lenght of the data in body
	//printf("Length of Data in header: %d\n", len);

	total += len; //Only the content counts in total

	char newPath[pathLength+4];
	sprintf(newPath, "sd:/%s", path);//generate the path

	gprintf("Generated path: %s", newPath);

	FILE *fp = fopen(newPath,"wb");
	if (!fp)
		{
		printf("Could not open %s!\n", newPath);
		gprintf("Could not open %s!", newPath);
		exit(1);
		}
	int result = fwrite(startOfData, 1, len, fp);//write first read results to sd excluding header
	if (result < 0){printf("Could not write to %s!\n", path); exit(1);}

	gprintf("Bytes read: %d", total);
	if (total == contentLength){goto complete;}//if total is the same size as cotentlength, no more reading needs to be done since the first read did it all

	//read the rest of the data
	while (1)
		{
		n = net_read(sock, buff, CHUNK);//recieve up to CHUNK bytes from server. (The server may decide to send a lot less);
		if (!n){printf("Could not read!\n"); exit(1);}
		total += n; //add n to total
		printf("\b\rRecieved: %d Bytes ", total);
		gprintf("\b\rRecieved: %d Bytes ", total);
		if (total == contentLength)//if total equals contentLength, reading is done
			{
			n = fwrite(buff, 1, n, fp);//attempt to write the chunk to sd
			if (n < 0){printf("Could not write to %s!\n", newPath); exit(1);}
//			printf("Secondary no more reading required\n");
			break;
			}
		n = fwrite(buff, 1, n, fp);//attempt to write the chunk to sd
		if (n < 0)
			{
			printf("Could not write to %s!\n", newPath);
			gprintf("Could not write to %s!", newPath);
			exit(1);}
		}

	complete:;

	fclose(fp);
	net_close(sock);
	if (status)
		{
		printf("\nDone downloading %s\n", path);
		gprintf("Done downloading %s", path);
		}
	return;
}


void create_folders(char path[])
{
	if (!strstr(path,"/")){return;}//no need to create folders if the file is in the root directory

	char newPath[strlen(path)+4];//need to have enough space for "sd:/"
	sprintf(newPath, "sd:/%s", path);

	int i;
	for (i=strlen(newPath); newPath[i] != '/';--i);//find first '/' from the back.
	newPath[i] = '\0';//overwrite the '/' with a null char so a dir named after the file isn't created

	int result;
	struct stat st;
	if (stat(newPath, &st) != 0){goto makeFullPath;}//fullpath does not exist
	else
		{
		gprintf("Fullpath exists");
		return;
		}

	makeFullPath: ;
	i = 0;
	while(1)
		{
		char *folder = strstr(path+i, "/");
		if (!folder)//if '/' is not found, we have reached the file.
			{
			//printf("Directory's created\n");
			return;
			}

		*folder = '\0';//overwrite '/' with a null char
		i=strlen(path)+1; //i equals the position of found '/'+1 so strstr finds the next '/' instead.

		sprintf(newPath, "sd:/%s", path);
		gprintf("Making: %s", newPath);

		result = mkdir(newPath, 0777);//make the dir
		if (result == -1)
			{
			if (errno == EEXIST)
				{
				gprintf("%s already exists", newPath);
				}
			else if (errno == ENOENT){printf("Parents of %s do not exist\n", newPath); exit(1);}
			else{printf("Could not create %s\n", newPath); exit(1);}
			}

		*folder = '/'; //replace the null char with '/' for next dir
		}
return;
}


int parse_root_txt(char file[])
{
int modCount = 0;//the number of mods extracted

FILE *fp = fopen(file, "r");
if (!fp)
	{
	printf("Could not open %s\n", file);
	gprintf("Could not open %s\n", file);
	exit(1);
	}

fseek(fp, 0L, SEEK_END);//seek to the end of the file
int size = ftell(fp);//store lenght of file
rewind(fp);//seek back to start of file

char buff[size];
buff[size] = '\0';//add null char to end of buff

char *colon = buff;//location of colon
char *secondColon = buff;//location of second colon
char *newLine = buff; //location of newline

while(1)
	{
	if (fgets(buff, size, fp) == NULL){break;}//get a single line from fp to buff
	colon = strstr(buff,":");//find colon in buff
	if (!colon)
		{
		printf("root.txt malformed!0\n");
		gprintf("root.txt malformed!0");
		exit(1);
		}

	secondColon = strstr(colon+1,":");//find second colon in buff
	if (!secondColon)
		{
		printf("root.txt malformed!1\n");
		gprintf("root.txt malformed!1");
		exit(1);
		}
	*secondColon = '\0'; //replace second colon with null char

	newLine = strstr(secondColon+1,"\n");//find newline in buff
	if (!newLine)
		{
		printf("root.txt malformed!6\n");
		gprintf("root.txt malformed!6");
		exit(1);
		}
	*newLine = '\0'; //replace newline with null char

	char elfPath[strlen(secondColon+1)+4];
	sprintf(elfPath, "sd:/%s", secondColon+1);
	FILE *boot_elf = fopen(elfPath, "r");
	if (boot_elf){printf(" %s%s%s\n", ANSI_COLOUR_GREEN, colon+1, ANSI_COLOUR_RESET); fclose(boot_elf);}//make mod name green if elf is found
	else {printf(" %s\n", colon+1);}

	++modCount;//increase the mod count
	}
if (!modCount)
	{
	printf("root.txt malformed!2\n");
	gprintf("root.txt malformed!2");
	exit(1);
	}

//move cursor back to start of the row
printf("\033[%dD", strlen(colon+1));

fclose(fp);
return --modCount;//return the number of lines printed (-1 to make the number correct)
}
#endif