Go Back

0 /*

1 * ISC License

2 * Copyright (c) 2023 RMF <rawmonk@firemail.cc>

3 */

4 #include <stdio.h>

5 #include <stdlib.h>

6 #include <stdint.h>

7 #include <string.h>

8 #include "macro.h"

9 #include "strlcpy.h"

10 #include "strnstr.h"

11 #include "error.h"

12 #include "image.h"

13 #include "storage.h"

14 #define CONFIG_INTERNAL

15 #include "config.h"

16

17 #define DEFAULT_SEARCH_URL "gemini://geminispace.info/search?%s"

18 #define CONFIG_FILE "config.conf"

19

20 struct config config = {0};

21

22 void config_default() {

23 memset(&config, 0, sizeof(config));

24 config.certificateLifespan = 3600 * 24 * 365 * 2; /* 2 years */

25 config.certificateBits = 2048;

26 config.enableHexViewer = 1;

27 config.enableSandbox = 1;

28 config.enableImage = 1;

29 config.enableHistory = 1;

30 config.enableXdg = 1;

31 config.maximumBodyLength = 8388608;

32 config.maximumDisplayLength = 1048576;

33 config.imageParserScratchPad = 10485760;

34 config.maximumRedirects = 5;

35 config.maximumCachedPages= 15;

36 config.maximumHistorySize = 3000;

37 STRLCPY(config.searchEngineURL, DEFAULT_SEARCH_URL);

38 }

39

40 static int set_field(struct field field, int v, char *str) {

41 unsigned int i = 0;

42 for (i = 0; i < LENGTH(fields); i++) {

43 if (STRCMP(fields[i].name, field.name)) continue;

44 if (fields[i].type != field.type) break;

45 switch (fields[i].type) {

46 case VALUE_INT:

47 {

48 int *integer = fields[i].ptr;

49 *integer = v;

50 }

51 break;

52 case VALUE_STRING:

53 strlcpy(fields[i].ptr, str, CONFIG_STRING_LENGTH);

54 break;

55 }

56 break;

57 }

58 return 0;

59 }

60

61 int config_set_field(int id, const char *value) {

62 if (id < 0 || (unsigned)id > LENGTH(fields))

63 return ERROR_INVALID_ARGUMENT;

64 switch (fields[id].type) {

65 case VALUE_INT:

66 {

67 int ivalue = atoi(value);

68 if (!ivalue && strcmp(value, "0"))

69 return ERROR_INVALID_ARGUMENT;

70 *(int*)fields[id].ptr = ivalue;

71 }

72 break;

73 case VALUE_STRING:

74 strlcpy(fields[id].ptr, value, CONFIG_STRING_LENGTH);

75 break;

76 default:

77 return ERROR_INVALID_ARGUMENT;

78 }

79 config_correction();

80 return 0;

81 }

82

83 int config_load() {

84 FILE *f;

85 struct field field;

86 char buf[1024];

87 int i, in_str, in_comment;

88 config_default();

89 if (!(f = storage_fopen(CONFIG_FILE, "r")))

90 return ERROR_STORAGE_ACCESS;

91

92 in_comment = in_str = i = 0;

93 while (1) {

94 int ch = fgetc(f);

95 if (ch == EOF || ch == '\n') {

96 int ivalue;

97 buf[i] = 0;

98 in_comment = in_str = i = 0;

99 ivalue = atoi(buf);

100 if (ivalue || !STRCMP(buf, "0")) {

101 field.type = VALUE_INT;

102 set_field(field, ivalue, NULL);

103 } else {

104 field.type = VALUE_STRING;

105 set_field(field, 0, buf);

106 }

107 field.name[0] = 0;

108 if (ch == EOF) break;

109 continue;

110 }

111 if (in_comment) continue;

112 if (!in_str && ch <= ' ') continue;

113 if (ch == '"') {

114 in_str = !in_str;

115 continue;

116 }

117 if (!in_str && ch == '#') {

118 in_comment = 1;

119 }

120 if (!in_str && ch == '=') {

121 buf[i] = 0;

122 STRLCPY(field.name, buf);

123 i = 0;

124 continue;

125 }

126 if ((unsigned)i >= sizeof(buf)) {

127 i = 0;

128 continue;

129 }

130 buf[i++] = ch;

131 }

132

133 fclose(f);

134 config_correction();

135 return 0;

136 }

137

138 int config_save() {

139

140 FILE *f;

141 unsigned int i;

142 if (!(f = storage_fopen(CONFIG_FILE, "w")))

143 return ERROR_STORAGE_ACCESS;

144 for (i = 0; i < LENGTH(fields); i++) {

145 switch (fields[i].type) {

146 case VALUE_INT:

147 fprintf(f, "%s = %d\n", fields[i].name,

148 *(int*)fields[i].ptr);

149 break;

150 case VALUE_STRING:

151 fprintf(f, "%s = \"%s\"\n", fields[i].name,

152 (char*)fields[i].ptr);

153 break;

154 }

155 }

156

157 fclose(f);

158 return 0;

159 }

160

161 int config_correction() {

162 size_t i;

163 for (i = 0; i < LENGTH(fields); i++) {

164 if (!STRCMP(fields[i].name, "request.maxdisplay")) {

165 unsigned int *value = fields[i].ptr;

166 if (*value < 4096) *value = 4096;

167 }

168 if (!STRCMP(fields[i].name, "search.url")) {

169 char *value = fields[i].ptr;

170 char *ptr = strnstr(value, "%s", CONFIG_STRING_LENGTH);

171 char *second = NULL;

172 if (ptr) {

173 second = strnstr(ptr + 1, "%s",

174 CONFIG_STRING_LENGTH - (ptr - value));

175 }

176 if (!ptr || second) {

177 strlcpy(fields[i].ptr, DEFAULT_SEARCH_URL,

178 CONFIG_STRING_LENGTH);

179 }

180 }

181 }

182 return 0;

183 }

184