aboutsummaryrefslogblamecommitdiffstats
path: root/src/passphrase_helper.h
blob: bd20472e44f2ac7fdb2b00f4399d0a0ca1335d82 (plain) (tree)

































































































































































































































































































                                                                                               

                                                                                 







                                                                        

                                                                                 










                                                                        
/**
 * libpassphrase – Personalisable library for TTY passphrase reading
 * 
 * Copyright © 2013, 2014, 2015  Mattias Andrée (maandree@member.fsf.org)
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#ifndef PASSPHRASE_HELPER_H
#define PASSPHRASE_HELPER_H


/* Fix conflicting configurations */
#if defined(PASSPHRASE_TEXT) && defined(PASSPHRASE_STAR)
#  warning You cannot have both PASSPHRASE_TEXT and PASSPHRASE_STAR
#  undef PASSPHRASE_TEXT
#endif


/* Default texts */
#ifndef PASSPHRASE_STAR_CHAR
#  define PASSPHRASE_STAR_CHAR  "*"  /* TODO document */
#endif
#ifndef PASSPHRASE_TEXT_EMPTY
#  define PASSPHRASE_TEXT_EMPTY  "(empty)"  /* TODO document */
#endif
#ifndef PASSPHRASE_TEXT_NOT_EMPTY
#  define PASSPHRASE_TEXT_NOT_EMPTY  "(not empty)"  /* TODO document */
#endif



/* Control keys. */

/**
 * Home-key.
 * Character sequences: \e[1~  \eOH
 * Control-key combination: ^A
 */
#define KEY_HOME    -1

/**
 * Insert-key.
 * Character sequences: \e[2~
 */
#define KEY_INSERT  -2

/**
 * Delete-key.
 * Character sequences: \e[3~
 * Control-key combination: ^D
 */
#define KEY_DELETE  -3

/**
 * End-key.
 * Character sequences: \e[4~  \eOF
 * Control-key combination: ^E
 */
#define KEY_END     -4

/**
 * Erase-key, also known as backspace.
 * Character sequences: \d8  \d127
 */
#define KEY_ERASE   -5

/**
 * Right-key.
 * Character sequences: \e[C
 * Control-key combination: ^F
 */
#define KEY_RIGHT   -6

/**
 * Left-key.
 * Character sequences: \e[D
 * Control-key combination: ^B
 */
#define KEY_LEFT    -7



/* Custom fflush and fprintf */
#if defined(PASSPHRASE_STAR) || defined(PASSPHRASE_TEXT)
#  define xprintf(...)  fprintf(stderr, __VA_ARGS__)
#  define xflush()      fflush(stderr)
#elif defined(PASSPHRASE_MOVE) && !defined(PASSPHRASE_ECHO)
#  define xprintf(...)  ({ /* do nothing */ })
#  define xflush()      ({ /* do nothing */ })
#elif defined(PASSPHRASE_MOVE)
#  define xprintf(...)  fprintf(stderr, __VA_ARGS__)
#  define xflush()      fflush(stderr)
#else
#  define xflush()      fflush(stderr)
#endif



/* Custom putchar */
#if defined(PASSPHRASE_STAR)
#  define xputchar(C)  (((C & 0xC0) != 0x80) ? fprintf(stderr, "%s", PASSPHRASE_STAR_CHAR) : 0)
#elif defined(PASSPHRASE_ECHO) && defined(PASSPHRASE_MOVE)
#  define xputchar(C)  fputc(C, stderr)
#else
#  define xputchar(C)  ({ /* be silent */ })
#endif



/* Is insert active by default? */
#if defined(PASSPHRASE_OVERRIDE) && defined(PASSPHRASE_INSERT)
#  if defined(DEFAULT_INSERT)
#    define DEFAULT_INSERT_VALUE  1
#  else
#    define DEFAULT_INSERT_VALUE  0
#  endif
#endif



/* PASSPHRASE_INVALID's affect */
#if defined(PASSPHRASE_INVALID)
#  define null_terminate()  (*(rc + len) = 0)
#else
#  define null_terminate()  ({ /* do nothing*/ })
#endif



/* Implementation of the right-key's action */
#define move_right()							\
  ({									\
    xprintf("\033[C");							\
    do									\
      point++;								\
    while ((len != point) && ((*(rc + point) & 0xC0) == 0x80));		\
  })


/* Implementation of the left-key's action */
#define move_left()							\
  ({									\
    xprintf("\033[D");							\
    point--;								\
    while (point && ((*(rc + point) & 0xC0) == 0x80))			\
      point--;								\
  })


/* Implementation of the home-key's action */
#define move_home()				\
  ({						\
    size_t n = 0;				\
    for (i = 0; i < point; i++)			\
      if ((*(rc + i) & 0xC0) != 0x80)		\
	n++;					\
    xprintf("\033[%zuD", n);			\
    point = 0;					\
  })


/* Implementation of the end-key's action */
#define move_end()				\
  ({						\
    size_t n = 0;				\
    for (i = point; i < len; i++)		\
      if ((*(rc + i) & 0xC0) != 0x80)		\
	n++;					\
    xprintf("\033[%zuC", n);			\
    point = len;				\
  })


/* Implementation of the delete-key's action upon the passphrase buffer */
#define delete_next()						\
  ({								\
    null_terminate();						\
    do								\
      {								\
	for (i = point; i < len; i++)				\
	  *(rc + i) = *(rc + i + 1);				\
	len--;							\
      }								\
    while ((len != point) && ((*(rc + point) & 0xC0) == 0x80));	\
  })


/* Implementation of the erase-key's action upon the passphrase buffer */
#if defined(PASSPHRASE_MOVE)
#define erase_prev()						\
  ({								\
    char redo = 1;						\
    null_terminate();						\
    while (redo)						\
      {								\
	redo = (*(rc + point - 1) & 0xC0) == 0x80;		\
	for (i = point; i < len; i++)				\
	  *(rc + i - 1) = *(rc + i);				\
	if (point <= len)					\
	  *(rc + len - 1) = *(rc + len);			\
	point--;						\
	len--;							\
      }								\
  })
#else
#  define erase_prev()  (*(rc + --len) = 0)
#endif


#if defined(PASSPHRASE_MOVE)
#  define append_char()  (xputchar(c), *(rc + len++) = (char)c, point++)
#elif defined(PASSPHRASE_TEXT)
#  define append_char()							\
  ({									\
    if (len == 0)							\
      {									\
	xprintf("\e[K%s%zn", PASSPHRASE_TEXT_NOT_EMPTY, &printed_len);	\
	if (printed_len)						\
	  xprintf("\e[%zuD", printed_len);				\
      }									\
    *(rc + len++) = (char)c;						\
  })
#else
#  define append_char()	 (xputchar(c), *(rc + len++) = (char)c)
#endif


#define insert_char()					\
  ({							\
    if ((c & 0xC0) != 0x80)				\
      xprintf("\033[@");				\
    xputchar(c);					\
    for (i = len; i > point; i--)			\
      *(rc + i) = *(rc + i - 1);			\
    len++;						\
    *(rc + point++) = (char)c;				\
  })


#define override_char()						\
  ({								\
    size_t n = 1;						\
    char cn = (char)c;						\
    while ((*(rc + point + n) & 0xC0) == 0x80)			\
      n++;							\
    for (i = point + n; i < len; i++)				\
      *(rc + i - n) = *(rc + i);				\
    passphrase_wipe(rc + len - n, n);				\
    len -= n;							\
    n = 0;							\
    while (cn & 0x80)						\
      {								\
	cn = (char)(cn << 1);					\
	n++;							\
      }								\
    n = n ?: 1;							\
    if (len + n > size)						\
      {								\
	if ((rc = xrealloc(rc, size, size << 1L)) == NULL)	\
	  return NULL;						\
	size <<= 1L;						\
      }								\
    len += n;							\
    for (i = len - 1; i > point + n; i--)			\
      *(rc + i) = *(rc + i - n);				\
    if (len - 1 >= point + n)					\
      *(rc + point + n) = *(rc + point);			\
    for (i = 0; i < n; i++)					\
      {								\
	if (i)							\
	  c = getchar();					\
	xputchar(c);						\
	*(rc + point++) = (char)c;				\
      }								\
  })


/* Implementation of the delete-key's action upon the display */
#if defined(PASSPHRASE_TEXT)
#  define print_delete()							\
  (len == 0 ? 0 : (xprintf("\e[K%s%zn", PASSPHRASE_TEXT_EMPTY, &printed_len),	\
		   (printed_len ? xprintf("\e[%zuD", printed_len) : 0)))
#else
#  define print_delete()  xprintf("\033[P")
#endif


/* Implementation of the erase-key's action upon the display */
#if defined(PASSPHRASE_TEXT)
#  define print_erase()								\
  (len == 0 ? 0 : (xprintf("\e[K%s%zn", PASSPHRASE_TEXT_EMPTY, &printed_len),	\
		   (printed_len ? xprintf("\e[%zuD", printed_len) : 0)))
#elif defined(PASSPHRASE_MOVE)
#  define print_erase()  xprintf("\033[D\033[P")
#elif defined(PASSPHRASE_STAR)
#  define print_erase()  xprintf("\033[D \033[D")
#endif



#endif