Commit 4373fd43 authored by Glenn Morris's avatar Glenn Morris

More small doc and lispref edits related to processes

* doc/lispref/processes.texi (Serial Ports, Byte Packing, Bindat Spec)
(Bindat Functions): Copyedits.

* src/process.c (Fset_process_inherit_coding_system_flag)
(Fset_process_query_on_exit_flag): Doc fix (mention return value).
(Fmake_network_process, Fmake_serial_process): Doc fix.

* admin/FOR-RELEASE: Related markup.
parent 0e80650b
...@@ -214,7 +214,7 @@ objects.texi cyd ...@@ -214,7 +214,7 @@ objects.texi cyd
os.texi cyd os.texi cyd
package.texi rgm package.texi rgm
positions.texi cyd positions.texi cyd
processes.texi processes.texi rgm
searching.texi rgm searching.texi rgm
sequences.texi cyd sequences.texi cyd
streams.texi cyd streams.texi cyd
......
2012-04-18 Glenn Morris <rgm@gnu.org>
* processes.texi (Serial Ports, Byte Packing, Bindat Spec)
(Bindat Functions): Copyedits.
2012-04-18 Christopher Schmidt <christopher@ch.ristopher.com> 2012-04-18 Christopher Schmidt <christopher@ch.ristopher.com>
* files.texi (Saving Buffers): Document `visit and `visit-save' * files.texi (Saving Buffers): Document `visit and `visit-save'
......
...@@ -2493,11 +2493,11 @@ lets you change the speed, bytesize, and other parameters. In a ...@@ -2493,11 +2493,11 @@ lets you change the speed, bytesize, and other parameters. In a
terminal window created by @code{serial-term}, you can click on the terminal window created by @code{serial-term}, you can click on the
mode line for configuration. mode line for configuration.
A serial connection is represented by a process object which can be A serial connection is represented by a process object, which can be
used similar to a subprocess or network process. You can send and used in a similar way to a subprocess or network process. You can send and
receive data and configure the serial port. A serial process object receive data, and configure the serial port. A serial process object
has no process ID, you can't send signals to it, and the status codes has no process ID, however, and you can't send signals to it, and the
are different from other types of processes. status codes are different from other types of processes.
@code{delete-process} on the process object or @code{kill-buffer} on @code{delete-process} on the process object or @code{kill-buffer} on
the process buffer close the connection, but this does not affect the the process buffer close the connection, but this does not affect the
device connected to the serial port. device connected to the serial port.
...@@ -2505,15 +2505,17 @@ device connected to the serial port. ...@@ -2505,15 +2505,17 @@ device connected to the serial port.
The function @code{process-type} returns the symbol @code{serial} The function @code{process-type} returns the symbol @code{serial}
for a process object representing a serial port connection. for a process object representing a serial port connection.
Serial ports are available on GNU/Linux, Unix, and Windows systems. Serial ports are available on GNU/Linux, Unix, and MS Windows systems.
@deffn Command serial-term port speed @deffn Command serial-term port speed
Start a terminal-emulator for a serial port in a new buffer. Start a terminal-emulator for a serial port in a new buffer.
@var{port} is the name of the serial port to which to connect. For @var{port} is the name of the serial port to connect to. For
example, this could be @file{/dev/ttyS0} on Unix. On Windows, this example, this could be @file{/dev/ttyS0} on Unix. On MS Windows, this
could be @file{COM1}, or @file{\\.\COM10} (double the backslashes in could be @file{COM1}, or @file{\\.\COM10} (double the backslashes in
Lisp strings). Lisp strings).
@c FIXME is 9600 still the most common value, or is it 115200 now?
@c (Same value, 9600, appears below as well.)
@var{speed} is the speed of the serial port in bits per second. 9600 @var{speed} is the speed of the serial port in bits per second. 9600
is a common value. The buffer is in Term mode; see @ref{Term Mode,,, is a common value. The buffer is in Term mode; see @ref{Term Mode,,,
emacs, The GNU Emacs Manual}, for the commands to use in that buffer. emacs, The GNU Emacs Manual}, for the commands to use in that buffer.
...@@ -2522,25 +2524,27 @@ You can change the speed and the configuration in the mode line menu. ...@@ -2522,25 +2524,27 @@ You can change the speed and the configuration in the mode line menu.
@defun make-serial-process &rest args @defun make-serial-process &rest args
This function creates a process and a buffer. Arguments are specified This function creates a process and a buffer. Arguments are specified
as keyword/argument pairs. Here's the list of the meaningful keywords: as keyword/argument pairs. Here's the list of the meaningful
keywords, with the first two (@var{port} and @var{speed}) being mandatory:
@table @code @table @code
@item :port @var{port}@r{ (mandatory)} @item :port @var{port}
This is the name of the serial port. On Unix and GNU systems, this is This is the name of the serial port. On Unix and GNU systems, this is
a file name such as @file{/dev/ttyS0}. On Windows, this could be a file name such as @file{/dev/ttyS0}. On Windows, this could be
@file{COM1}, or @file{\\.\COM10} for ports higher than @file{COM9} @file{COM1}, or @file{\\.\COM10} for ports higher than @file{COM9}
(double the backslashes in Lisp strings). (double the backslashes in Lisp strings).
@item :speed @var{speed}@r{ (mandatory)} @item :speed @var{speed}
The speed of the serial port in bits per second. This function calls The speed of the serial port in bits per second. This function calls
@code{serial-process-configure} to handle the speed. @code{serial-process-configure} to handle the speed; see the
following documentation of that function for more details.
@item :name @var{name} @item :name @var{name}
The name of the process. If @var{name} is not given, @var{port} will The name of the process. If @var{name} is not given, @var{port} will
serve as the process name as well. serve as the process name as well.
@item :buffer @var{buffer} @item :buffer @var{buffer}
The buffer to associate with the process. The value could be either a The buffer to associate with the process. The value can be either a
buffer or a string that names a buffer. Process output goes at the buffer or a string that names a buffer. Process output goes at the
end of that buffer, unless you specify an output stream or filter end of that buffer, unless you specify an output stream or filter
function to handle the output. If @var{buffer} is not given, the function to handle the output. If @var{buffer} is not given, the
...@@ -2550,9 +2554,9 @@ keyword. ...@@ -2550,9 +2554,9 @@ keyword.
@item :coding @var{coding} @item :coding @var{coding}
If @var{coding} is a symbol, it specifies the coding system used for If @var{coding} is a symbol, it specifies the coding system used for
both reading and writing for this process. If @var{coding} is a cons both reading and writing for this process. If @var{coding} is a cons
@code{(decoding . encoding)}, @var{decoding} is used for reading, and @code{(@var{decoding} . @var{encoding})}, @var{decoding} is used for
@var{encoding} is used for writing. If not specified, the default is reading, and @var{encoding} is used for writing. If not specified,
to determine the coding systems from data itself. the default is to determine the coding systems from the data itself.
@item :noquery @var{query-flag} @item :noquery @var{query-flag}
Initialize the process query flag to @var{query-flag}. @xref{Query Initialize the process query flag to @var{query-flag}. @xref{Query
...@@ -2574,8 +2578,7 @@ Install @var{sentinel} as the process sentinel. ...@@ -2574,8 +2578,7 @@ Install @var{sentinel} as the process sentinel.
@item :plist @var{plist} @item :plist @var{plist}
Install @var{plist} as the initial plist of the process. Install @var{plist} as the initial plist of the process.
@item :speed @item :bytesize
@itemx :bytesize
@itemx :parity @itemx :parity
@itemx :stopbits @itemx :stopbits
@itemx :flowcontrol @itemx :flowcontrol
...@@ -2603,7 +2606,7 @@ Here is an example: ...@@ -2603,7 +2606,7 @@ Here is an example:
This functions configures a serial port connection. Arguments are This functions configures a serial port connection. Arguments are
specified as keyword/argument pairs. Attributes that are not given specified as keyword/argument pairs. Attributes that are not given
are re-initialized from the process's current configuration (available are re-initialized from the process's current configuration (available
via the function @code{process-contact}) or set to reasonable default via the function @code{process-contact}), or set to reasonable default
values. The following arguments are defined: values. The following arguments are defined:
@table @code @table @code
...@@ -2621,8 +2624,8 @@ rate}. The value can be any number, but most serial ports work only ...@@ -2621,8 +2624,8 @@ rate}. The value can be any number, but most serial ports work only
at a few defined values between 1200 and 115200, with 9600 being the at a few defined values between 1200 and 115200, with 9600 being the
most common value. If @var{speed} is @code{nil}, the function ignores most common value. If @var{speed} is @code{nil}, the function ignores
all other arguments and does not configure the port. This may be all other arguments and does not configure the port. This may be
useful for special serial ports such as Bluetooth-to-serial converters useful for special serial ports such as Bluetooth-to-serial converters,
which can only be configured through AT commands sent through the which can only be configured through @samp{AT} commands sent through the
connection. The value of @code{nil} for @var{speed} is valid only for connection. The value of @code{nil} for @var{speed} is valid only for
connections that were already opened by a previous call to connections that were already opened by a previous call to
@code{make-serial-process} or @code{serial-term}. @code{make-serial-process} or @code{serial-term}.
...@@ -2649,9 +2652,9 @@ flow control). If @var{flowcontrol} is not given, it defaults to no ...@@ -2649,9 +2652,9 @@ flow control). If @var{flowcontrol} is not given, it defaults to no
flow control. flow control.
@end table @end table
@code{serial-process-configure} is called by Internally, @code{make-serial-process} calls
@code{make-serial-process} for the initial configuration of the serial @code{serial-process-configure} for the initial configuration of the
port. serial port.
@end defun @end defun
@node Byte Packing @node Byte Packing
...@@ -2661,8 +2664,12 @@ port. ...@@ -2661,8 +2664,12 @@ port.
This section describes how to pack and unpack arrays of bytes, This section describes how to pack and unpack arrays of bytes,
usually for binary network protocols. These functions convert byte arrays usually for binary network protocols. These functions convert byte arrays
to alists, and vice versa. The byte array can be represented as a to alists, and vice versa. The byte array can be represented as a
@c FIXME? No multibyte?
unibyte string or as a vector of integers, while the alist associates unibyte string or as a vector of integers, while the alist associates
symbols either with fixed-size objects or with recursive sub-alists. symbols either with fixed-size objects or with recursive sub-alists.
To use the functions referred to in this section, load the
@code{bindat} library.
@c It doesn't have any autoloads.
@cindex serializing @cindex serializing
@cindex deserializing @cindex deserializing
...@@ -2683,7 +2690,7 @@ direction is also known as @dfn{serializing} or @dfn{packing}. ...@@ -2683,7 +2690,7 @@ direction is also known as @dfn{serializing} or @dfn{packing}.
To control unpacking and packing, you write a @dfn{data layout To control unpacking and packing, you write a @dfn{data layout
specification}, a special nested list describing named and typed specification}, a special nested list describing named and typed
@dfn{fields}. This specification controls length of each field to be @dfn{fields}. This specification controls the length of each field to be
processed, and how to pack or unpack it. We normally keep bindat specs processed, and how to pack or unpack it. We normally keep bindat specs
in variables whose names end in @samp{-bindat-spec}; that kind of name in variables whose names end in @samp{-bindat-spec}; that kind of name
is automatically recognized as ``risky''. is automatically recognized as ``risky''.
...@@ -2732,12 +2739,12 @@ String of length @var{len}. ...@@ -2732,12 +2739,12 @@ String of length @var{len}.
Zero-terminated string, in a fixed-size field with length @var{len}. Zero-terminated string, in a fixed-size field with length @var{len}.
@item vec @var{len} [@var{type}] @item vec @var{len} [@var{type}]
Vector of @var{len} elements of type @var{type}, or bytes if not Vector of @var{len} elements of type @var{type}, defaulting to bytes.
@var{type} is specified.
The @var{type} is any of the simple types above, or another vector The @var{type} is any of the simple types above, or another vector
specified as a list @code{(vec @var{len} [@var{type}])}. specified as a list of the form @code{(vec @var{len} [@var{type}])}.
@item ip @item ip
@c FIXME? IPv6?
Four-byte vector representing an Internet address. For example: Four-byte vector representing an Internet address. For example:
@code{[127 0 0 1]} for localhost. @code{[127 0 0 1]} for localhost.
...@@ -2765,12 +2772,11 @@ below, or by an expression @code{(eval @var{form})} where @var{form} ...@@ -2765,12 +2772,11 @@ below, or by an expression @code{(eval @var{form})} where @var{form}
should evaluate to an integer, specifying the field length. should evaluate to an integer, specifying the field length.
A field specification generally has the form @code{([@var{name}] A field specification generally has the form @code{([@var{name}]
@var{handler})}. The square braces indicate that @var{name} is @var{handler})}, where @var{name} is optional. Don't use names that
optional. (Don't use names that are symbols meaningful as type are symbols meaningful as type specifications (above) or handler
specifications (above) or handler specifications (below), since that specifications (below), since that would be ambiguous. @var{name} can
would be ambiguous.) @var{name} can be a symbol or the expression be a symbol or an expression @code{(eval @var{form})}, in which case
@code{(eval @var{form})}, in which case @var{form} should evaluate to @var{form} should evaluate to a symbol.
a symbol.
@var{handler} describes how to unpack or pack the field and can be one @var{handler} describes how to unpack or pack the field and can be one
of the following: of the following:
...@@ -2817,10 +2823,11 @@ of @var{form}. A non-@code{nil} result indicates a match. ...@@ -2817,10 +2823,11 @@ of @var{form}. A non-@code{nil} result indicates a match.
@item repeat @var{count} @var{field-specs}@dots{} @item repeat @var{count} @var{field-specs}@dots{}
Process the @var{field-specs} recursively, in order, then repeat Process the @var{field-specs} recursively, in order, then repeat
starting from the first one, processing all the specs @var{count} starting from the first one, processing all the specifications @var{count}
times overall. The @var{count} is given using the same formats as a times overall. The @var{count} is given using the same formats as a
field length---if an @code{eval} form is used, it is evaluated just once. field length---if an @code{eval} form is used, it is evaluated just once.
For correct operation, each spec in @var{field-specs} must include a name. For correct operation, each specification in @var{field-specs} must
include a name.
@end table @end table
For the @code{(eval @var{form})} forms used in a bindat specification, For the @code{(eval @var{form})} forms used in a bindat specification,
...@@ -2859,9 +2866,10 @@ specification, @code{bindat-raw} to a byte array, and @var{struct} to an ...@@ -2859,9 +2866,10 @@ specification, @code{bindat-raw} to a byte array, and @var{struct} to an
alist representing unpacked field data. alist representing unpacked field data.
@defun bindat-unpack spec bindat-raw &optional bindat-idx @defun bindat-unpack spec bindat-raw &optional bindat-idx
@c FIXME? Again, no multibyte?
This function unpacks data from the unibyte string or byte This function unpacks data from the unibyte string or byte
array @code{bindat-raw} array @code{bindat-raw}
according to @var{spec}. Normally this starts unpacking at the according to @var{spec}. Normally, this starts unpacking at the
beginning of the byte array, but if @var{bindat-idx} is non-@code{nil}, it beginning of the byte array, but if @var{bindat-idx} is non-@code{nil}, it
specifies a zero-based starting position to use instead. specifies a zero-based starting position to use instead.
...@@ -2897,7 +2905,7 @@ according to @var{spec}. ...@@ -2897,7 +2905,7 @@ according to @var{spec}.
@defun bindat-pack spec struct &optional bindat-raw bindat-idx @defun bindat-pack spec struct &optional bindat-raw bindat-idx
This function returns a byte array packed according to @var{spec} from This function returns a byte array packed according to @var{spec} from
the data in the alist @var{struct}. Normally it creates and fills a the data in the alist @var{struct}. It normally creates and fills a
new byte array starting at the beginning. However, if @var{bindat-raw} new byte array starting at the beginning. However, if @var{bindat-raw}
is non-@code{nil}, it specifies a pre-allocated unibyte string or vector to is non-@code{nil}, it specifies a pre-allocated unibyte string or vector to
pack into. If @var{bindat-idx} is non-@code{nil}, it specifies the starting pack into. If @var{bindat-idx} is non-@code{nil}, it specifies the starting
...@@ -2910,6 +2918,7 @@ meets or exceeds the total length to avoid an out-of-range error. ...@@ -2910,6 +2918,7 @@ meets or exceeds the total length to avoid an out-of-range error.
@defun bindat-ip-to-string ip @defun bindat-ip-to-string ip
Convert the Internet address vector @var{ip} to a string in the usual Convert the Internet address vector @var{ip} to a string in the usual
dotted notation. dotted notation.
@c FIXME? Does it do IPv6?
@example @example
(bindat-ip-to-string [127 0 0 1]) (bindat-ip-to-string [127 0 0 1])
...@@ -2919,10 +2928,16 @@ dotted notation. ...@@ -2919,10 +2928,16 @@ dotted notation.
@node Bindat Examples @node Bindat Examples
@subsection Examples of Byte Unpacking and Packing @subsection Examples of Byte Unpacking and Packing
@c FIXME? This seems a very long example for something that is not used
@c very often. As of 24.1, gdb-mi.el is the only user of bindat.el in Emacs.
@c Maybe one or both of these examples should just be moved to the
@c commentary of bindat.el.
Here is a complete example of byte unpacking and packing: Here is a complete example of byte unpacking and packing:
@lisp @lisp
(require 'bindat)
(defvar fcookie-index-spec (defvar fcookie-index-spec
'((:version u32) '((:version u32)
(:count u32) (:count u32)
...@@ -2931,16 +2946,14 @@ dotted notation. ...@@ -2931,16 +2946,14 @@ dotted notation.
(:flags u32) (:flags u32)
(:delim u8) (:delim u8)
(:ignored fill 3) (:ignored fill 3)
(:offset repeat (:count) (:offset repeat (:count) (:foo u32)))
(:foo u32)))
"Description of a fortune cookie index file's contents.") "Description of a fortune cookie index file's contents.")
(defun fcookie (cookies &optional index) (defun fcookie (cookies &optional index)
"Display a random fortune cookie from file COOKIES. "Display a random fortune cookie from file COOKIES.
Optional second arg INDEX specifies the associated index Optional second arg INDEX specifies the associated index
filename, which is by default constructed by appending filename, by default \"COOKIES.dat\". Display cookie text
\".dat\" to COOKIES. Display cookie text in possibly in buffer \"*Fortune Cookie: BASENAME*\", where BASENAME
new buffer \"*Fortune Cookie: BASENAME*\" where BASENAME
is COOKIES without the directory part." is COOKIES without the directory part."
(interactive "fCookies file: ") (interactive "fCookies file: ")
(let* ((info (with-temp-buffer (let* ((info (with-temp-buffer
...@@ -2963,10 +2976,9 @@ is COOKIES without the directory part." ...@@ -2963,10 +2976,9 @@ is COOKIES without the directory part."
(defun fcookie-create-index (cookies &optional index delim) (defun fcookie-create-index (cookies &optional index delim)
"Scan file COOKIES, and write out its index file. "Scan file COOKIES, and write out its index file.
Optional second arg INDEX specifies the index filename, Optional arg INDEX specifies the index filename, which by
which is by default constructed by appending \".dat\" to default is \"COOKIES.dat\". Optional arg DELIM specifies the
COOKIES. Optional third arg DELIM specifies the unibyte unibyte character that, when found on a line of its own in
character which, when found on a line of its own in
COOKIES, indicates the border between entries." COOKIES, indicates the border between entries."
(interactive "fCookies file: ") (interactive "fCookies file: ")
(setq delim (or delim ?%)) (setq delim (or delim ?%))
...@@ -3003,8 +3015,8 @@ COOKIES, indicates the border between entries." ...@@ -3003,8 +3015,8 @@ COOKIES, indicates the border between entries."
(write-file (or index (concat cookies ".dat"))))))) (write-file (or index (concat cookies ".dat")))))))
@end lisp @end lisp
Following is an example of defining and unpacking a complex structure. The following is an example of defining and unpacking a complex
Consider the following C structures: structure. Consider the following C structures:
@example @example
struct header @{ struct header @{
...@@ -3017,14 +3029,14 @@ struct header @{ ...@@ -3017,14 +3029,14 @@ struct header @{
struct data @{ struct data @{
unsigned char type; unsigned char type;
unsigned char opcode; unsigned char opcode;
unsigned short length; /* In network byte order */ unsigned short length; /* in network byte order */
unsigned char id[8]; /* null-terminated string */ unsigned char id[8]; /* null-terminated string */
unsigned char data[/* (length + 3) & ~3 */]; unsigned char data[/* (length + 3) & ~3 */];
@}; @};
struct packet @{ struct packet @{
struct header header; struct header header;
unsigned long counters[2]; /* In little endian order */ unsigned long counters[2]; /* in little endian order */
unsigned char items; unsigned char items;
unsigned char filler[3]; unsigned char filler[3];
struct data item[/* items */]; struct data item[/* items */];
...@@ -3032,7 +3044,7 @@ struct packet @{ ...@@ -3032,7 +3044,7 @@ struct packet @{
@}; @};
@end example @end example
The corresponding data layout specification: The corresponding data layout specification is:
@lisp @lisp
(setq header-spec (setq header-spec
...@@ -3044,21 +3056,21 @@ The corresponding data layout specification: ...@@ -3044,21 +3056,21 @@ The corresponding data layout specification:
(setq data-spec (setq data-spec
'((type u8) '((type u8)
(opcode u8) (opcode u8)
(length u16) ;; network byte order (length u16) ; network byte order
(id strz 8) (id strz 8)
(data vec (length)) (data vec (length))
(align 4))) (align 4)))
(setq packet-spec (setq packet-spec
'((header struct header-spec) '((header struct header-spec)
(counters vec 2 u32r) ;; little endian order (counters vec 2 u32r) ; little endian order
(items u8) (items u8)
(fill 3) (fill 3)
(item repeat (items) (item repeat (items)
(struct data-spec)))) (struct data-spec))))
@end lisp @end lisp
A binary data representation: A binary data representation is:
@lisp @lisp
(setq binary-data (setq binary-data
...@@ -3068,7 +3080,7 @@ A binary data representation: ...@@ -3068,7 +3080,7 @@ A binary data representation:
1 4 0 7 ?B ?C ?D ?E ?F ?G 0 0 6 7 8 9 10 11 12 0 ]) 1 4 0 7 ?B ?C ?D ?E ?F ?G 0 0 6 7 8 9 10 11 12 0 ])
@end lisp @end lisp
The corresponding decoded structure: The corresponding decoded structure is:
@lisp @lisp
(setq decoded (bindat-unpack packet-spec binary-data)) (setq decoded (bindat-unpack packet-spec binary-data))
...@@ -3092,7 +3104,7 @@ The corresponding decoded structure: ...@@ -3092,7 +3104,7 @@ The corresponding decoded structure:
(type . 1)))) (type . 1))))
@end lisp @end lisp
Fetching data from this structure: An example of fetching data from this structure:
@lisp @lisp
(bindat-get-field decoded 'item 1 'id) (bindat-get-field decoded 'item 1 'id)
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* process.c (Fset_process_inherit_coding_system_flag) * process.c (Fset_process_inherit_coding_system_flag)
(Fset_process_query_on_exit_flag): Doc fix (mention return value). (Fset_process_query_on_exit_flag): Doc fix (mention return value).
(Fmake_network_process): Doc fix. (Fmake_network_process, Fmake_serial_process): Doc fix.
2012-04-17 Eli Zaretskii <eliz@gnu.org> 2012-04-17 Eli Zaretskii <eliz@gnu.org>
......
...@@ -2528,7 +2528,7 @@ could be "COM1", or "\\\\.\\COM10" for ports higher than COM9 (double ...@@ -2528,7 +2528,7 @@ could be "COM1", or "\\\\.\\COM10" for ports higher than COM9 (double
the backslashes in strings). the backslashes in strings).
:speed SPEED -- (mandatory) is handled by `serial-process-configure', :speed SPEED -- (mandatory) is handled by `serial-process-configure',
which is called by `make-serial-process'. which this function calls.
:name NAME -- NAME is the name of the process. If NAME is not given, :name NAME -- NAME is the name of the process. If NAME is not given,
the value of PORT is used. the value of PORT is used.
...@@ -2557,13 +2557,12 @@ but you can send outgoing data. The stopped state is cleared by ...@@ -2557,13 +2557,12 @@ but you can send outgoing data. The stopped state is cleared by
:plist PLIST -- Install PLIST as the initial plist of the process. :plist PLIST -- Install PLIST as the initial plist of the process.
:speed
:bytesize :bytesize
:parity :parity
:stopbits :stopbits
:flowcontrol :flowcontrol
-- These arguments are handled by `serial-process-configure', which is -- This function calls `serial-process-configure' to handle these
called by `make-serial-process'. arguments.
The original argument list, possibly modified by later configuration, The original argument list, possibly modified by later configuration,
is available via the function `process-contact'. is available via the function `process-contact'.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment