+/** Encode an IP address in the base64 used by numnicks.
+ * For IPv4 addresses (including IPv4-mapped and IPv4-compatible IPv6
+ * addresses), the 32-bit host address is encoded directly as six
+ * characters.
+ *
+ * For IPv6 addresses, each 16-bit address segment is encoded as three
+ * characters, but the longest run of zero segments is encoded using an
+ * underscore.
+ * @param[out] buf Output buffer to write to.
+ * @param[in] addr IP address to encode.
+ * @param[in] count Number of bytes writable to \a buf.
+ * @param[in] v6_ok If non-zero, peer understands base-64 encoded IPv6 addresses.
+ */
+const char* iptobase64(char* buf, const struct irc_in_addr* addr, unsigned int count, int v6_ok)
+{
+ if (irc_in_addr_is_ipv4(addr)) {
+ assert(count >= 6);
+ inttobase64(buf, (ntohs(addr->in6_16[6]) << 16) | ntohs(addr->in6_16[7]), 6);
+ } else if (!v6_ok) {
+ assert(count >= 6);
+ if (addr->in6_16[0] == htons(0x2002))
+ inttobase64(buf, (ntohs(addr->in6_16[1]) << 16) | ntohs(addr->in6_16[2]), 6);
+ else
+ strcpy(buf, "AAAAAA");
+ } else {
+ unsigned int max_start, max_zeros, curr_zeros, zero, ii;
+ char *output = buf;
+
+ assert(count >= 25);
+ /* Can start by printing out the leading non-zero parts. */
+ for (ii = 0; (addr->in6_16[ii]) && (ii < 8); ++ii) {
+ inttobase64(output, ntohs(addr->in6_16[ii]), 3);
+ output += 3;
+ }
+ /* Find the longest run of zeros. */
+ for (max_start = zero = ii, max_zeros = curr_zeros = 0; ii < 8; ++ii) {
+ if (!addr->in6_16[ii])
+ curr_zeros++;
+ else if (curr_zeros > max_zeros) {
+ max_start = ii - curr_zeros;
+ max_zeros = curr_zeros;
+ curr_zeros = 0;
+ }
+ }
+ if (curr_zeros > max_zeros) {
+ max_start = ii - curr_zeros;
+ max_zeros = curr_zeros;
+ curr_zeros = 0;
+ }
+ /* Print the rest of the address */
+ for (ii = zero; ii < 8; ) {
+ if ((ii == max_start) && max_zeros) {
+ *output++ = '_';
+ ii += max_zeros;
+ } else {
+ inttobase64(output, ntohs(addr->in6_16[ii]), 3);
+ output += 3;
+ ii++;
+ }
+ }
+ *output = '\0';
+ }
+ return buf;
+}