]> Pileus Git - ~andy/fetchmail/blob - netrc.c
Remove bad redefinitions.
[~andy/fetchmail] / netrc.c
1 /* netrc.c -- parse the .netrc file to get hosts, accounts, and passwords
2    Copyright (C) 1996, Free Software Foundation, Inc.
3    Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
18
19 /* Compile with -DSTANDALONE to test this module. */
20
21 #include <stdio.h>
22 #include <ctype.h>
23 #include <stdlib.h>
24 #ifdef HAVE_STRING_H
25 #  include <string.h>
26 #else
27 #  include <strings.h>
28 #endif
29
30 #include "config.h"
31 #include "fetchmail.h"
32 #include "netrc.h"
33
34 #ifdef STANDALONE
35 /* Normally defined in xstrdup.c. */
36 # define xstrdup strdup
37
38 /* Normally defined in xmalloc.c */
39 # define xmalloc malloc
40 # define xrealloc realloc
41 #endif
42
43 /* Maybe add NEWENTRY to the account information list, LIST.  NEWENTRY is
44    set to a ready-to-use netrc_entry, in any event. */
45 static void
46 maybe_add_to_list (newentry, list)
47      netrc_entry **newentry;
48      netrc_entry **list;
49 {
50     netrc_entry *a, *l;
51     a = *newentry;
52     l = *list;
53
54     /* We need an account name in order to add the entry to the list. */
55     if (a && ! a->account)
56     {
57         /* Free any allocated space. */
58         free (a->host);
59         free (a->account);
60         free (a->password);
61     }
62     else
63     {
64         if (a)
65         {
66             /* Add the current machine into our list. */
67             a->next = l;
68             l = a;
69         }
70
71         /* Allocate a new netrc_entry structure. */
72         a = (netrc_entry *) xmalloc (sizeof (netrc_entry));
73     }
74
75     /* Zero the structure, so that it is ready to use. */
76     memset (a, 0, sizeof(*a));
77
78     /* Return the new pointers. */
79     *newentry = a;
80     *list = l;
81     return;
82 }
83
84
85 /* Parse FILE as a .netrc file (as described in ftp(1)), and return a
86    list of entries.  NULL is returned if the file could not be
87    parsed. */
88 netrc_entry *
89 parse_netrc (file)
90      char *file;
91 {
92     FILE *fp;
93     char buf[POPBUFSIZE+1], *p, *tok, *premature_token;
94     netrc_entry *current, *retval;
95     int ln;
96
97     /* The latest token we've seen in the file. */
98     enum
99     {
100         tok_nothing, tok_account, tok_login, tok_macdef, tok_machine, tok_password
101     } last_token = tok_nothing;
102
103     current = retval = NULL;
104
105     fp = fopen (file, "r");
106     if (!fp)
107     {
108         /* Just return NULL if we can't open the file. */
109         return NULL;
110     }
111
112     /* Initialize the file data. */
113     ln = 0;
114     premature_token = NULL;
115
116     /* While there are lines in the file... */
117     while (fgets(buf, POPBUFSIZE, fp))
118     {
119         ln ++;
120
121         /* Strip trailing CRLF */
122         p = buf + strlen(buf) - 1;
123         while (*p && isspace(*p))
124             *p-- = '\0';
125
126         /* Parse the line. */
127         p = buf;
128
129         /* If the line is empty... */
130         if (!*p)
131             if (last_token == tok_macdef)       /* end of macro */
132                 last_token = tok_nothing;
133             else
134                 continue;                       /* otherwise ignore it */
135
136         /* If we are defining macros, then skip parsing the line. */
137         while (*p && last_token != tok_macdef)
138         {
139             /* Skip any whitespace. */
140             while (*p && isspace (*p))
141                 p++;
142
143             /* Discard end-of-line comments. */
144             if (*p == '#')
145                 break;
146
147             tok = p;
148
149             /* Find the end of the token. */
150             while (*p && !isspace (*p))
151                 p ++;
152
153             /* Null-terminate the token, if it isn't already. */
154             if (*p)
155                 *p ++ = '\0';
156
157             switch (last_token)
158             {
159             case tok_login:
160                 if (current)
161                     current->account = (char *) xstrdup (tok);
162                 else
163                     premature_token = "login";
164                 break;
165
166             case tok_machine:
167                 /* Start a new machine entry. */
168                 maybe_add_to_list (&current, &retval);
169                 current->host = (char *) xstrdup (tok);
170                 break;
171
172             case tok_password:
173                 if (current)
174                     current->password = (char *) xstrdup (tok);
175                 else
176                     premature_token = "password";
177                 break;
178
179                 /* We handle most of tok_macdef above. */
180             case tok_macdef:
181                 if (!current)
182                     premature_token = "macdef";
183                 break;
184
185                 /* We don't handle the account keyword at all. */
186             case tok_account:
187                 if (!current)
188                     premature_token = "account";
189                 break;
190
191                 /* We handle tok_nothing below this switch. */
192             case tok_nothing:
193                 break;
194             }
195
196             if (premature_token)
197             {
198 #ifdef HAVE_ERROR
199                 error_at_line (0, 0, file, ln,
200                                _("warning: found \"%s\" before any host names"),
201                                premature_token);
202 #else
203                 fprintf (stderr,
204                          "%s:%d: warning: found \"%s\" before any host names\n",
205                          file, ln, premature_token);
206 #endif
207                 premature_token = NULL;
208             }
209
210             if (last_token != tok_nothing)
211                 /* We got a value, so reset the token state. */
212                 last_token = tok_nothing;
213             else
214             {
215                 /* Fetch the next token. */
216                 if (!strcmp (tok, "account"))
217                     last_token = tok_account;
218
219                 if (!strcmp (tok, "default"))
220                 {
221                     maybe_add_to_list (&current, &retval);
222                 }
223                 else if (!strcmp (tok, "login"))
224                     last_token = tok_login;
225
226                 else if (!strcmp (tok, "macdef"))
227                     last_token = tok_macdef;
228
229                 else if (!strcmp (tok, "machine"))
230                     last_token = tok_machine;
231
232                 else if (!strcmp (tok, "password"))
233                     last_token = tok_password;
234
235                 else
236                 {
237                     fprintf (stderr, "%s:%d: warning: unknown token \"%s\"\n",
238                              file, ln, tok);
239                 }
240             }
241         }
242     }
243
244     fclose (fp);
245
246     /* Finalize the last machine entry we found. */
247     maybe_add_to_list (&current, &retval);
248     free (current);
249
250     /* Reverse the order of the list so that it appears in file order. */
251     current = retval;
252     retval = NULL;
253     while (current)
254     {
255         netrc_entry *saved_reference;
256
257         /* Change the direction of the pointers. */
258         saved_reference = current->next;
259         current->next = retval;
260
261         /* Advance to the next node. */
262         retval = current;
263         current = saved_reference;
264     }
265
266     return retval;
267 }
268
269
270 /* Return the netrc entry from LIST corresponding to HOST.  NULL is
271    returned if no such entry exists. */
272 netrc_entry *
273 search_netrc (list, host)
274      netrc_entry *list;
275      char *host;
276 {
277     /* Look for the HOST in LIST. */
278     while (list)
279     {
280         if (!list->host)
281             /* We hit the default entry. */
282             break;
283
284         else if (!strcmp (list->host, host))
285             /* We found a matching entry. */
286             break;
287
288         list = list->next;
289     }
290
291     /* Return the matching entry, or NULL. */
292     return list;
293 }
294
295
296 #ifdef STANDALONE
297 #include <sys/types.h>
298 #include <sys/stat.h>
299
300 extern int errno;
301
302 int
303 main (argc, argv)
304      int argc;
305      char **argv;
306 {
307     struct stat sb;
308     char *program_name, *file, *target;
309     netrc_entry *head, *a;
310
311     if (argc < 2)
312     {
313         fprintf (stderr, "Usage: %s NETRC [HOSTNAME]...\n", argv[0]);
314         exit (1);
315     }
316
317     program_name = argv[0];
318     file = argv[1];
319     target = argv[2];
320
321     if (stat (file, &sb))
322     {
323         fprintf (stderr, "%s: cannot stat %s: %s\n", argv[0], file,
324                  strerror (errno));
325         exit (1);
326     }
327
328     head = parse_netrc (file);
329     if (!head)
330     {
331         fprintf (stderr, "%s: no entries found in %s\n", argv[0], file);
332         exit (1);
333     }
334
335     if (argc > 2)
336     {
337         int i, status;
338         status = 0;
339         for (i = 2; i < argc; i++)
340         {
341             /* Print out the host that we are checking for. */
342             fputs (argv[i], stdout);
343
344             a = search_netrc (head, argv[i]);
345             if (a)
346             {
347                 /* Print out the account and password (if any). */
348                 fputc (' ', stdout);
349                 fputs (a->account, stdout);
350                 if (a->password)
351                 {
352                     fputc (' ', stdout);
353                     fputs (a->password, stdout);
354                 }
355             }
356             else
357                 status = 1;
358
359             fputc ('\n', stdout);
360         }
361         exit (status);
362     }
363
364     /* Print out the entire contents of the netrc. */
365     a = head;
366     while (a)
367     {
368         /* Print the host name. */
369         if (a->host)
370             fputs (a->host, stdout);
371         else
372             fputs ("DEFAULT", stdout);
373
374         fputc (' ', stdout);
375
376         /* Print the account name. */
377         fputs (a->account, stdout);
378
379         if (a->password)
380         {
381             /* Print the password, if there is any. */
382             fputc (' ', stdout);
383             fputs (a->password, stdout);
384         }
385
386         fputc ('\n', stdout);
387         a = a->next;
388     }
389
390     exit (0);
391 }
392 #endif /* STANDALONE */