/**
* @mainpage Yep Utility.
*
* Software for encryption/decryption of private text data.\n
* System requirements:
* - Compiler: cc/gcc
* - Compile options: -ansi -std=c99
*
* Contact: valsorym.e@gmail.com \n
* Copyright (c) 2012 valsorym. All rights reserved.
*/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <termios.h>
#include <sys/time.h>
#include <unistd.h>
/* DEFINES */
/*---------------------------------------------------------------------------*/
/**
* @def ARGV_HELP
* @brief The list of arguments to display help information.
*
* @def ARGV_NEWPASS
* @brief The list of arguments to change the password on the specified file.
*
* @def ARGV_TEMPDIR
* @brief The list of arguments to specify a directory for storing
* temporary files.
*
* @def ARGV_HOOKWORD
* @brief The list of arguments to specify the protection word.
*/
#define ARGV_HELP 2, "-i", "-h"
#define ARGV_NEWPASS 1, "-p"
#define ARGV_TEMPDIR 1, "-d"
#define ARGV_HOOKWORD 1, "-w"
/**
* @def DEFAULT_HOOKWORD
* @brief Protection word by default. Use if not specified arguments
* are \a ARGV_HOOKWORD.
*
* @def DEFAULT_TEMPDIR
* @brief Directory for storing temporary files by default. Use if not
* specified arguments are \a ARGV_TEMPDIR.
*/
#define DEFAULT_HOOKWORD "howdy"
#define DEFAULT_TEMPDIR "/tmp/yep"
/**
* @def MAXLEN_BUF
* @brief The maximum length of text buffer. The buffer used to read lines
* from a file, encode/decode strings.
*
* @def MAXLEN_PATH
* @brief The maximum permissible length of the path to the file including
* the file name.
*
* @def MAXLEN_SYSKEY
* @brief Maximum length of keywords: passwords, hookword.
*
* @def MAXLEN_TEMPNAME
* @brief The maximum permissible length of the temporary file name.
*/
#define MAXLEN_BUF 4096
#define MAXLEN_PATH 255
#define MAXLEN_SYSKEY 15
#define MAXLEN_TEMPNAME 10
/* NEWTYPES */
/*---------------------------------------------------------------------------*/
/**
* @enum bool
* @brief Boolean data type. etc. \e c99 _Bool.
*/
typedef enum {
false=0, /**< True value. */
true /**< False value. */
} bool;
/**
* @enum cmethod
* @brief Direction of encryption: encrypt, decrypt.
*/
typedef enum {
encode=1, /**< Encrypt a file. */
decode=-1 /**< Decrypt a file. */
} cmethod;
/**
* @enum cstatus
* @brief The status of the encrypting/decrypting the file.
*/
typedef enum {
no_err=0, /**< Encryption/decryption is successful. */
err_hookword, /**< Decrypted file can not be obtained because of
* not correct password/hookword. */
o_err_read, /**< Can not open for reading the original file. */
t_err_read, /**< Can not open for reading the temp file. */
o_err_write, /**< Can not open for writing the original file. */
t_err_write, /**< Can not open for writing the temp file. */
o_err_save, /**< Can not save the original file.
* Error function fclose(). */
t_err_save, /**< Can not save the temp file.
* Error function fclose(). */
o_err_create, /**< Can not create the original file.
* Error function createyep(). */
t_err_create /**< Can not create the temp file.
* Error function createyep(). */
} cstatus;
/**
* @enum maintype
* @brief The way to open the file.
*/
typedef enum {
editfile, /**< The file is open to change/read. */
changepass /**< The file is opened to change the password. */
} maintype;
/* SYSTEM FUNCTIONS */
/*---------------------------------------------------------------------------*/
extern bool tsarg(const char *, int , ...);
extern void errexit(const char *, ...);
extern char *geths(char [], int );
extern int intrand(int );
extern char *strrand(char [], int );
extern char csymbol(const char , int );
extern bool cstr(char [], int , const char *, const char *, cmethod );
extern bool createyep(const char *, const char *, const char *);
extern cstatus decodingfile(const char *, const char *,
const char *, const char *);
extern cstatus encodingfile(const char *, const char *,
const char *, const char *);
extern int terminal(const char *, ...);
/* SCREEN FUNCTIONS */
/*---------------------------------------------------------------------------*/
extern void s_help(void);
extern void s_main(const char *, const char *, const char *,
const char *, maintype );
/* VIRTUAL SCREEN FUNCTIONS */
/*---------------------------------------------------------------------------*/
extern void vs_newpass(char [], char [], const char *);
/* MAIN */
/*---------------------------------------------------------------------------*/
/**
* @brief Yep main function.
*
* @param argc Count of arguments passed.
* @param argv The list of arguments.
*
* @return Returns zero on success of the program.
*/ //*
int
main(int argc, char **argv)
{
// "editor" - text editor software.
// "tempdir" - store temporary files.
// "hookword" - indicator for file recovery.
char *editor = NULL,
*tempdir = NULL,
*hookword = NULL;
// The program requires access to the UNIX shell.
if (!system(NULL))
errexit("The UNIX shell is not available.\n");
// Must be at least one external argument.
if (argc < 2)
errexit("See the help page on the program.\n");
// Read the arguments list.
for (int i = 1; i < argc; ++i)
if (tsarg(argv[i], ARGV_HELP))
// Show help screen.
s_help();
else if (tsarg(argv[i], ARGV_HOOKWORD)) {
// Read hookword.
if (++i < argc)
hookword = argv[i];
else
errexit("Hookword parameter is not specified.\n");
} else if (tsarg(argv[i], ARGV_TEMPDIR)) {
// Read tempdir.
if (++i < argc)
tempdir = argv[i];
else
errexit("Tempdir parameter is not specified.\n");
} else if (tsarg(argv[i], ARGV_NEWPASS)) {
// Set new password on file.
if (++i < argc) {
if (!hookword)
hookword = DEFAULT_HOOKWORD;
if (!tempdir)
tempdir = DEFAULT_TEMPDIR;
s_main(hookword, editor, argv[i], tempdir, changepass);
} else
errexit("Don't specify a file for change the password.\n");
} else {
// Get the editor and a filename.
editor = argv[i];
if (++i < argc) {
if (i + 1 < argc)
errexit("Too many arguments.\n");
if (!hookword)
hookword = DEFAULT_HOOKWORD;
if (!tempdir)
tempdir = DEFAULT_TEMPDIR;
s_main(hookword, editor, argv[i], tempdir, editfile);
} else
errexit("The file is not specified.\n");
} // end if ().
return 0;
} // end main(). */
/* SYSTEM FUNCTIONS */
/*---------------------------------------------------------------------------*/
/**
* @brief To determine whether an \a arg list of available string
* arguments \a (...).
*
* @param arg Argument (string) for comparison.
* @param count Number of arguments in the list of comparisons.
* @param ... List of comparisons.
*
* @return
* - true - If the argument \a arg corresponds to at least one argument
* from the argument list.
* - false - If the argument \a arg does not correspond to any argument
* from the argument list.
*/ //*
bool
tsarg(const char *arg, int count, ...)
{
va_list ptr;
char *str = NULL;
bool result = false;
// The argument list is empty.
if (count < 1)
return result;
// Find the argument.
va_start(ptr, count);
while ((str = va_arg(ptr, char *))
&& !result && count-- > 0)
if (!strcmp(arg, str))
result = true;
va_end(ptr);
return result;
} // end tsarg(). */
/**
* @brief Exit on error.
*
* @detailed This function takes cover those arguments as printf() function
* from the C standard library.
*
* @param format Error message.
* @param ... The data formatting.
*
* @return No data is returned.
*/ //*
void
errexit(const char *format, ...)
{
va_list ptr;
char buf[MAXLEN_BUF];
// Format the error message.
va_start(ptr, format);
sprintf(buf, "*** Error: %s.", format);
vfprintf(stderr, buf, ptr);
va_end(ptr);
exit(1);
} // end errexit(). */
/**
* @brief Read from standard input hidden line.
*
* @param buf The buffer where written to a string from stdin.
* @param bufsize The size of the buffer.
*
* @return Returns a pointer to the line of input that is placed in the
* buffer \a buf.
*/ //*
char
*geths(char buf[], int bufsize)
{
struct termios term, oldterm;
int ch, i = 0, max = bufsize - 1;
// Do not display the characters as you type.
tcgetattr(0, &term);
oldterm = term;
term.c_lflag &= ~ECHO; // Does not display the characters.
term.c_lflag &= ~ICANON; // Do not expect the press enter.
tcsetattr(0, TCSANOW, &term);
// Read the hidden characters.
while ((ch = getchar()) != EOF && ch != '\n')
if (ch == 127 || ch == 8 || ch == '\b') {
if (i > 0) i--;
} else if (i < max)
buf[i++] = ch;
buf[i++] = '\0';
// Restore the old display options.
term = oldterm;
tcsetattr(0, TCSANOW, &term);
return buf;
} // end geths(). */
/**
* @brief Generate random number.
*
* @param max The right border of the generated numbers.
*
* @return The function returns a random number between \a 0 and \a max. When
* the function returns an error number \a -1.
*
* @see strrand().
*/ //*
int
intrand(int max)
{
struct timeval tp;
struct timezone tzp;
unsigned stime;
// There is an extreme right edge.
max = abs(max);
if (max >= 32767)
return -1;
// Random number depends on the microseconds.
if (gettimeofday(&tp, &tzp) == -1)
return -1;
stime = (unsigned)tp.tv_usec;
srand(stime);
// Return a random number in the range 0 ... max.
return abs(rand()%max);
} // end intrand(). */
/**
* @brief Create a random string.
*
* @param buf A random sequence of characters will be written into this buffer.
* @param bufsize The size of the buffer.
*
* @return Returns a pointer to a random string that was placed in the
* buffer \a buf.
*
* @see intrand().
*/ //*
char
*strrand(char buf[], int bufsize)
{
char *alphabet = "QWERTYUIOPASDFGHJKLZXCVBNM"
"qwertyuiopasdfghjklzxcvbnm"
"1234567890";
int alphsize = strlen(alphabet);
// The minimum buffer size - 1 bytes.
if (bufsize <= 0)
return NULL;
// Generate random string.
for (int i=0; i<bufsize; ++i) {
int rn = intrand(alphsize);
if (rn >= 0 && rn < alphsize)
buf[i] = *(alphabet + rn);
else if (i > 0)
--i;
} // end for ().
buf[bufsize-1] = '\0';
return buf;
} // end strrand(). */
/**
* @brief Encode a character offset.
*
* @param ch The symbol to encode.
* @param seek The shift to encode.
*
* @return Returns the encoded (If \a seek variable > = 0)/decoded (If
* \a seek variable <0) symbol. If symbol failed to encode/decode, returns the
* character \a ch variable .
*
* @see cstr().
*/ //*
char
csymbol(const char ch, int seek)
{
char result = ch;
char *alphabet = "QWERTYUIOPASDFGHJKLZXCVBNM"
"qwertyuiopasdfghjklzxcvbnm"
"1234567890 !@#$%^&*()_-+{}:";
int alphsize = strlen(alphabet);
// Determine the symbol.
for (int i=0; i < alphsize; ++i)
if (ch == *(alphabet + i)) {
seek += i;
while (seek >= alphsize)
seek -= alphsize;
while (seek < 0)
seek += alphsize;
if (seek >= 0 && seek < alphsize)
result = *(alphabet + seek);
break;
} // end if ().
return result;
} // end csymbol(). */
/**
* @brief Cryptography string.
*
* @param buf Encoded string is placed in the buffer.
* @param bufsize The size of the buffer.
* @param str The string to encode.
* @param pass Password to encrypt the string.
* @param method Method: encode/decode.
*
* @return
* - true - If the string \a str has been successfully encoded/decoded
* and placed in buffer \a buf.
* - false - If you encode/decode the string is impossible.
*
* @see csymbol().
*/ //*
bool
cstr(char buf[], int bufsize, const char *str, const char *pass,
cmethod method)
{
int len = strlen(pass), seek=0;
bool result = true;
// Determine the offset.
for (int i = 0; i < len; ++i)
seek = seek + ((int)(char)*(pass + i)) * i;
// Can I put the original in the buffer?
// Determine the count of processed symbols.
len = strlen(str);
if (len > bufsize - 1)
result = false;
// encode || decode str.
if (result) {
for (int i = 0; i < len; ++i)
buf[i] = csymbol((char)*(str+i), (seek + i) * method);
buf[len] = '\0';
} else
buf[0] = '\0';
return result;
} // end cstr(). */
/**
* @brief Creates an empty yep-file recording it encoded a keyword (hookword).
*
* @param hookword Word of the key.
* @param pass Password.
* @param file The file to be created.
*
* @return
* - true - If the file is successfully created.
* - false - An error occurred while creating the file.
*/ //*
bool
createyep(const char *hookword, const char *pass,
const char *file)
{
FILE *f_file;
char buf[MAXLEN_BUF];
if (!(f_file = fopen(file, "w")))
return false;
cstr(buf, MAXLEN_BUF, hookword, pass, encode);
strncat(buf, "\n", MAXLEN_BUF);
fputs(buf, f_file);
if(fclose(f_file))
return false;
return true;
} // end createyep(). */
/**
* @brief Вуcode file.
*
* @param hookword Word of the key.
* @param pass Password.
* @param file File for decoding.
* @param tempfile The temporary file.
*
* @return
* - no_err - If the operation is executed without error.
* - o_err_read - Can not open file \a file for reading.
* - t_err_write - Can not open file \a tempfile for writing.
* - err_hookword - Wrong password or secret word.
* - o_err_save - Unable to save file \a file.
* - t_err_save - Unable to save file \a tempfile.
*
* @see encodingfile().
*/ //*
cstatus
decodingfile(const char *hookword, const char *pass, const char *file,
const char *tempfile)
{
FILE *f_file, *f_tempfile;
char buf[MAXLEN_BUF], str[MAXLEN_BUF];
bool hw_tested = false, result = no_err;
if (!(f_file = fopen(file, "r")))
return o_err_read;
if (!(f_tempfile = fopen(tempfile, "w"))) {
fclose(f_file);
return t_err_write;
} // end if ().
// Encoding file.
while(!feof(f_file)) {
if (!hw_tested) {
// Read hookword.
hw_tested = true;
if(fgets(buf, MAXLEN_BUF, f_file)) {
buf[strlen(buf)-1] = '\0'; // Remove "\n" symbol.
cstr(str, MAXLEN_BUF, buf, pass, decode);
if (strcmp(str, hookword)) {
result = err_hookword;
break;
} // end if ().
} else {
result = err_hookword;
break;
}
} else {
// Read body.
buf[0] = '\0';
str[0] = '\0';
if(fgets(buf, MAXLEN_BUF, f_file)) {
cstr(str, MAXLEN_BUF, buf, pass, decode);
fputs(str, f_tempfile);
} // end if ().
} // end if ().
} // end while ().
if(fclose(f_file)) {
fclose(f_tempfile);
return o_err_save;
} // end if ().
if(fclose(f_tempfile))
return t_err_save;
return result;
} // end decodingfile(). */
/**
* @brief Encode file.
*
* @param hookword Word of the key.
* @param pass Password.
* @param file File for decoding.
* @param tempfile The temporary file.
*
* @return
* - no_err - If the operation is executed without error.
* - o_err_create - If the function createyep() caused the error,
* etc. can not create file \a file.
* - o_err_write - Can not open file for writing \a file.
* - t_err_read - Can not open file for reading \a tempfile.
* - o_err_save - Unable to close file \a file.
* - t_err_save - Unable to close file \a tempfile.
*
* @see decodingfile().
*/ //*
cstatus
encodingfile(const char *hookword, const char *pass, const char *file,
const char *tempfile)
{
FILE *f_file, *f_tempfile;
char buf[MAXLEN_BUF], str[MAXLEN_BUF];
bool result = no_err;
if (!createyep(hookword, pass, file))
return o_err_create;
if (!(f_file = fopen(file, "a")))
return o_err_write;
if (!(f_tempfile = fopen(tempfile, "r"))) {
fclose(f_file);
return t_err_read;
} // end if ().
// Decoding file.
while(!feof(f_tempfile)) {
// Write body.
buf[0] = '\0';
str[0] = '\0';
if(fgets(buf, MAXLEN_BUF, f_tempfile)) {
cstr(str, MAXLEN_BUF, buf, pass, encode);
fputs(str, f_file);
}
} // end while ().
if(fclose(f_file)) {
fclose(f_tempfile);
return o_err_save;
} // end if ();
if(fclose(f_tempfile))
return t_err_save;
return result;
} // end encodingfile(). */
/**
* @brief Executing shell commands.
*
* @detailed This function takes cover those arguments as printf() function
* from the C standard library.
*
* @param format Command for the terminal.
* @param ... Formatting options.
*
* @return Returns integer - the result of a shell command.
*/ //*
int
terminal(const char *format, ...)
{
va_list ptr;
char buf[MAXLEN_BUF];
va_start(ptr, format);
vsprintf(buf, format, ptr);
va_end(ptr);
return system(buf);
} // end terminal(). */
/* SCREEN FUNCTIONS */
/*---------------------------------------------------------------------------*/
/**
* @brief Show help page.
*
* @return No data is returned.
*/ //*
void
s_help(void)
{
printf("\nNAME\n"
"\tyep - encrypted text files.\n\n"
"SYNOPSIS\n"
"\tyep [-w hookword] [-d tempdir] editor file\n"
"\tyep [-h | -i]\n"
"\tyep [-w hookword] [-d tempdir] -p file\n\n"
"DESCRIPTION\n"
"\tyep program allows you to encrypt text files using the "
"public key.\n\n"
"OPTIONS\n"
"\t-w hookword\n"
"\t\tEstablishes additional protection for the word file. This \n"
"\t\tword should be that you could safely recover an encrypted \n"
"\t\tfile. If the word is not specified - the word will be used \n"
"\t\tby default.\n"
"\t-p file\n"
"\t\tThe flag allows you to change the previously set password,\n"
"\t\tand the protection word (hookword).\n"
"\t-d tempdir\n"
"\t\tSets the directory for storing temporary files.\n"
"\t-h, -i\n"
"\t\tDisplay help information about the program.\n"
"\teditor\n"
"\t\tSpecify a text editor synchronous: vi, vim, ee ... Use \n"
"\t\tasynchronous editors (geany &, emacs & ...) - is impossible.\n"
"\tfile\n"
"\t\tThe file to be encrypted / decrypted. If the file does not \n"
"\t\texist - it is created.\n\n"
"BUGS\n"
"\tEmail bug reports to iam@valsorym.com. Be sure to include \n"
"\tthe word \"yep bugs\" somewhere in the \"Subject:\" field.\n");
exit(0);
} // end help(). */
/**
* @brief The main function of encoding, decoding, and change the
* password on file.
*
* @param hookword Secret word.
* @param editor Synchronous text editor.
* @param file File manipulation.
* @param tempdir The directory for storing temporary files.
* @param type The method of handling file: encoding/decoding or change
* your password.
*
* @return No data is returned.
*/ //*
void
s_main(const char *hookword, const char *editor, const char *file,
const char *tempdir, maintype type)
{
char newhookword[MAXLEN_SYSKEY],
passagain[MAXLEN_SYSKEY],
pass[MAXLEN_SYSKEY];
bool existfile = false,
existeditor = false;
char tempname[MAXLEN_TEMPNAME],
tempfile[MAXLEN_PATH];
int len = 0;
// Create a random filename for a temporary file.
do {
if (!strrand(tempname, MAXLEN_TEMPNAME))
errexit("Unable to create a temporary name.\n");
len = strlen(tempname);
} while (len < MAXLEN_TEMPNAME/2);
if (strlen(tempdir) + MAXLEN_TEMPNAME > MAXLEN_PATH)
errexit("A very long name for a temporary file.\n");
sprintf(tempfile, "%s/%s", tempdir, tempname);
// Create a YEP temporary directory.
if (terminal("ls -l -d %s | grep ^d", tempdir))
if (terminal("mkdir -p %s", tempdir))
errexit("Can not create a directory for storing "
"temporary files.\n");
// Check for the file.
if (!(existfile = !terminal("ls -l -d %s | grep ^-", file)))
if (!terminal("ls -l -d %s | grep ^d", file)) {
// There exists a directory with that name: filename.
terminal("clear");
errexit("There exists a directory with that name: %s.\n", file);
} // end if ().
// Checking the editor.
existeditor = !terminal("which %s", editor);
terminal("clear");
// Create interface.
printf("This will open the file with the following parameters:\n");
printf(" Filename%s:\t%s\n", (existfile ? (char*)"" :
(char*)" (file not exist)"), file);
if (type == editfile)
printf(" Editor%s:\t%s\n", (existeditor ? (char*)"" :
(char*)" (editor is not installed)"), editor);
printf(" Hookword%s:\t%s\n\n", (!strcmp(DEFAULT_HOOKWORD, hookword) ?
(char*)" (default word protection)" : (char*)""), hookword);
if (type == editfile) {
// Just open file.
if (!existeditor)
errexit("Editor is not installed: %s.\n", editor);
} else if (type == changepass) {
// Change password.
if (!existfile)
errexit("Сan not change the password on this file: %s.\n", file);
} else
// Bad type parameter.
errexit("Is not valid action.\n");
// end if ().
// Read the password.
printf("\nTo exit, press Ctrl+C.\n");
while (true) {
printf("\nPassword: ");
geths(pass, MAXLEN_SYSKEY);
if (!existfile) {
printf("\nEnter password again: ");
geths(passagain, MAXLEN_SYSKEY);
if (strcmp(pass, passagain))
printf("\nPasswords do not match. Please, enter again.\n");
else {
// Need create file.
if (!createyep(hookword, pass, file))
errexit("The file can not be created: %s.\n", file);
break;
}
} else
break;
// end if ().
} // end while ().
printf("\n");
// Decoding.
switch ((int)decodingfile(hookword, pass, file, tempfile)) {
case (int)o_err_read:
errexit("Can not open file: %s.\n", file);
break;
case (int)t_err_write:
errexit("Unable to open temporary file for writing: %s.\n",
tempfile);
break;
case (int)err_hookword:
errexit("Hookword was not recognized.\n");
break;
case (int)o_err_save:
errexit("Unable to close file: %s.\n", file);
break;
case (int)t_err_save:
errexit("Unable to close file: %s.\n", tempfile);
break;
} // end switch ().
if (type == editfile) {
// Open editor.
if (terminal("%s %s", editor, tempfile))
errexit("Can not open file: %s.\n", tempfile);
} else if (type == changepass) {
// Change password.
sprintf(newhookword, "%s", hookword);
vs_newpass(newhookword, pass, file);
hookword = newhookword;
} // end if ().
// Encoding again.
switch ((int)encodingfile(hookword, pass, file, tempfile)) {
case (int)o_err_create:
errexit("Can not create file: %s.\n", file);
break;
case (int)o_err_write:
errexit("Unable to write data to file: %s.\n", file);
break;
case (int)t_err_read:
errexit("Unable to read data from the temfile: %s.\n", tempfile);
break;
case (int)o_err_save:
errexit("Can not save the file: %s.\n", file);
break;
case (int)t_err_save:
errexit("Can not save the file: %s.\n", tempfile);
break;
} // end switch ().
// Remove temp file.
if (terminal("rm -f %s", tempfile))
printf("\nThe temporary file was not deleted: %s.\n", tempfile);
exit(0);
} // end s_main(). */
/**
* @brief Function-interface to change password.
*
* @param hookword Buffer storage keyword.
* @param pass Buffer storage password.
* @param file The file to change the password.
*
* @return No data is returned.
*/ //*
void
vs_newpass(char hookword[], char pass[], const char *file)
{
char passagain[MAXLEN_SYSKEY],
cmd;
// Go-go-go!!!
while (true) {
terminal("clear");
printf("You are trying to change the system "
"data to a file: %s.\n", file);
printf("Choose one of the actions:\n");
printf(" 1. Change password (*******).\n");
printf(" 2. Change hookword (%s).\n", hookword);
printf(" 3. Save and exit.");
printf("\nTo exit, press Ctrl+C.\n");
printf("\nYour choice: ");
scanf("%c", &cmd);
while (getchar() != '\n'); // Clear stdin buffer. Bad method. :(
if (cmd == '1') {
// Change password.
while (true) {
printf("\nEnter new password: ");
geths(pass, MAXLEN_SYSKEY);
printf("\nEnter password again: ");
geths(passagain, MAXLEN_SYSKEY);
if (strcmp(pass, passagain))
printf("\nPasswords do not match. Please, enter again.\n");
else
break;
} // end while ().
} else if (cmd == '2') {
// Change hookword.
char hwformat[15];
sprintf(hwformat, "%%%ds", MAXLEN_SYSKEY-1);
printf("\nEnter new hookword: ");
scanf(hwformat, hookword);
while (getchar() != '\n'); // Clear stdin buffer. Bad method. :(
} else if (cmd == '3') {
// Save and exit;
terminal("clear");
printf("\nThe changes take effect.\n");
return;
} // end if ().
} // end while ().
exit(0);
} // end vs_newpass(). */
/* The End. */