1/* This file is part of Mailfromd.             -*- c -*-
2   Copyright (C) 2009-2021 Sergey Poznyakoff
3
4   This program is free software; you can redistribute it and/or modify
5   it under the terms of the GNU General Public License as published by
6   the Free Software Foundation; either version 3, or (at your option)
7   any later version.
8
9   This program is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   GNU General Public License for more details.
13
14   You should have received a copy of the GNU General Public License
15   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17MF_BUILTIN_MODULE
18
19#ifndef ENAMETOOLONG
20# define ENAMETOOLONG 0
21#endif
22
23#ifndef INITIAL_HOSTNAME_LENGTH
24# define INITIAL_HOSTNAME_LENGTH 34
25#endif
26
27#ifndef INITIAL_DOMAINNAME_LENGTH
28# define INITIAL_DOMAINNAME_LENGTH 34
29#endif
30
31/* string gethostname()
32
33   This implementation is based on xgethostname by Jim Meyering
34*/
35MF_DEFUN(gethostname, STRING, OPTIONAL, NUMBER dns)
36{
37	size_t size = INITIAL_HOSTNAME_LENGTH;
38
39	MF_OBSTACK_BEGIN();
40	while (1) {
41		size_t nsize;
42		size_t size_1;
43		char *hostname;
44
45		MF_OBSTACK_GROW(NULL, size);
46		hostname = MF_OBSTACK_BASE();
47
48                /* Use SIZE_1 here rather than SIZE to work around the bug in
49		   SunOS 5.5's gethostname whereby it NUL-terminates HOSTNAME
50		   even when the name is as long as the supplied buffer.  */
51		size_1 = size - 1;
52		hostname[size_1 - 1] = '\0';
53		errno = 0;
54
55		if (gethostname(hostname, size_1) == 0)	{
56			if (!hostname[size_1 - 1])
57				break;
58		} else if (errno != 0
59			   && errno != ENAMETOOLONG && errno != EINVAL
60			   /* OSX/Darwin does this when the buffer is not
61			      large enough */
62			   && errno != ENOMEM) {
63			int saved_errno = errno;
64			MF_OBSTACK_CANCEL();
65			MF_THROW(mfe_failure,
66				 "%s", mu_strerror(saved_errno));
67		}
68
69		nsize = size * 2;
70		if (nsize <= size) {
71			MF_OBSTACK_CANCEL();
72			MF_THROW(mfe_failure,
73				 "%s", mu_strerror(ENOMEM));
74		}
75		size = nsize;
76	}
77
78	if (MF_OPTVAL(dns)) {
79		struct hostent *hp;
80		char *ptr = MF_OBSTACK_BASE;
81
82		hp = gethostbyname(ptr);
83		if (hp) {
84			size_t nlen = strlen(hp->h_name);
85			if (nlen >= size)
86				MF_OBSTACK_GROW(NULL,
87						nlen - size + 1);
88			strcpy(ptr, hp->h_name);
89		}
90	}
91
92	MF_RETURN_OBSTACK();
93}
94END
95
96/* string getdomainname()
97
98   This implementation is based on xgetdomainname by Jim Meyering
99*/
100MF_DEFUN(getdomainname, STRING)
101{
102	size_t size = INITIAL_DOMAINNAME_LENGTH;
103
104	MF_OBSTACK_BEGIN();
105	while (1) {
106		size_t nsize;
107		size_t size_1;
108		char *domainname;
109		int rc;
110
111		MF_OBSTACK_GROW(NULL, size);
112		domainname = MF_OBSTACK_BASE();
113
114		size_1 = size - 1;
115		domainname[size_1 - 1] = '\0';
116		errno = 0;
117
118		rc = getdomainname(domainname, size);
119		if (rc >= 0 && domainname[size_1] == '\0')
120			break;
121		else if (rc < 0 && errno != EINVAL) {
122			int saved_errno = errno;
123			MF_OBSTACK_CANCEL();
124			MF_THROW(mfe_failure,
125				 "%s", mu_strerror(saved_errno));
126		}
127
128		nsize = size * 2;
129		if (nsize <= size) {
130			MF_OBSTACK_CANCEL();
131			MF_THROW(mfe_failure,
132				 "%s", mu_strerror(ENOMEM));
133		}
134		size = nsize;
135	}
136	MF_RETURN_OBSTACK();
137}
138END
139
140