Importet from internal CVS/Added Log headers.
[silc.git] / apps / silc / clientutil.c
1 /*
2
3   client.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2000 Pekka Riikonen
8
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.
13   
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.
18
19 */
20 /*
21  * $Id$
22  * $Log$
23  * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
24  *      Importet from internal CVS/Added Log headers.
25  *
26  *
27  */
28
29 #include "clientincludes.h"
30
31 /* Internal routine used to print lines to window. This can split the
32    line neatly if a word would overlap the line. */
33
34 static void silc_print_to_window(WINDOW *win, char *message)
35 {
36   int str_len, len;
37
38   str_len = strlen(message);
39  
40   if (str_len > COLS - 1) {
41     /* Split overlapping words to next line */
42     /* XXX In principal this is wrong as this modifies the original
43        string as it replaces the last ' ' with '\n'. This could be done
44        with little more work so that it would not replace anything. */
45     len = COLS - 1;
46     while (1) {
47
48       while (len && message[len] != ' ')
49         len--;
50
51       if (!len)
52         break;
53
54       message[len] = '\n';
55       len += COLS - 1;
56       if (len > str_len)
57         break;
58     }
59   }
60
61   wprintw(win, "%s", message);
62   wrefresh(win);
63 }
64
65 /* Prints a message with three star (*) sign before the actual message
66    on the current output window. This is used to print command outputs
67    and error messages. */
68 /* XXX Change to accept SilcClientWindow and use output window 
69    from there (the pointer to the output window must be added to the
70    SilcClientWindow object. */
71
72 void silc_say(SilcClient client, char *msg, ...)
73 {
74   va_list vp;
75   char message[1024];
76   
77   memset(message, 0, sizeof(message));
78   strncat(message, "\n***  ", 5);
79
80   va_start(vp, msg);
81   vsprintf(message + 5, msg, vp);
82   va_end(vp);
83   
84   /* Print the message */
85   silc_print_to_window(client->screen->output_win[0], message);
86 }
87
88 /* Prints message to the screen. This is used to print the messages
89    user is typed and message that came on channels. */
90
91 void silc_print(SilcClient client, char *msg, ...)
92 {
93   va_list vp;
94   char message[1024];
95   
96   memset(message, 0, sizeof(message));
97   strncat(message, "\n ", 2);
98
99   va_start(vp, msg);
100   vsprintf(message + 1, msg, vp);
101   va_end(vp);
102   
103   /* Print the message */
104   silc_print_to_window(client->screen->output_win[0], message);
105 }
106
107 /* Returns user's mail path */
108
109 char *silc_get_mail_path()
110 {
111   char pathbuf[MAXPATHLEN];
112   char *path;
113   
114   if ((path = (char *)getenv("MAIL")) != 0) {
115     strncpy(pathbuf, path, strlen(path));
116   } else {
117     strcpy(pathbuf, _PATH_MAILDIR);
118     strcat(pathbuf, "/");
119     strcat(pathbuf, silc_get_username());
120   }
121
122   return strdup(pathbuf);
123 }
124
125 /* gets the number of the user's mails, if possible */
126
127 int silc_get_number_of_emails()
128 {
129   FILE *tl;
130   int num = 0;
131   char *filename;
132   char data[1024];
133   
134   filename = silc_get_mail_path();
135   
136   tl = fopen(filename, "r");
137   if (!tl) {
138     fprintf(stderr, "Couldn't open mail file (%s).\n", filename);
139   } else {
140     while((fscanf(tl, "%s", data)) != EOF) { 
141       if(!strcmp(data, "Subject:"))
142         num++;
143     }
144     
145     fclose(tl);
146   }
147   
148   return num;
149 }
150
151 /* Returns the username of the user. If the global variable LOGNAME
152    does not exists we will get the name from the password file. */
153
154 char *silc_get_username()
155 {
156   char *logname = NULL;
157   
158   logname = strdup(getenv("LOGNAME"));
159   if (!logname) {
160     logname = getlogin();
161     if (!logname) {
162       struct passwd *pw;
163
164       pw = getpwuid(getuid());
165       if (!pw) {
166         fprintf(stderr, "silc_get_username: %s\n", strerror(errno));
167         return NULL;
168       }
169       
170       logname = strdup(pw->pw_name);
171     }
172   }
173   
174   return logname;
175 }                          
176
177 /* Returns the real name of ther user. */
178
179 char *silc_get_real_name()
180 {
181   char *realname = NULL;
182   struct passwd *pw;
183     
184   pw = getpwuid(getuid());
185   if (!pw) {
186     fprintf(stderr, "silc_get_username: %s\n", strerror(errno));
187     return NULL;
188   }
189
190   if (strchr(pw->pw_gecos, ','))
191     *strchr(pw->pw_gecos, ',') = 0;
192
193   realname = strdup(pw->pw_gecos);
194
195   return realname;
196 }
197
198 /* Returns time til next minute changes. Used to update the clock when
199    needed. */
200
201 int silc_client_time_til_next_min()
202 {
203   time_t curtime;
204   struct tm *min;
205   
206   curtime = time(0);
207   min = localtime(&curtime);
208   
209   return 60 - min->tm_sec;
210 }
211
212 /* Asks passphrase from user on the input line. */
213
214 char *silc_client_ask_passphrase(SilcClient client)
215 {
216   char pass1[256], pass2[256];
217   char *ret;
218   int try = 3;
219
220   while(try) {
221
222     /* Print prompt */
223     wattroff(client->screen->input_win, A_INVIS);
224     silc_screen_input_print_prompt(client->screen, "Passphrase: ");
225     wattron(client->screen->input_win, A_INVIS);
226     
227     /* Get string */
228     memset(pass1, 0, sizeof(pass1));
229     wgetnstr(client->screen->input_win, pass1, sizeof(pass1));
230     
231     /* Print retype prompt */
232     wattroff(client->screen->input_win, A_INVIS);
233     silc_screen_input_print_prompt(client->screen, "Retype passphrase: ");
234     wattron(client->screen->input_win, A_INVIS);
235     
236     /* Get string */
237     memset(pass2, 0, sizeof(pass2));
238     wgetnstr(client->screen->input_win, pass2, sizeof(pass2));
239
240     if (!strncmp(pass1, pass2, strlen(pass2)))
241       break;
242
243     try--;
244   }
245
246   ret = silc_calloc(strlen(pass1), sizeof(char));
247   memcpy(ret, pass1, strlen(pass1));
248
249   memset(pass1, 0, sizeof(pass1));
250   memset(pass2, 0, sizeof(pass2));
251
252   wattroff(client->screen->input_win, A_INVIS);
253   silc_screen_input_reset(client->screen);
254
255   return ret;
256 }
257
258 /* Lists supported (builtin) ciphers */
259
260 void silc_client_list_ciphers()
261 {
262
263 }
264
265 /* Lists supported (builtin) hash functions */
266
267 void silc_client_list_hash_funcs()
268 {
269
270 }
271
272 /* Lists supported PKCS algorithms */
273
274 void silc_client_list_pkcs()
275 {
276
277 }
278
279 /* Displays input prompt on command line and takes input data from user */
280
281 char *silc_client_get_input(const char *prompt)
282 {
283   char input[2048];
284   int fd;
285
286   fd = open("/dev/tty", O_RDONLY);
287   if (fd < 0) {
288     fprintf(stderr, "silc: %s\n", strerror(errno));
289     exit(1);
290   }
291
292   memset(input, 0, sizeof(input));
293
294   printf("%s", prompt);
295   fflush(stdout);
296
297   if ((read(fd, input, sizeof(input))) < 0) {
298     fprintf(stderr, "silc: %s\n", strerror(errno));
299     exit(1);
300   }
301
302   if (strlen(input) <= 1)
303     return NULL;
304
305   if (strchr(input, '\n'))
306     *strchr(input, '\n') = '\0';
307
308   return strdup(input);
309 }
310
311 /* Displays prompt on command line and takes passphrase with echo 
312    off from user. */
313
314 char *silc_client_get_passphrase(const char *prompt)
315 {
316 #if 0
317   char input[2048];
318   char *ret;
319   int fd;
320   struct termios to;
321   struct termios to_old;
322
323   fd = open("/dev/tty", O_RDONLY);
324   if (fd < 0) {
325     fprintf(stderr, "silc: %s\n", strerror(errno));
326     exit(1);
327   }
328
329   signal(SIGINT, SIG_IGN);
330
331   /* Get terminal info */
332   tcgetattr(fd, &to);
333   to_old = to;
334
335   /* Echo OFF */
336   to.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
337   tcsetattr(fd, TCSANOW, &to);
338
339   memset(input, 0, sizeof(input));
340
341   printf("%s", prompt);
342   fflush(stdout);
343
344   if ((read(fd, input, sizeof(input))) < 0) {
345     fprintf(stderr, "silc: %s\n", strerror(errno));
346     exit(1);
347   }
348
349   if (strlen(input) <= 1) {
350     tcsetattr(fd, TCSANOW, &to_old);
351     return NULL;
352   }
353
354   if (strchr(input, '\n'))
355     *strchr(input, '\n') = '\0';
356
357   /* Restore old terminfo */
358   tcsetattr(fd, TCSANOW, &to_old);
359   signal(SIGINT, SIG_DFL);
360
361   ret = silc_calloc(strlen(input), sizeof(char));
362   memcpy(ret, input, strlen(input));
363   memset(input, 0, sizeof(input));
364   return ret;
365 #else
366   return NULL;
367 #endif
368 }
369
370 /* Creates new public key and private key pair. This is used only
371    when user wants to create new key pair from command line. */
372
373 void silc_client_create_key_pair(char *pkcs_name, int bits)
374 {
375   SilcPKCS pkcs;
376   SilcRng rng;
377   unsigned char *key;
378   unsigned int key_len;
379   char *pkfile = NULL, *prvfile = NULL;
380
381   printf("\
382 New pair of keys will be created.  Please, answer to following questions.\n\
383 ");
384
385   if (!pkcs_name) {
386   again_name:
387     pkcs_name = 
388       silc_client_get_input("PKCS name (l to list names) [rsa]: ");
389     if (!pkcs_name)
390       pkcs_name = strdup("rsa");
391
392     if (*pkcs_name == 'l' || *pkcs_name == 'L') {
393       silc_client_list_pkcs();
394       silc_free(pkcs_name);
395       goto again_name;
396     }
397   }
398
399   if (!bits) {
400     char *length = NULL;
401     length = 
402       silc_client_get_input("Key length in bits [1024]: ");
403     if (!length)
404       bits = 1024;
405     else
406       bits = atoi(length);
407   }
408
409   rng = silc_rng_alloc();
410   silc_rng_init(rng);
411   silc_math_primegen_init();
412
413  again_pk:
414   pkfile = silc_client_get_input("Public key filename: ");
415   if (!pkfile) {
416     printf("Public key filename must be defined\n");
417     goto again_pk;
418   }
419
420  again_prv:
421   prvfile = silc_client_get_input("Private key filename: ");
422   if (!prvfile) {
423     printf("Private key filename must be defined\n");
424     goto again_prv;
425   }
426
427   /* Generate keys */
428   silc_pkcs_alloc(pkcs_name, &pkcs);
429   pkcs->pkcs->init(pkcs->context, bits, rng);
430
431   /* Save keys into file */
432   key = silc_pkcs_get_public_key(pkcs, &key_len);
433   silc_pkcs_save_public_key(pkcs, pkfile, key, key_len);
434   memset(key, 0, sizeof(key_len));
435   silc_free(key);
436   key = silc_pkcs_get_private_key(pkcs, &key_len);
437   silc_pkcs_save_private_key(pkcs, prvfile, key, key_len, "");
438   memset(key, 0, sizeof(key_len));
439   silc_free(key);
440
441   silc_math_primegen_uninit();
442   silc_rng_free(rng);
443   silc_pkcs_free(pkcs);
444 }