5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2000 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
21 * These are general utility functions that doesn't belong to any specific
27 * Revision 1.1 2000/09/13 17:45:16 priikone
28 * Splitted SILC core library. Core library includes now only
29 * SILC protocol specific stuff. New utility library includes the
30 * old stuff from core library that is more generic purpose stuff.
32 * Revision 1.4 2000/07/19 07:04:04 priikone
33 * Minor bug fix in silc_encode_pem
35 * Revision 1.3 2000/07/10 05:34:40 priikone
36 * Added PEM encoding/decoding functions.
38 * Revision 1.2 2000/07/05 06:06:12 priikone
39 * Added file saving with specific mode.
41 * Revision 1.1.1.1 2000/06/27 11:36:55 priikone
42 * Imported from internal CVS/Added Log headers.
47 #include "silcincludes.h"
49 /* Reads a file to a buffer. The allocated buffer is returned. Length of
50 the file read is returned to the return_len argument. */
52 char *silc_file_read(const char *filename, int *return_len)
58 fd = open(filename, O_RDONLY);
60 SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
64 filelen = lseek(fd, (off_t)0L, SEEK_END);
67 if (lseek(fd, (off_t)0L, SEEK_SET) < 0)
71 SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
75 buffer = silc_calloc(filelen + 1, sizeof(char));
77 if ((read(fd, buffer, filelen)) == -1) {
78 memset(buffer, 0, sizeof(buffer));
80 SILC_LOG_ERROR(("Cannot read from file %s: %s", filename,
86 buffer[filelen] = EOF;
88 *return_len = filelen;
92 /* Writes a buffer to the file. */
94 int silc_file_write(const char *filename, const char *buffer, int len)
98 if ((fd = creat(filename, 0644)) == -1) {
99 SILC_LOG_ERROR(("Cannot open file %s for writing: %s", strerror(errno)));
103 if ((write(fd, buffer, len)) == -1) {
104 SILC_LOG_ERROR(("Cannot write to file %s: %s", strerror(errno)));
113 /* Writes a buffer to the file. If the file is created specific mode is
116 int silc_file_write_mode(const char *filename, const char *buffer,
121 if ((fd = creat(filename, mode)) == -1) {
122 SILC_LOG_ERROR(("Cannot open file %s for writing: %s", strerror(errno)));
126 if ((write(fd, buffer, len)) == -1) {
127 SILC_LOG_ERROR(("Cannot write to file %s: %s", strerror(errno)));
136 /* Gets line from a buffer. Stops reading when a newline or EOF occurs.
137 This doesn't remove the newline sign from the destination buffer. The
138 argument begin is returned and should be passed again for the function. */
140 int silc_gets(char *dest, int destlen, const char *src, int srclen, int begin)
142 static int start = 0;
145 memset(dest, 0, destlen);
151 for ( ; start <= srclen; i++, start++) {
155 dest[i] = src[start];
168 /* Checks line for illegal characters. Return -1 when illegal character
169 were found. This is used to check for bad lines when reading data from
170 for example a configuration file. */
172 int silc_check_line(char *buf)
174 /* Illegal characters in line */
175 if (strchr(buf, '#')) return -1;
176 if (strchr(buf, '\'')) return -1;
177 if (strchr(buf, '\\')) return -1;
178 if (strchr(buf, '\r')) return -1;
179 if (strchr(buf, '\a')) return -1;
180 if (strchr(buf, '\b')) return -1;
181 if (strchr(buf, '\f')) return -1;
190 /* Returns current time as string. */
192 char *silc_get_time()
197 curtime = time(NULL);
198 return_time = ctime(&curtime);
199 return_time[strlen(return_time) - 1] = '\0';
204 /* Converts string to capital characters */
206 char *silc_to_upper(char *string)
209 char *ret = silc_calloc(strlen(string) + 1, sizeof(char));
211 for (i = 0; i < strlen(string); i++)
212 ret[i] = toupper(string[i]);
217 /* Compares two strings. Strings may include wildcards * and ?.
218 Returns TRUE if strings match. */
220 int silc_string_compare(char *string1, char *string2)
223 int slen1 = strlen(string1);
224 int slen2 = strlen(string2);
225 char *tmpstr1, *tmpstr2;
227 if (!string1 || !string2)
230 /* See if they are same already */
231 if (!strncmp(string1, string2, strlen(string2)))
235 if (!strchr(string1, '*'))
238 /* Take copies of the original strings as we will change them */
239 tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
240 memcpy(tmpstr1, string1, slen1);
241 tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
242 memcpy(tmpstr2, string2, slen2);
244 for (i = 0; i < slen2; i++) {
246 /* * wildcard. Only one * wildcard is possible. */
247 if (tmpstr1[i] == '*')
248 if (!strncmp(tmpstr1, tmpstr2, i)) {
249 memset(tmpstr2, 0, slen2);
250 strncpy(tmpstr2, tmpstr1, i);
255 if (tmpstr1[i] == '?') {
256 if (!strncmp(tmpstr1, tmpstr2, i)) {
257 if (!(slen1 < i + 1))
258 if (tmpstr1[i + 1] != '?' &&
259 tmpstr1[i + 1] != tmpstr2[i + 1])
262 if (!(slen1 < slen2))
267 if (strncmp(tmpstr1, tmpstr2, i))
268 strncpy(tmpstr2, string2, slen2);
273 /* if using *, remove it */
274 if (strchr(tmpstr1, '*'))
275 *strchr(tmpstr1, '*') = 0;
277 if (!strcmp(tmpstr1, tmpstr2)) {
278 memset(tmpstr1, 0, slen1);
279 memset(tmpstr2, 0, slen2);
285 memset(tmpstr1, 0, slen1);
286 memset(tmpstr2, 0, slen2);
292 unsigned char pem_enc[64] =
293 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
295 /* Encodes data into PEM encoding. Returns NULL terminated PEM encoded
296 data string. Note: This is originally public domain code and is
299 char *silc_encode_pem(unsigned char *data, unsigned int len)
302 unsigned int bits, c, char_count;
309 pem = silc_calloc(((len * 8 + 5) / 6) + 5, sizeof(*pem));
311 for (i = 0; i < len; i++) {
316 if (char_count == 3) {
317 pem[j++] = pem_enc[bits >> 18];
318 pem[j++] = pem_enc[(bits >> 12) & 0x3f];
319 pem[j++] = pem_enc[(bits >> 6) & 0x3f];
320 pem[j++] = pem_enc[bits & 0x3f];
328 if (char_count != 0) {
329 bits <<= 16 - (8 * char_count);
330 pem[j++] = pem_enc[bits >> 18];
331 pem[j++] = pem_enc[(bits >> 12) & 0x3f];
333 if (char_count == 1) {
337 pem[j++] = pem_enc[(bits >> 6) & 0x3f];
345 /* Same as above but puts newline ('\n') every 72 characters. */
347 char *silc_encode_pem_file(unsigned char *data, unsigned int data_len)
350 unsigned int len, cols;
353 pem = silc_encode_pem(data, data_len);
356 pem2 = silc_calloc(len + (len / 72) + 1, sizeof(*pem2));
358 for (i = 0, j = 0, cols = 1; i < len; i++, cols++) {
372 /* Decodes PEM into data. Returns the decoded data. Note: This is
373 originally public domain code and is still PD. */
375 unsigned char *silc_decode_pem(unsigned char *pem, unsigned int pem_len,
376 unsigned int *ret_len)
379 unsigned int len, c, char_count, bits;
381 static char ialpha[256], decoder[256];
383 for (i = 64 - 1; i >= 0; i--) {
384 ialpha[pem_enc[i]] = 1;
385 decoder[pem_enc[i]] = i;
397 data = silc_calloc(((len * 6) / 8), sizeof(*data));
399 for (i = 0; i < len; i++) {
405 if (c > 127 || !ialpha[c])
411 if (char_count == 4) {
412 data[j++] = bits >> 16;
413 data[j++] = (bits >> 8) & 0xff;
414 data[j++] = bits & 0xff;
428 data[j++] = bits >> 10;
431 data[j++] = bits >> 16;
432 data[j++] = (bits >> 8) & 0xff;
442 /* Parse nickname string. The format may be <num>!<nickname>@<server> to
443 support multiple same nicknames. The <num> is the final unifier if same
444 nickname is on same server. Note, this is only local format and server
445 does not know anything about these. */
447 int silc_parse_nickname(char *string, char **nickname, char **server,
456 if (strchr(string, '!')) {
457 tlen = strcspn(string, "!");
458 memset(tmp, 0, sizeof(tmp));
459 memcpy(tmp, string, tlen);
464 if (tlen >= strlen(string))
470 if (strchr(string, '@')) {
471 tlen = strcspn(string, "@");
474 *nickname = silc_calloc(tlen + 1, sizeof(char));
475 memcpy(*nickname, string, tlen);
479 *server = silc_calloc(strlen(string) - tlen, sizeof(char));
480 memcpy(*server, string + tlen + 1, strlen(string) - tlen - 1);
484 *nickname = strdup(string);
490 /* Parses command line. At most `max_args' is taken. Rest of the line
491 will be allocated as the last argument if there are more than `max_args'
492 arguments in the line. Note that the command name is counted as one
493 argument and is saved. */
495 void silc_parse_command_line(unsigned char *buffer,
496 unsigned char ***parsed,
497 unsigned int **parsed_lens,
498 unsigned int **parsed_types,
499 unsigned int *parsed_num,
500 unsigned int max_args)
504 const char *cp = buffer;
506 *parsed = silc_calloc(1, sizeof(**parsed));
507 *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
509 /* Get the command first */
510 len = strcspn(cp, " ");
511 (*parsed)[0] = silc_to_upper((char *)cp);
512 (*parsed_lens)[0] = len;
516 /* Parse arguments */
517 if (strchr(cp, ' ') || strlen(cp) != 0) {
518 for (i = 1; i < max_args; i++) {
520 if (i != max_args - 1)
521 len = strcspn(cp, " ");
525 *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
526 *parsed_lens = silc_realloc(*parsed_lens,
527 sizeof(**parsed_lens) * (argc + 1));
528 (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
529 memcpy((*parsed)[argc], cp, len);
530 (*parsed_lens)[argc] = len;
541 /* Save argument types. Protocol defines all argument types but
542 this implementation makes sure that they are always in correct
543 order hence this simple code. */
544 *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
545 for (i = 0; i < argc; i++)
546 (*parsed_types)[i] = i;