mirror of
git://git.gnupg.org/gnupg.git
synced 2025-04-13 22:21:09 +02:00
Implement the server comamnd DECRYPT.
Use int instead of gnupg_fd_t in the server. Comment fixes. Rename encr-data.c -> decrypt-data.c
This commit is contained in:
parent
3b7dc7b384
commit
71625f56fd
@ -1,3 +1,13 @@
|
|||||||
|
2009-10-02 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
|
* server.c (cmd_encrypt, cmd_decrypt): Implement.
|
||||||
|
* decrypt.c (decrypt_message_fd): New.
|
||||||
|
* options.h (struct opt): Add field OUTFP.
|
||||||
|
* plaintext.c (handle_plaintext): Support opt.outfp.
|
||||||
|
|
||||||
|
* encr-data.c: Rename to decrypt-data.c to reflect the action and
|
||||||
|
not the processed packet type.
|
||||||
|
|
||||||
2009-10-02 Werner Koch <wk@g10code.com>
|
2009-10-02 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
* encr-data.c (decode_filter_context_s): Add fields PARTIAL and
|
* encr-data.c (decode_filter_context_s): Add fields PARTIAL and
|
||||||
|
@ -79,13 +79,13 @@ gpg2_SOURCES = gpg.c \
|
|||||||
pubkey-enc.c \
|
pubkey-enc.c \
|
||||||
passphrase.c \
|
passphrase.c \
|
||||||
seckey-cert.c \
|
seckey-cert.c \
|
||||||
encr-data.c \
|
decrypt.c \
|
||||||
|
decrypt-data.c \
|
||||||
cipher.c \
|
cipher.c \
|
||||||
encrypt.c \
|
encrypt.c \
|
||||||
sign.c \
|
sign.c \
|
||||||
verify.c \
|
verify.c \
|
||||||
revoke.c \
|
revoke.c \
|
||||||
decrypt.c \
|
|
||||||
keyedit.c \
|
keyedit.c \
|
||||||
dearmor.c \
|
dearmor.c \
|
||||||
import.c \
|
import.c \
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* encr-data.c - process an encrypted data packet
|
/* decrypt-data.c - Decrypt an encrypted data packet
|
||||||
* Copyright (C) 1998, 1999, 2000, 2001, 2005,
|
* Copyright (C) 1998, 1999, 2000, 2001, 2005,
|
||||||
* 2006, 2009 Free Software Foundation, Inc.
|
* 2006, 2009 Free Software Foundation, Inc.
|
||||||
*
|
*
|
@ -97,6 +97,73 @@ decrypt_message (const char *filename)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Same as decrypt_message but takes a file descriptor for input and
|
||||||
|
output. */
|
||||||
|
gpg_error_t
|
||||||
|
decrypt_message_fd (int input_fd, int output_fd)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
IOBUF fp;
|
||||||
|
armor_filter_context_t *afx = NULL;
|
||||||
|
progress_filter_context_t *pfx;
|
||||||
|
|
||||||
|
if (opt.outfp)
|
||||||
|
return gpg_error (GPG_ERR_BUG);
|
||||||
|
|
||||||
|
pfx = new_progress_context ();
|
||||||
|
|
||||||
|
/* Open the message file. */
|
||||||
|
fp = iobuf_open_fd_or_name (input_fd, NULL, "rb");
|
||||||
|
if (fp && is_secured_file (iobuf_get_fd (fp)))
|
||||||
|
{
|
||||||
|
iobuf_close (fp);
|
||||||
|
fp = NULL;
|
||||||
|
errno = EPERM;
|
||||||
|
}
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
char xname[64];
|
||||||
|
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
snprintf (xname, sizeof xname, "[fd %d]", input_fd);
|
||||||
|
log_error (_("can't open `%s': %s\n"), xname, gpg_strerror (err));
|
||||||
|
release_progress_context (pfx);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
opt.outfp = fdopen (dup (output_fd), "wb");
|
||||||
|
if (!opt.outfp)
|
||||||
|
{
|
||||||
|
char xname[64];
|
||||||
|
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
snprintf (xname, sizeof xname, "[fd %d]", output_fd);
|
||||||
|
log_error (_("can't open `%s': %s\n"), xname, gpg_strerror (err));
|
||||||
|
iobuf_close (fp);
|
||||||
|
release_progress_context (pfx);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!opt.no_armor)
|
||||||
|
{
|
||||||
|
if (use_armor_filter (fp))
|
||||||
|
{
|
||||||
|
afx = new_armor_context ();
|
||||||
|
push_armor_filter ( afx, fp );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = proc_encryption_packets ( NULL, fp );
|
||||||
|
|
||||||
|
iobuf_close (fp);
|
||||||
|
fclose (opt.outfp);
|
||||||
|
opt.outfp = NULL;
|
||||||
|
release_armor_context (afx);
|
||||||
|
release_progress_context (pfx);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
decrypt_messages (int nfiles, char *files[])
|
decrypt_messages (int nfiles, char *files[])
|
||||||
{
|
{
|
||||||
|
@ -264,8 +264,7 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
|
|||||||
do_compress = 0;
|
do_compress = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( rc || (rc = open_outfile (GNUPG_INVALID_FD, filename,
|
if ( rc || (rc = open_outfile (-1, filename, opt.armor? 1:0, &out )))
|
||||||
opt.armor? 1:0, &out )))
|
|
||||||
{
|
{
|
||||||
iobuf_cancel (inp);
|
iobuf_cancel (inp);
|
||||||
xfree (cfx.dek);
|
xfree (cfx.dek);
|
||||||
@ -462,9 +461,9 @@ write_symkey_enc (STRING2KEY *symkey_s2k, DEK *symkey_dek, DEK *dek,
|
|||||||
* PROVIDED_PKS; if not the function builds a list of keys on its own.
|
* PROVIDED_PKS; if not the function builds a list of keys on its own.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
encrypt_crypt (gnupg_fd_t filefd, const char *filename,
|
encrypt_crypt (int filefd, const char *filename,
|
||||||
strlist_t remusr, int use_symkey, pk_list_t provided_keys,
|
strlist_t remusr, int use_symkey, pk_list_t provided_keys,
|
||||||
gnupg_fd_t outputfd)
|
int outputfd)
|
||||||
{
|
{
|
||||||
iobuf_t inp = NULL;
|
iobuf_t inp = NULL;
|
||||||
iobuf_t out = NULL;
|
iobuf_t out = NULL;
|
||||||
@ -482,7 +481,7 @@ encrypt_crypt (gnupg_fd_t filefd, const char *filename,
|
|||||||
PK_LIST pk_list, work_list;
|
PK_LIST pk_list, work_list;
|
||||||
int do_compress;
|
int do_compress;
|
||||||
|
|
||||||
if (filefd != GNUPG_INVALID_FD && filename)
|
if (filefd != -1 && filename)
|
||||||
return gpg_error (GPG_ERR_INV_ARG);
|
return gpg_error (GPG_ERR_INV_ARG);
|
||||||
|
|
||||||
do_compress = opt.compress_algo && !RFC1991;
|
do_compress = opt.compress_algo && !RFC1991;
|
||||||
@ -539,7 +538,7 @@ encrypt_crypt (gnupg_fd_t filefd, const char *filename,
|
|||||||
char xname[64];
|
char xname[64];
|
||||||
|
|
||||||
rc = gpg_error_from_syserror ();
|
rc = gpg_error_from_syserror ();
|
||||||
if (filefd != GNUPG_INVALID_FD)
|
if (filefd != -1)
|
||||||
snprintf (xname, sizeof xname, "[fd %d]", filefd);
|
snprintf (xname, sizeof xname, "[fd %d]", filefd);
|
||||||
else if (!filename)
|
else if (!filename)
|
||||||
strcpy (xname, "[stdin]");
|
strcpy (xname, "[stdin]");
|
||||||
@ -652,7 +651,7 @@ encrypt_crypt (gnupg_fd_t filefd, const char *filename,
|
|||||||
if (!opt.no_literal)
|
if (!opt.no_literal)
|
||||||
pt = setup_plaintext_name (filename, inp);
|
pt = setup_plaintext_name (filename, inp);
|
||||||
|
|
||||||
if (filefd != GNUPG_INVALID_FD
|
if (filefd != -1
|
||||||
&& !iobuf_is_pipe_filename (filename) && *filename && !opt.textmode )
|
&& !iobuf_is_pipe_filename (filename) && *filename && !opt.textmode )
|
||||||
{
|
{
|
||||||
off_t tmpsize;
|
off_t tmpsize;
|
||||||
@ -964,8 +963,7 @@ encrypt_crypt_files (int nfiles, char **files, strlist_t remusr)
|
|||||||
}
|
}
|
||||||
line[strlen(line)-1] = '\0';
|
line[strlen(line)-1] = '\0';
|
||||||
print_file_status(STATUS_FILE_START, line, 2);
|
print_file_status(STATUS_FILE_START, line, 2);
|
||||||
rc = encrypt_crypt (GNUPG_INVALID_FD, line, remusr, 0,
|
rc = encrypt_crypt (-1, line, remusr, 0, NULL, -1);
|
||||||
NULL, GNUPG_INVALID_FD);
|
|
||||||
if (rc)
|
if (rc)
|
||||||
log_error ("encryption of `%s' failed: %s\n",
|
log_error ("encryption of `%s' failed: %s\n",
|
||||||
print_fname_stdin(line), g10_errstr(rc) );
|
print_fname_stdin(line), g10_errstr(rc) );
|
||||||
@ -977,8 +975,7 @@ encrypt_crypt_files (int nfiles, char **files, strlist_t remusr)
|
|||||||
while (nfiles--)
|
while (nfiles--)
|
||||||
{
|
{
|
||||||
print_file_status(STATUS_FILE_START, *files, 2);
|
print_file_status(STATUS_FILE_START, *files, 2);
|
||||||
if ( (rc = encrypt_crypt (GNUPG_INVALID_FD, *files, remusr, 0,
|
if ( (rc = encrypt_crypt (-1, *files, remusr, 0, NULL, -1)) )
|
||||||
NULL, GNUPG_INVALID_FD)) )
|
|
||||||
log_error("encryption of `%s' failed: %s\n",
|
log_error("encryption of `%s' failed: %s\n",
|
||||||
print_fname_stdin(*files), g10_errstr(rc) );
|
print_fname_stdin(*files), g10_errstr(rc) );
|
||||||
write_status( STATUS_FILE_DONE );
|
write_status( STATUS_FILE_DONE );
|
||||||
|
@ -3434,8 +3434,7 @@ main (int argc, char **argv)
|
|||||||
{
|
{
|
||||||
if( argc > 1 )
|
if( argc > 1 )
|
||||||
wrong_args(_("--encrypt [filename]"));
|
wrong_args(_("--encrypt [filename]"));
|
||||||
if( (rc = encrypt_crypt (GNUPG_INVALID_FD, fname,
|
if( (rc = encrypt_crypt (-1, fname, remusr, 0, NULL, -1)) )
|
||||||
remusr, 0, NULL, GNUPG_INVALID_FD)) )
|
|
||||||
log_error("%s: encryption failed: %s\n",
|
log_error("%s: encryption failed: %s\n",
|
||||||
print_fname_stdin(fname), g10_errstr(rc) );
|
print_fname_stdin(fname), g10_errstr(rc) );
|
||||||
}
|
}
|
||||||
@ -3456,8 +3455,7 @@ main (int argc, char **argv)
|
|||||||
" while in %s mode\n"),compliance_option_string());
|
" while in %s mode\n"),compliance_option_string());
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( (rc = encrypt_crypt (GNUPG_INVALID_FD, fname,
|
if( (rc = encrypt_crypt (-1, fname, remusr, 1, NULL, -1)) )
|
||||||
remusr, 1, NULL, GNUPG_INVALID_FD)) )
|
|
||||||
log_error("%s: encryption failed: %s\n",
|
log_error("%s: encryption failed: %s\n",
|
||||||
print_fname_stdin(fname), g10_errstr(rc) );
|
print_fname_stdin(fname), g10_errstr(rc) );
|
||||||
}
|
}
|
||||||
|
@ -185,9 +185,9 @@ void display_online_help( const char *keyword );
|
|||||||
int setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek);
|
int setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek);
|
||||||
int encrypt_symmetric (const char *filename );
|
int encrypt_symmetric (const char *filename );
|
||||||
int encrypt_store (const char *filename );
|
int encrypt_store (const char *filename );
|
||||||
int encrypt_crypt (gnupg_fd_t filefd, const char *filename,
|
int encrypt_crypt (int filefd, const char *filename,
|
||||||
strlist_t remusr, int use_symkey, pk_list_t provided_keys,
|
strlist_t remusr, int use_symkey, pk_list_t provided_keys,
|
||||||
gnupg_fd_t outputfd);
|
int outputfd);
|
||||||
void encrypt_crypt_files (int nfiles, char **files, strlist_t remusr);
|
void encrypt_crypt_files (int nfiles, char **files, strlist_t remusr);
|
||||||
int encrypt_filter (void *opaque, int control,
|
int encrypt_filter (void *opaque, int control,
|
||||||
iobuf_t a, byte *buf, size_t *ret_len);
|
iobuf_t a, byte *buf, size_t *ret_len);
|
||||||
@ -245,7 +245,7 @@ int save_unprotected_key_to_card (PKT_secret_key *sk, int keyno);
|
|||||||
int overwrite_filep( const char *fname );
|
int overwrite_filep( const char *fname );
|
||||||
char *make_outfile_name( const char *iname );
|
char *make_outfile_name( const char *iname );
|
||||||
char *ask_outfile_name( const char *name, size_t namelen );
|
char *ask_outfile_name( const char *name, size_t namelen );
|
||||||
int open_outfile (gnupg_fd_t inp_fd, const char *iname, int mode, iobuf_t *a);
|
int open_outfile (int inp_fd, const char *iname, int mode, iobuf_t *a);
|
||||||
iobuf_t open_sigfile( const char *iname, progress_filter_context_t *pfx );
|
iobuf_t open_sigfile( const char *iname, progress_filter_context_t *pfx );
|
||||||
void try_make_homedir( const char *fname );
|
void try_make_homedir( const char *fname );
|
||||||
|
|
||||||
@ -319,6 +319,7 @@ int gpg_verify (ctrl_t ctrl, int sig_fd, int data_fd, FILE *out_fp);
|
|||||||
|
|
||||||
/*-- decrypt.c --*/
|
/*-- decrypt.c --*/
|
||||||
int decrypt_message( const char *filename );
|
int decrypt_message( const char *filename );
|
||||||
|
gpg_error_t decrypt_message_fd (int input_fd, int output_fd);
|
||||||
void decrypt_messages(int nfiles, char *files[]);
|
void decrypt_messages(int nfiles, char *files[]);
|
||||||
|
|
||||||
/*-- plaintext.c --*/
|
/*-- plaintext.c --*/
|
||||||
|
@ -178,24 +178,24 @@ ask_outfile_name( const char *name, size_t namelen )
|
|||||||
* Mode 0 = use ".gpg"
|
* Mode 0 = use ".gpg"
|
||||||
* 1 = use ".asc"
|
* 1 = use ".asc"
|
||||||
* 2 = use ".sig"
|
* 2 = use ".sig"
|
||||||
|
*
|
||||||
* If INP_FD is not GNUPG_INVALID_FD the function will simply create
|
* If INP_FD is not -1 the function simply creates an IOBUF for that
|
||||||
* an IOBUF for that file descriptor and ignore a INAME and MODE.
|
* file descriptor and ignorea INAME and MODE. Note that INP_FD won't
|
||||||
* Note that INP_FD won't be closed if the returned IOBUF is closed.
|
* be closed if the returned IOBUF is closed.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
open_outfile (gnupg_fd_t inp_fd, const char *iname, int mode, iobuf_t *a)
|
open_outfile (int inp_fd, const char *iname, int mode, iobuf_t *a)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
*a = NULL;
|
*a = NULL;
|
||||||
if (inp_fd != GNUPG_INVALID_FD)
|
if (inp_fd != -1)
|
||||||
{
|
{
|
||||||
char xname[64];
|
char xname[64];
|
||||||
gnupg_fd_t fd2;
|
int fd2;
|
||||||
|
|
||||||
fd2 = INT2FD (dup (FD2INT (inp_fd)));
|
fd2 = dup (inp_fd);
|
||||||
if (fd2 == GNUPG_INVALID_FD)
|
if (fd2 == -1)
|
||||||
*a = NULL;
|
*a = NULL;
|
||||||
else
|
else
|
||||||
*a = iobuf_fdopen (fd2, "wb");
|
*a = iobuf_fdopen (fd2, "wb");
|
||||||
|
@ -43,6 +43,7 @@ struct
|
|||||||
unsigned debug;
|
unsigned debug;
|
||||||
int armor;
|
int armor;
|
||||||
char *outfile;
|
char *outfile;
|
||||||
|
FILE *outfp; /* Hack, sometimes used in place of outfile. */
|
||||||
off_t max_output;
|
off_t max_output;
|
||||||
int dry_run;
|
int dry_run;
|
||||||
int list_only;
|
int list_only;
|
||||||
|
@ -289,8 +289,8 @@ typedef struct {
|
|||||||
} PKT_compressed;
|
} PKT_compressed;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u32 len; /* length of encrypted data */
|
u32 len; /* Remaining length of encrypted data. */
|
||||||
int extralen; /* this is (blocksize+2) */
|
int extralen; /* This is (blocksize+2). Used by build_packet. */
|
||||||
byte new_ctb; /* uses a new CTB */
|
byte new_ctb; /* uses a new CTB */
|
||||||
byte is_partial; /* partial length encoded */
|
byte is_partial; /* partial length encoded */
|
||||||
byte mdc_method; /* > 0: integrity protected encrypted data packet */
|
byte mdc_method; /* > 0: integrity protected encrypted data packet */
|
||||||
|
@ -86,10 +86,13 @@ handle_plaintext (PKT_plaintext * pt, md_filter_context_t * mfx,
|
|||||||
/* Create the filename as C string. */
|
/* Create the filename as C string. */
|
||||||
if (nooutput)
|
if (nooutput)
|
||||||
;
|
;
|
||||||
|
else if (opt.outfp)
|
||||||
|
{
|
||||||
|
fname = xstrdup ("[FP]");
|
||||||
|
}
|
||||||
else if (opt.outfile)
|
else if (opt.outfile)
|
||||||
{
|
{
|
||||||
fname = xmalloc (strlen (opt.outfile) + 1);
|
fname = xstrdup (opt.outfile);
|
||||||
strcpy (fname, opt.outfile);
|
|
||||||
}
|
}
|
||||||
else if (pt->namelen == 8 && !memcmp (pt->name, "_CONSOLE", 8))
|
else if (pt->namelen == 8 && !memcmp (pt->name, "_CONSOLE", 8))
|
||||||
{
|
{
|
||||||
@ -112,6 +115,13 @@ handle_plaintext (PKT_plaintext * pt, md_filter_context_t * mfx,
|
|||||||
|
|
||||||
if (nooutput)
|
if (nooutput)
|
||||||
;
|
;
|
||||||
|
else if (opt.outfp)
|
||||||
|
{
|
||||||
|
fp = opt.outfp;
|
||||||
|
#ifdef HAVE_DOSISH_SYSTEM
|
||||||
|
setmode (fileno (fp), O_BINARY);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
else if (iobuf_is_pipe_filename (fname) || !*fname)
|
else if (iobuf_is_pipe_filename (fname) || !*fname)
|
||||||
{
|
{
|
||||||
/* No filename or "-" given; write to stdout. */
|
/* No filename or "-" given; write to stdout. */
|
||||||
@ -138,7 +148,13 @@ handle_plaintext (PKT_plaintext * pt, md_filter_context_t * mfx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef __riscos__
|
#ifndef __riscos__
|
||||||
if (fp || nooutput)
|
if (opt.outfp && is_secured_file (fileno (opt.outfp)))
|
||||||
|
{
|
||||||
|
rc = gpg_error (GPG_ERR_EPERM);
|
||||||
|
log_error (_("error creating `%s': %s\n"), fname, gpg_strerror (rc));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
else if (fp || nooutput)
|
||||||
;
|
;
|
||||||
else if (is_secured_filename (fname))
|
else if (is_secured_filename (fname))
|
||||||
{
|
{
|
||||||
@ -154,9 +170,9 @@ handle_plaintext (PKT_plaintext * pt, md_filter_context_t * mfx,
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
#else /* __riscos__ */
|
#else /* __riscos__ */
|
||||||
/* If no output filename was given, i.e. we constructed it,
|
/* If no output filename was given, i.e. we constructed it, convert
|
||||||
convert all '.' in fname to '/' but not vice versa as
|
all '.' in fname to '/' but not vice versa as we don't create
|
||||||
we don't create directories! */
|
directories! */
|
||||||
if (!opt.outfile)
|
if (!opt.outfile)
|
||||||
for (c = 0; fname[c]; ++c)
|
for (c = 0; fname[c]; ++c)
|
||||||
if (fname[c] == '.')
|
if (fname[c] == '.')
|
||||||
@ -418,7 +434,7 @@ handle_plaintext (PKT_plaintext * pt, md_filter_context_t * mfx,
|
|||||||
pt->buf = NULL;
|
pt->buf = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fp && fp != stdout && fclose (fp))
|
if (fp && fp != stdout && fp != opt.outfp && fclose (fp))
|
||||||
{
|
{
|
||||||
rc = (errno ? gpg_error_from_syserror ()
|
rc = (errno ? gpg_error_from_syserror ()
|
||||||
: gpg_error (GPG_ERR_INTERNAL));
|
: gpg_error (GPG_ERR_INTERNAL));
|
||||||
@ -434,7 +450,7 @@ handle_plaintext (PKT_plaintext * pt, md_filter_context_t * mfx,
|
|||||||
before checking the signature. */
|
before checking the signature. */
|
||||||
fflush (stdout);
|
fflush (stdout);
|
||||||
|
|
||||||
if (fp && fp != stdout)
|
if (fp && fp != stdout && fp != opt.outfp)
|
||||||
fclose (fp);
|
fclose (fp);
|
||||||
xfree (fname);
|
xfree (fname);
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -362,7 +362,7 @@ cmd_decrypt (assuan_context_t ctx, char *line)
|
|||||||
if (out_fd == -1)
|
if (out_fd == -1)
|
||||||
return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
|
return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
|
||||||
|
|
||||||
err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
err = decrypt_message_fd (inp_fd, out_fd);
|
||||||
|
|
||||||
/* Close and reset the fds. */
|
/* Close and reset the fds. */
|
||||||
close_message_fd (ctrl);
|
close_message_fd (ctrl);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user