cmdopts.diff
changeset 80 93088d0c8140
parent 79 07e696e91b6f
child 81 8e1ccd27d60f
equal deleted inserted replaced
79:07e696e91b6f 80:93088d0c8140
    35   * /move:
    35   * /move:
    36     * -j(--jid), -n(--name)
    36     * -j(--jid), -n(--name)
    37   * misc:
    37   * misc:
    38     * fix help for /buffer date
    38     * fix help for /buffer date
    39 
    39 
       
    40 diff -r 1b0b563a81e6 mcabber/doc/commands_HOWTO.mdwn
       
    41 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
       
    42 +++ b/mcabber/doc/commands_HOWTO.mdwn	Fri Mar 22 01:56:17 2013 +0200
       
    43 @@ -0,0 +1,967 @@
       
    44 +
       
    45 +**New commands interface for MCabber**
       
    46 +
       
    47 +[[!toc levels=2]]
       
    48 +
       
    49 +# Overview
       
    50 +
       
    51 +New command interface was designed with next goals in mind:
       
    52 +
       
    53 + * Share as much argument checking code as possible.
       
    54 + * Remove cumbersome parsing code from commands.
       
    55 + * Encourage adding options and switches to commands.
       
    56 + * Use the same rules, when handling arguments everywhere.
       
    57 + * Integrate and improve completion system.
       
    58 + * Add common generic stuff, like '--help'.
       
    59 + * Try to still be lightweight.
       
    60 + * Try to still be readable.
       
    61 +
       
    62 +It is built around static structure, "command description". User can add or
       
    63 +remove these structures to list of commands. FIXME more
       
    64 +
       
    65 +## Command description struct, 'cmdopts_t'
       
    66 +
       
    67 +[[!format c """ // -------------------------------------------------------------
       
    68 +
       
    69 +typedef struct cmdopts_struct cmdopts_t;
       
    70 +
       
    71 +typedef enum {
       
    72 +    cmd_default = 0x0000,
       
    73 +    cmd_safe    = 0x0001,
       
    74 +} cmd_flags_t;
       
    75 +
       
    76 +struct cmdopts_struct {
       
    77 +    const char          *name;
       
    78 +    const cmd_flags_t   flags;
       
    79 +    const cmd_checker_t check;
       
    80 +    const cmd_handler_t handle;
       
    81 +    const cmdopt_t      *opts;
       
    82 +    const cmdarg_t      *args;
       
    83 +    const cmdopts_t     *cmds;
       
    84 +    const gpointer      userdata;
       
    85 +    size_t              valno;
       
    86 +};
       
    87 +
       
    88 +// -------------------------------------------------------------      """     ]]
       
    89 +
       
    90 +This struct describes command as a whole and links to argument descriptions.
       
    91 +This struct is also used to describe individual subcommands, as they are quite
       
    92 +similar to normal command, because they can have their own options, arguments
       
    93 +and subcommands. The fields of this struct:
       
    94 +
       
    95 + * 'name' - name of the command or subcommand.
       
    96 +
       
    97 + * 'flags' - currently there's only one flag:
       
    98 +
       
    99 +    + 'cmd_safe' -  command is safe to execute in main mcabberrc during
       
   100 +      initialization. Have no meaning for subcommands.
       
   101 +    + 'cmd_default' - default value of no flags enabled.
       
   102 + 
       
   103 + * 'check' - execution environment checker for command. This callback is used to
       
   104 +   do general checks before even parsing command line. You can write your own
       
   105 +   checker or use standard ones, for example - 'cmd_check_online', that checks,
       
   106 +   if you are currently online.
       
   107 +
       
   108 + * 'handle' - command function. It is executed only if command line was
       
   109 +   successfully parsed and argument values passed the type checking. Unused in
       
   110 +   subcommands.
       
   111 +
       
   112 + * 'opts' - pointer to the array of 'cmdopt_t' structs, describing command-line
       
   113 +   options ("-f bar") and switches ("-x"), that this command accepts.
       
   114 + 
       
   115 + * 'args' - similarly, pointer to the array of 'cmdarg_t' structs, that describe
       
   116 +   command-line positional arguments (in order).
       
   117 + 
       
   118 + * 'cmds' - pointer to the array of subcommands of this command (or subcommand).
       
   119 +   How parser switches to subcommands we will describe later.
       
   120 + 
       
   121 + * 'userdata' - arbitrary pointer, where you can put some data, that should
       
   122 +   accompany this command or subcommand. Unused by parser.
       
   123 +
       
   124 + * 'valno' - this is internal value, that is initialized at command definition
       
   125 +   time, you should not modify it. Currently unused in subcommands.
       
   126 +
       
   127 +## Command function, 'cmd_handler_t'
       
   128 +
       
   129 +[[!format c """ // -------------------------------------------------------------
       
   130 +
       
   131 +typedef gchar *(*cmd_handler_t) (cmdopts_t *command, cmdarg_value_t *values);
       
   132 +
       
   133 +// -------------------------------------------------------------      """     ]]
       
   134 +
       
   135 +Command function is passed it's command definition struct (mainly to give it
       
   136 +access to userdata) and dynamically allocated array of parsed argument values.
       
   137 +
       
   138 +It should return NULL in case all went smoothly, or dynamically allocated error
       
   139 +string, that will be g_free()'d after displaying.
       
   140 +
       
   141 +So, as you can see, command definition should give parser info on what can
       
   142 +appear in command line and how to map all these options and arguments to array
       
   143 +of values.
       
   144 +
       
   145 +## Option description struct, 'cmdopt_t'
       
   146 +
       
   147 +[[!format c """ // -------------------------------------------------------------
       
   148 +
       
   149 +typedef struct {
       
   150 +    const char stortopt;
       
   151 +    const char *longopt;
       
   152 +    cmdarg_t   arg;
       
   153 +} cmdopt_t;
       
   154 +
       
   155 +// -------------------------------------------------------------      """     ]]
       
   156 +
       
   157 +This struct just adds short option character and long option name to generic
       
   158 +argument struct, that we'll look at right now.
       
   159 +
       
   160 +## Argument description struct, 'cmdarg_t'
       
   161 +
       
   162 +[[!format c """ // -------------------------------------------------------------
       
   163 +
       
   164 +typedef struct cmdarg_struct cmdarg_t;
       
   165 +
       
   166 +typedef enum {
       
   167 +    cmdarg_default  = 0x0000,
       
   168 +    cmdarg_catchall = 0x0001,
       
   169 +    cmdarg_plain    = 0x0002,
       
   170 +    cmdarg_check    = 0x0004,
       
   171 +    cmdarg_required = 0x0008,
       
   172 +    cmdarg_subcmd   = 0x0010,
       
   173 +    cmdarg_switch   = 0x0020,
       
   174 +    cmdarg_eol      = 0x0003, // catchall + plain
       
   175 +    cmdarg_chreq    = 0x000C, // check + required
       
   176 +    cmdarg_special  = 0x0030, // subcmd + switch
       
   177 +} cmdarg_flags_t;
       
   178 +
       
   179 +struct cmdarg_struct {
       
   180 +    const char           *name;
       
   181 +    const guint          pos;
       
   182 +    const cmdarg_flags_t flags;
       
   183 +    const char           *defval;
       
   184 +    const cmdarg_type    *type;
       
   185 +    gconstpointer        chkdata;
       
   186 +    gconstpointer        userdata;
       
   187 +};
       
   188 +
       
   189 +// -------------------------------------------------------------      """     ]]
       
   190 +
       
   191 +This struct stores information about mapping between command-line entity
       
   192 +(switch, option, argument, subcommand) and element in 'values' array. First,
       
   193 +let's briefly describe fields, and then walk through their use in different
       
   194 +entities.
       
   195 +
       
   196 +Fields:
       
   197 +
       
   198 + * 'name' - argument name, mainly used for help (not implemented yet) and error
       
   199 +   messages.
       
   200 + 
       
   201 + * 'pos' - this is the index in 'values' array, where argument value should be
       
   202 +   stored.
       
   203 + 
       
   204 + * 'flags' - various tweaks to parsing process:
       
   205 +
       
   206 +    + 'catchall' - argument value will catch everything, remaining on command
       
   207 +      line, even if unescaped spaces will appear in it.
       
   208 +    + 'plain' - do not treat backslashes ('\') and quotes ('"') as escaping
       
   209 +      characters.
       
   210 +    + 'check' - call argument value checker (defined in 'type' field), even if
       
   211 +      argument was not assigned the value during the parsing process.
       
   212 +    + 'required' - if mentioned checker will return error, with this flag set,
       
   213 +      this error will be considered fatal, and command function will not be
       
   214 +      called.
       
   215 +    + 'subcmd' - this argument is subcommand.
       
   216 +    + 'switch' - this argument is part of option definition, and this option
       
   217 +      have no argument (but it still needs to store switch state somewhere).
       
   218 +    + 'eol' - shortcut for "rest of command line without modification".
       
   219 +    + 'chreq' - shortcut for "argument must have a valid value".
       
   220 +    + 'special' - this is special type of argument - subcommand or switch.
       
   221 + 
       
   222 + * 'defval' - default value for argument in "unchecked" form - i.e., in the form
       
   223 +   of string, as it appears on command line (we'll discuss type checkers and
       
   224 +   what can they do to value later). Before parsing command line, parser will
       
   225 +   assign this value to corresponding value structure.
       
   226 +
       
   227 + * 'type' - pointer to structure, describing argument type.
       
   228 +
       
   229 + * 'chkdata' - if type needs some additional info, it is a place to supply it.
       
   230 +
       
   231 + * 'userdata' - place for arbitrary info, that should accompany this argument or
       
   232 +   option. Unused by parser.
       
   233 +
       
   234 +Now, let's discuss general case - option with argument or positional argument.
       
   235 +
       
   236 +When parser encounters such argument, it checks 'catchall' and 'plain' flags and
       
   237 +crops argument value from command line accordingly, then it assigns it to the
       
   238 +'value.arg' field of 'cmdarg_value_t' struct in array 'values' with index, given
       
   239 +in 'pos'. Also it marks such value as 'visited' and puts a link to argument
       
   240 +description into value's 'src' field. More about effect of these actions later,
       
   241 +in 'cmdarg_value_t' section.
       
   242 +
       
   243 +However, if argument struct is a part of option description struct, and have
       
   244 +flag 'switch' set, parser will not try to parse value. Instead it will increase
       
   245 +the count in 'value.swc' in corresponding 'cmdarg_value_t' struct. Argument name
       
   246 +for switches is essentially ignored, but for safety sake it is recommended to
       
   247 +duplicate switch long option name here. Flags 'catchall' and 'plain' obviously
       
   248 +have no effect. Flag 'check' makes switch a trigger, that flips between 'on' and
       
   249 +'off' for every occurence of flag on command line. Flags 'required' and 'subcmd'
       
   250 +also have no effect for obvious reasons. Default value is ignored for switches,
       
   251 +they always start with count 0 (off). Since switch is internal type, argument
       
   252 +type field is ignored as well. Flags and source fields of value are updated as
       
   253 +usual.
       
   254 +
       
   255 +If flag 'subcmd' is set for positional argument, parser crops argument value
       
   256 +according to flags as usual, but instead of assigning it, walks through list of
       
   257 +subcommands in command description struct and compares obtained value to
       
   258 +subcommand names. If it finds corresponding subcommand, it assigns pointer to
       
   259 +subcommand description struct to 'value.cmd' field of corresponding
       
   260 +'cmdarg_value_t' struct and updates it's source and flags. Then, instead of
       
   261 +proceeding with parsing process, it recursively calls parser on remaining part
       
   262 +of command line, passing subparser subcommand description. Note, that if
       
   263 +subcommand parser will end parsing before hitting end of command line, parser
       
   264 +will proceed with parsing arguments for main command. Default value and argument
       
   265 +type fields are ignored for subcommands.
       
   266 +
       
   267 +Now let's take a look at value structure, that you'll be dealing with the most
       
   268 +in the actual code.
       
   269 +
       
   270 +## Argument value structure, 'cmdarg_value_t'
       
   271 +
       
   272 +[[!format c """ // -------------------------------------------------------------
       
   273 +
       
   274 +typedef struct cmdarg_value_struct cmdarg_value_t;
       
   275 +
       
   276 +typedef enum {
       
   277 +    cmdval_default = 0x0000,
       
   278 +    cmdval_visited = 0x0100,
       
   279 +    cmdval_freeme  = 0x0200,
       
   280 +} cmdval_flags_t;
       
   281 +
       
   282 +struct cmdarg_value_struct {
       
   283 +    cmdarg_t       *src;
       
   284 +    cmdval_flags_t flags;
       
   285 +    union {
       
   286 +        guint        uint;
       
   287 +        gint         sint;
       
   288 +        guint        swc;
       
   289 +        const gchar  *roarg;
       
   290 +        gchar        *arg;
       
   291 +        cmdopts_t    *cmd;
       
   292 +        struct {
       
   293 +            gpointer   bud;
       
   294 +            gchar      *resource;
       
   295 +        } rjid;
       
   296 +        gpointer     ptr;
       
   297 +    } value;
       
   298 +};
       
   299 +
       
   300 +// -------------------------------------------------------------      """     ]]
       
   301 +
       
   302 +Command may happen to be called recursively - i.e., something in command may
       
   303 +cause the event, that will cause another call to the same command, thus we
       
   304 +cannot store actual values in command/argument definition struct, and have to
       
   305 +allocate dynamic memory for them. This struct is designed exactly for this.
       
   306 +Let's take a look at it's fields:
       
   307 +
       
   308 + * 'src' - this points to the argument description, from which this struct is
       
   309 +   holding value right now (note, that value can be initialized several times
       
   310 +   during parsing process from different arguments).
       
   311 + 
       
   312 + * 'flags' - to hold parser and typechecker marks:
       
   313 +
       
   314 +    + 'visited' - parser uses this to track values, initialized from command
       
   315 +      line as opposed to values, holding default value.
       
   316 +    + 'freeme' - used by argument type checker to tell parser, that it needs to
       
   317 +      call value destructor callback on value.
       
   318 + 
       
   319 + * 'value' - union, that contains various possible forms of value:
       
   320 +
       
   321 +    + 'uint'  - generic unsigned integer.
       
   322 +    + 'sint'  - generic signed integer.
       
   323 +    + 'swc'   - switch occurence count.
       
   324 +    + 'roarg' - XXX read-only string - default value or like.
       
   325 +    + 'arg'   - generic string value (read-write).
       
   326 +    + 'cmd'   - pointer to subcommand description struct.
       
   327 +    + 'rjid'  - roster jid value - pair of roster buddy and resource string.
       
   328 +    + 'ptr'   - used for anything, that does not fits into these types.
       
   329 +
       
   330 +To better understand, how these fields are used, let's walk through parsing
       
   331 +process.
       
   332 +
       
   333 +## Parsing
       
   334 +
       
   335 +Parser starts by allocating memory for values array, and then initializing it by
       
   336 +walking through command description, looking at options and arguments and
       
   337 +assigning default values to corresponding entries in array. It also puts pointer
       
   338 +to the argument description into value's 'src' field. Thus, all used in command
       
   339 +description values will have this field initialized, even if they were not
       
   340 +specified on command line. This comes handly later, when checking for reqired
       
   341 +value presence. For switches parser just sets the counter to zero. Note, that
       
   342 +parser does not descend into subcommands at this stage. It does the same
       
   343 +procedure for subcommand, but later, when it already knows which subcommand is
       
   344 +selected. Also note, that if several arguments have the same value index, parser
       
   345 +will use latest encountered one to initialize the value. This is used for
       
   346 +default value in "argument clustering", that I'll show you later.
       
   347 +
       
   348 +Then parser calls command environment checker callback (if present), and if it
       
   349 +returns error - terminates the process right now. Note, that subcommands can
       
   350 +also have checkers.
       
   351 +
       
   352 +Next parser does its job of parsing command line. Each time it extracts argument
       
   353 +value, it into 'value.arg' field of corresponding value entry and pointer to
       
   354 +argument description struct into 'src' field. Also it sets 'visited' flag on
       
   355 +value. At this stage value is still just unchecked string, except for special
       
   356 +argument types. For switch occurence count in 'value.swc' gets increased each
       
   357 +time argument was specified. Note however, that if several switches use the same
       
   358 +value index ("clustered switches"), counter gets reset, when switches change one
       
   359 +another in sequence - i.e. "-e -s -s -s" will count as three "-s", but "-s -s -e
       
   360 +-s" will count as only one "-s". For subcommands parser checks for corresponding
       
   361 +subcommand in 'cmds' list, assigns it to 'value.cmd' and recursively passes the
       
   362 +end of command line to be parsed with subcommand description. Note, that for
       
   363 +subcommands parser does "checking on the spot" - if parsed argument value does
       
   364 +not match any subcommand, and argument have 'required' flag set, it raises error
       
   365 +immediately (if flag is not set, it merely assigns NULL and proceeds parsing
       
   366 +according to current command description).
       
   367 +
       
   368 +Then parser walks through array of values and performs value checking. Note,
       
   369 +that all values, that need checking at this point should have 'src' field
       
   370 +initialized - either set at default value assignment step, or during parsing,
       
   371 +so, parser knows properties of value's argument. Parser only pays attention to
       
   372 +the values, that either have 'visited' flag set (i.e. provided by user) or that
       
   373 +have 'check' flag in argument description (useful for mandatory arguments or
       
   374 +default values, that need convesion). If value corresponds to a switch, and
       
   375 +argument have 'check' flag set, switch occurence count is replaced by remainder
       
   376 +of division it by 2 (this way switch behaves like trigger). If it is a
       
   377 +subcommand, and it have 'required' flag set, parser checks, if it have non-NULL
       
   378 +value. If it is usual argument (option or positional), and it does have 'type',
       
   379 +that have 'check' callback set, parser calls this checker, passing it value
       
   380 +structure (again, value structure contains pointer to argument description, so,
       
   381 +checker can access 'chkdata' field, supplied by user). If checker returns error
       
   382 +string and argument have 'required' flag set, parser raises error. If flag is
       
   383 +not set, parser just prints warning and proceeds with checking.
       
   384 +
       
   385 +If checking was successful, parser calls command function, providing it with
       
   386 +command description and values array. This function can also return error, but
       
   387 +at this stage it does not change process, only causes error message to be
       
   388 +printed.
       
   389 +
       
   390 +And finally parser frees allocated resources - walks through values array,
       
   391 +calling argument type 'free' callback on values, that have 'freeme' flag set and
       
   392 +then frees the array itself.
       
   393 +
       
   394 +## Argument type, 'cmdarg_type_t'
       
   395 +
       
   396 +[[!format c """ // -------------------------------------------------------------
       
   397 +
       
   398 +typedef struct cmdarg_type_struct cmdarg_type_t;
       
   399 +
       
   400 +typedef gchar *(*cmdarg_checker_t) (cmdarg_value_t *value);
       
   401 +typedef void (*cmdarg_destructor_t) (cmdarg_value_t *value);
       
   402 +// FIXME: this one is still not designed
       
   403 +typedef void (*cmdarg_completor_t) (void);
       
   404 +
       
   405 +struct cmdarg_type_struct {
       
   406 +    cmdarg_checker_t    check;
       
   407 +    cmdarg_destructor_t free;
       
   408 +    cmdarg_completor_t  complete;
       
   409 +};
       
   410 +
       
   411 +// -------------------------------------------------------------      """     ]]
       
   412 +
       
   413 +As you can see, argument type is nothing more than a set of callbacks:
       
   414 +
       
   415 + * 'check' - check parsed argument value for conformance to type rules, possibly
       
   416 +   replace with something different, like corresponding integer value or roster
       
   417 +   buddy pointer.
       
   418 +
       
   419 + * 'free' - if type checker may need to free some data afterwards, this callback
       
   420 +   should be set to corresponding function, and each time checker really needs
       
   421 +   value to be freed, it should set flag 'freeme' on value.
       
   422 +
       
   423 + * 'complete' - FIXME not yet designed callback, that will return list of
       
   424 +   possible completions according to given prefix.
       
   425 +
       
   426 +After parsing command line parser performs argument value checking, that's where
       
   427 +it calls 'check' callbacks.  Checker is given pointer to value structure, that
       
   428 +it needs to check. Checker can modify value string (except when it is default
       
   429 +value, but you have to supply your default values so, that they do not need
       
   430 +modifying) or completely replace it with another string or even non-string
       
   431 +object. If checker uses some resources (eg. allocates memory for replacement
       
   432 +value), it can set the flag 'freeme' on value to request call to value
       
   433 +destructor, when values array will be freed. If checker needs some additional
       
   434 +data (eg. it is some generic checker, that needs list of valid values or other
       
   435 +parameters), these data can be supplied in 'chkdata' field. Checker function
       
   436 +should return NULL on success or error string, that will be g_free()'d by
       
   437 +parser. Take note, that if argument does not have 'reqired' flag set, parser
       
   438 +will ignore checker error, so, it is recommended to nullify invalid value before
       
   439 +returning error (but it is not required).
       
   440 +
       
   441 +# Examples
       
   442 +
       
   443 +When writing description for a command, first thing, you have to do - is to
       
   444 +determine, which values your command can get from user. You don't have to be
       
   445 +shy - new interface is designed to encourage commands to be as flexible and
       
   446 +option-rich as possible. 
       
   447 +
       
   448 +Second - consider, which ones are to be specified as positional arguments, and
       
   449 +which should become options or switches.
       
   450 +
       
   451 +Next you will want to decide, which checks and restrictions should you put on
       
   452 +values. Essentially, determine value type.
       
   453 +
       
   454 +And then you can begin writing command definition. So, let's start with
       
   455 +something simple.
       
   456 +
       
   457 +## Single-argument no-checks command
       
   458 +
       
   459 +Let's look at command like /say, that have only one argument, that should be
       
   460 +passed as is, and with no restrictions:
       
   461 +
       
   462 +    /ex1 message...
       
   463 +
       
   464 +Definition for such command will look like:
       
   465 +
       
   466 +[[!format c """ // -------------------------------------------------------------
       
   467 +
       
   468 +// command function predeclaration
       
   469 +gchar *do_ex1 (cmdopts_t *command, cmdarg_value_t *values);
       
   470 +
       
   471 +// command arguments definition
       
   472 +cmdopts_t def_ex1 = {
       
   473 +    "ex1",              // command name
       
   474 +    cmd_default,        // flags
       
   475 +    NULL,               // checker
       
   476 +    do_ex1,             // command function
       
   477 +    NULL,               // list of options - none
       
   478 +    (cmdarg_t[2]){      // list of arguments
       
   479 +        {
       
   480 +            "message",  // argument name
       
   481 +            0,          // value index
       
   482 +            // flags:
       
   483 +            // - plain:    do not interpret quotes and escapes
       
   484 +            // - catchall: do not end argument on unescaped spaces
       
   485 +            cmdarg_plain | cmdarg_catchall,
       
   486 +            NULL,       // default value
       
   487 +            NULL,       // argument type
       
   488 +        },
       
   489 +        {NULL}          // this is an argument list end marker
       
   490 +    },
       
   491 +    NULL,               // list of subcommands - none
       
   492 +};
       
   493 +
       
   494 +// Command function gets shown above command description (we don't need it) and
       
   495 +// argument value list. Returns error message or NULL.
       
   496 +gchar *do_ex1 (cmdopts_t *command, cmdarg_value_t *values)
       
   497 +{
       
   498 +    gchar *message = values[0].value.arg;
       
   499 +    // now do something with message:
       
   500 +    // - check, if message was given at all
       
   501 +    if (!message || !*message)
       
   502 +        // return error, it will be printed, prepended by command name
       
   503 +        return g_strdup("You need to specify a message!");
       
   504 +    // - use the value
       
   505 +    scr_log_print (LPRINT_NORMAL, "Got the message: \"%s\".", message);
       
   506 +    // no error occured
       
   507 +    return NULL;
       
   508 +}
       
   509 +
       
   510 +...
       
   511 +// register our command
       
   512 +cmd_define (&def_ex1);
       
   513 +...
       
   514 +// remove command
       
   515 +cmd_undef (&def_ex1);
       
   516 +...
       
   517 +
       
   518 +[[!format c """ // -------------------------------------------------------------
       
   519 +
       
   520 +A lot of things to do to achieve a simple goal - does not look quite appealing
       
   521 +so far. Still, let's tweak our example a bit.
       
   522 +
       
   523 +Remember the third step - decide, which checks should apply to our argument.
       
   524 +Now, look at our command - we check, if message is NULL or if message is empty.
       
   525 +But imagine, that user has given us a message " " - it's of no big use to us,
       
   526 +so, probably, we should also strip leading/trailing spaces before doing the
       
   527 +check. That's where argument types come into play. We can write argument
       
   528 +checker for that! But luckily, we already have built-in standard checker, that
       
   529 +does exactly what we need - checks if string contains non-space characters. All
       
   530 +we need to do - to specify '&cmdarg_type_nonspace' as argument type and remove
       
   531 +our check inside of the command:
       
   532 +
       
   533 +[[!format c """ // -------------------------------------------------------------
       
   534 +
       
   535 +...
       
   536 +cmdopts_t def_ex1 = {
       
   537 +    "ex1",
       
   538 +    cmd_default,
       
   539 +    NULL,
       
   540 +    do_ex1,
       
   541 +    NULL,
       
   542 +    (cmdarg_t[2]){
       
   543 +        {
       
   544 +            "message",
       
   545 +            0,
       
   546 +            // flags:
       
   547 +            // - plain: do not interpret quotes and escapes
       
   548 +            // - catchall: do not end argument on unescaped spaces
       
   549 +            // - check: always invoke checker, even if user omitted the argument
       
   550 +            // - required: terminate processing, if checker returns error
       
   551 +            // a lot of flags, but we can use shortcuts:
       
   552 +            // - eol = plain + catchall: get everything to the end of line as is
       
   553 +            // - chreq = check + required: argument needs to have a valid value
       
   554 +            cmdarg_eol | cmdarg_chreq,
       
   555 +            NULL,
       
   556 +            // strip spaces, check if result have non-zero length
       
   557 +            &cmdarg_type_nonspace,
       
   558 +        },
       
   559 +        {NULL}
       
   560 +    },
       
   561 +    NULL,
       
   562 +};
       
   563 +
       
   564 +gchar *do_ex1 (cmdopts_t *command, cmdarg_value_t *values)
       
   565 +{
       
   566 +    scr_log_print (LPRINT_NORMAL, "Got the message: \"%s\".",
       
   567 +                   values[0].value.arg);
       
   568 +    return NULL;
       
   569 +}
       
   570 +...
       
   571 +
       
   572 +// -------------------------------------------------------------      """     ]]
       
   573 +
       
   574 +Ok, that's a little bit better. Now let's move on to something more complex.
       
   575 +
       
   576 +## Switches
       
   577 +
       
   578 +Let's add switches '-s' and '-l', that will define, where to print the message
       
   579 +to - to log or to screen. For that we will need another two value indices - one
       
   580 +for each switch.
       
   581 +
       
   582 +[[!format c """ // -------------------------------------------------------------
       
   583 +
       
   584 +...
       
   585 +cmdopts_t def_ex1 = {
       
   586 +    "ex1",
       
   587 +    cmd_default,
       
   588 +    NULL,
       
   589 +    do_ex1,
       
   590 +    (cmdopt_t[3]){
       
   591 +        {                    // first switch: [-s|--screen]
       
   592 +            's',             // short option name
       
   593 +            "screen",        // long option name
       
   594 +            {
       
   595 +              "screen",      // argument name - unused
       
   596 +              1,             // value position
       
   597 +              // flags:
       
   598 +              // - switch: this is switch
       
   599 +              cmdarg_switch,
       
   600 +              NULL,          // default value - unused
       
   601 +              NULL,          // type - unused
       
   602 +            }
       
   603 +        },
       
   604 +                             // second switch: [-l|--log]
       
   605 +        { 'l', "log", { "log", 2, cmdarg_switch, NULL, NULL } },
       
   606 +        {0}                  // end of list marker
       
   607 +    },
       
   608 +    (cmdarg_t[2]){
       
   609 +        { "message", 0, cmdarg_eol | cmdarg_chreq, NULL,
       
   610 +                                                   &cmdarg_type_nonspace },
       
   611 +        {NULL}
       
   612 +    },
       
   613 +    NULL,
       
   614 +};
       
   615 +
       
   616 +gchar *do_ex1 (cmdopts_t *command, cmdarg_value_t *values)
       
   617 +{
       
   618 +    // default value
       
   619 +    guint whereto = LPRINT_NORMAL;
       
   620 +    // -s is default, so, check, that it is not set before checking for -l
       
   621 +    if (!values[1].value.swc)
       
   622 +        if (values[2].value.swc)
       
   623 +            whereto = LPRINT_LOG;
       
   624 +    scr_log_print (whereto, "Got the message: \"%s\".", values[0].value.arg);
       
   625 +    return NULL;
       
   626 +}
       
   627 +...
       
   628 +
       
   629 +// -------------------------------------------------------------      """     ]]
       
   630 +
       
   631 +Ok, that works, but what if user have aliases, and wants last specified option
       
   632 +to override the value? Currently, if -s was once specified, -l will not have any
       
   633 +effect, regardless of count or position in command line. Not that good. Let's
       
   634 +use the trick, that I call "argument clustering". We'll specify the same value
       
   635 +index for both switches. Since 'value' struct have the pointer to the argument,
       
   636 +it was initialized from last time, we can recognize, which switch was used last.
       
   637 +By default this pointer points to the last argument with this index in command
       
   638 +definition - we can use that to specify default value. Now, to identify switches
       
   639 +we can use argument names, but 'argument' struct contains userdata field, where
       
   640 +we can put our LPRINT_* constants and just use it directly. So, with clustered
       
   641 +switches, we will have:
       
   642 +
       
   643 +[[!format c """ // -------------------------------------------------------------
       
   644 +
       
   645 +...
       
   646 +cmdopts_t def_ex1 = {
       
   647 +    "ex1",
       
   648 +    cmd_default,
       
   649 +    NULL,
       
   650 +    do_ex1,
       
   651 +    (cmdopt_t[3]){
       
   652 +        // Set both argument indices to 1, specify our constants in userdata
       
   653 +        // field. Screen is default value, thus, it goes last.
       
   654 +        { 'l', "log",    { "log",    1, cmdarg_switch, NULL, NULL, NULL,
       
   655 +                             (gpointer)LPRINT_LOG    } },
       
   656 +        { 's', "screen", { "screen", 1, cmdarg_switch, NULL, NULL, NULL,
       
   657 +                             (gpointer)LPRINT_NORMAL } },
       
   658 +        {0}
       
   659 +    },
       
   660 +    (cmdarg_t[2]){
       
   661 +        { "message", 0, cmdarg_eol | cmdarg_chreq, NULL,
       
   662 +                                                   &cmdarg_type_nonspace },
       
   663 +        {NULL}
       
   664 +    },
       
   665 +    NULL,
       
   666 +};
       
   667 +
       
   668 +gchar *do_ex1 (cmdopts_t *command, cmdarg_value_t *values)
       
   669 +{
       
   670 +    scr_log_print ((guint)values[1].src -> userdata,
       
   671 +                   "Got the message: \"%s\".", values[0].value.arg);
       
   672 +    return NULL;
       
   673 +}
       
   674 +...
       
   675 +
       
   676 +// -------------------------------------------------------------      """     ]]
       
   677 +
       
   678 +That's much better. This trick may be quite useful not only with switches, but
       
   679 +also with options, sometimes even clustering options with arguments can be
       
   680 +handy.
       
   681 +
       
   682 +## Options
       
   683 +
       
   684 +Options are not much different from normal arguments, except there you'll see
       
   685 +'check' and 'required' mostly only in combination with default value - otherwise
       
   686 +it defeats the purpose - to be optional.
       
   687 +
       
   688 +[[!format c """ // -------------------------------------------------------------
       
   689 +
       
   690 +// TODO:
       
   691 +//   example (not really used as of now - were too complex to deal using old
       
   692 +//   interface).
       
   693 +
       
   694 +// -------------------------------------------------------------      """     ]]
       
   695 +
       
   696 +## Subcommands
       
   697 +
       
   698 +Now, let's discuss another internal argument type - subcommand. Since
       
   699 +subcommands are quite common in mcabber, and since they have quite big impact on
       
   700 +parsing process, they were made a part of parser.
       
   701 +
       
   702 +Currently, only positional arguments can be subcommands. You can have options or
       
   703 +other arguments precede them, though in practice there's no examples of that so
       
   704 +far.
       
   705 +
       
   706 +So, to indicate, that argument is a subcommand, you just add flag 'subcmd'. When
       
   707 +parser will encounter such argument, it will look up command structure with
       
   708 +specified name in the list 'cmds' of command definition and proceed parsing,
       
   709 +using that command definition instead of main one. A good example of command
       
   710 +with several completely different subcommands would be '/color', so, let's look:
       
   711 +
       
   712 +[[!format c """ // -------------------------------------------------------------
       
   713 +
       
   714 +static gchar *do_color (cmdopts_t *command, cmdarg_value_t *values);
       
   715 +
       
   716 +// We will put these values in subcommand definition 'userdata' fields
       
   717 +// to simplify the task of determining, which subcommand was actually selected.
       
   718 +typedef enum {
       
   719 +    scmd_color_roster,
       
   720 +    scmd_color_mucnick,
       
   721 +    scmd_color_muc,
       
   722 +} scmd_color_t;
       
   723 +
       
   724 +// We define value inedxes as enum to make value access expressions
       
   725 +// self-explanatory.
       
   726 +typedef enum {
       
   727 +    pos_color_scmd          = 0,
       
   728 +    pos_color_roster_status = 1,
       
   729 +    pos_color_roster_jid    = 2,
       
   730 +    pos_color_roster_color  = 3,
       
   731 +    pos_color_muc_room      = 1,
       
   732 +    pos_color_muc_mode      = 2,
       
   733 +    pos_color_nick_nick     = 1,
       
   734 +    pos_color_nick_color    = 2,
       
   735 +} pos_color_t;
       
   736 +
       
   737 +// This is a helper struct for cmdarg_type_string2enum checker.
       
   738 +// The checker will compare value to strings and replace value.arg
       
   739 +// with corresponding value.uint.
       
   740 +static const string2enum_t s2e_color_muc[] = {
       
   741 +    { "on",     MC_ALL    },
       
   742 +    { "off",    MC_OFF    },
       
   743 +    { "preset", MC_PRESET },
       
   744 +    { "-",      MC_REMOVE },
       
   745 +    { NULL,     0         },
       
   746 +};
       
   747 +
       
   748 +static cmdopts_t def_color = {
       
   749 +    "color",
       
   750 +    // This command is allowed in main config file during initialization, thus
       
   751 +    // it have the 'safe' flag.
       
   752 +    cmd_safe,
       
   753 +    NULL,
       
   754 +    do_color,
       
   755 +    // no options
       
   756 +    NULL,
       
   757 +    // only one argument - subcommand
       
   758 +    (cmdarg_t[2]){{ "subcommand", pos_color_scmd, cmdarg_subcmd | cmdarg_chreq,
       
   759 +                                                           NULL, NULL },{NULL}},
       
   760 +    // three subcommands
       
   761 +    (cmdopts_t[4]){
       
   762 +        // First subcommand - 'roster' with three arguments.
       
   763 +        {"roster", cmd_default, NULL, NULL, NULL, (cmdarg_t[4]){
       
   764 +              { "statusmask|clear", pos_color_roster_status, cmdarg_chreq, NULL,
       
   765 +                           &cmdarg_type_color_statusmask, (gpointer)"ofdna_?" },
       
   766 +              { "jidmask",          pos_color_roster_jid,    cmdarg_check, NULL,
       
   767 +                           &cmdarg_type_bjidmask },
       
   768 +              { "color|-",          pos_color_roster_color,  cmdarg_check, NULL,
       
   769 +                           &cmdarg_type_color    },
       
   770 +              {NULL}
       
   771 +            },
       
   772 +            // Subcommand can have its own subcommands, but in this case we
       
   773 +            // don't have them.
       
   774 +            NULL,
       
   775 +            // We use userdata to determine, which subcommand was selected.
       
   776 +            (gpointer)scmd_color_roster},
       
   777 +        // Second subcommand - 'muc' with two arguments.
       
   778 +        {"muc", cmd_default, NULL, NULL, NULL, (cmdarg_t[3]){
       
   779 +              { "roomjid",         pos_color_muc_room, cmdarg_chreq, NULL,
       
   780 +                           &cmdarg_type_color_roomjid },
       
   781 +              { "on|off|preset|-", pos_color_muc_mode, cmdarg_chreq, "on",
       
   782 +                           &cmdarg_type_string2enum, (gpointer)s2e_color_muc },
       
   783 +              {NULL}
       
   784 +            }, NULL, (gpointer)scmd_color_muc},
       
   785 +        // Third subcommand - 'mucnick' also with two arguments.
       
   786 +        {"mucnick", cmd_default, NULL, NULL, NULL, (cmdarg_t[3]){
       
   787 +              { "nick",    pos_color_nick_nick,  cmdarg_chreq, NULL,
       
   788 +                           &cmdarg_type_nick  },
       
   789 +              { "color|-", pos_color_nick_color, cmdarg_chreq, NULL,
       
   790 +                           &cmdarg_type_color },
       
   791 +              {NULL}
       
   792 +            }, NULL, (gpointer)scmd_color_mucnick},
       
   793 +        {NULL}
       
   794 +    },
       
   795 +};
       
   796 +
       
   797 +static gchar *do_color (cmdopts_t *options, cmdarg_value_t *values)
       
   798 +{
       
   799 +    scmd_color_t subcmd =
       
   800 +                  (scmd_color_t) (values[pos_color_scmd].value.cmd -> userdata);
       
   801 +
       
   802 +    if (subcmd == scmd_color_roster) {
       
   803 +        const gchar *status   = values[pos_color_roster_status].value.arg;
       
   804 +        const gchar *wildcard = values[pos_color_roster_jid].value.arg;
       
   805 +        const gchar *color    = values[pos_color_roster_color].value.arg;
       
   806 +        if (!strcmp(status, "clear")) { // Not a color command, clear all
       
   807 +            scr_roster_clear_color();
       
   808 +            update_roster = TRUE;
       
   809 +        } else {
       
   810 +            // Unfortunately, due to "clear" case not taking any arguments,
       
   811 +            // we cannot check for argument presence using 'required' flag.
       
   812 +            if ((!wildcard) || (!color)) {
       
   813 +              return g_strdup ("Missing argument.");
       
   814 +            } else {
       
   815 +              update_roster = scr_roster_color(status, wildcard, color) ||
       
   816 +                              update_roster;
       
   817 +            }
       
   818 +        }
       
   819 +    } else if (subcmd == scmd_color_muc) {
       
   820 +        scr_muc_color ( values[pos_color_muc_room].value.arg,
       
   821 +                        values[pos_color_muc_mode].value.uint );
       
   822 +    } else { // scmd_color_mucnick
       
   823 +        scr_muc_nick_color( values[pos_color_nick_nick].value.arg,
       
   824 +                            values[pos_color_nick_color].value.arg );
       
   825 +    }
       
   826 +
       
   827 +    return NULL;
       
   828 +}
       
   829 +
       
   830 +// -------------------------------------------------------------      """     ]]
       
   831 +
       
   832 +Here you also see a lot of new types:
       
   833 +
       
   834 + * 'color_statusmask' - specific to "/color" command wrapper over generic type
       
   835 +   'charset'.  This type allows only word "clear" or string, composed of
       
   836 +   specified in 'chkdata' field characters, in this case tese are, of course,
       
   837 +   "ofdna_?".
       
   838 +
       
   839 + * 'bjidmask' - this type only provides completion, otherwise it is the same as
       
   840 +   'nonspace'.
       
   841 +
       
   842 + * 'color' - checks value to be a valid name of mcabber color.
       
   843 +
       
   844 + * 'color_roomjid' - specific to "/color" command wrapper over type 'bjid'.
       
   845 +   Type allows the string "*" or a valid bare jid.
       
   846 +
       
   847 + * 'string2enum' - generic type, that converts string into unsigned integer
       
   848 +   value according to given in 'chkdata' dictionary of name-value pairs.
       
   849 +
       
   850 + * 'nick' - as 'bjidmask' - only provides completion.
       
   851 +
       
   852 +## Argument types
       
   853 +
       
   854 +Let's take a look at simple checker, that we've encountered first - 'nonspace':
       
   855 +
       
   856 +[[!format c """ // -------------------------------------------------------------
       
   857 +
       
   858 +// Checker gets parsed value string in 'value.arg', argument description in
       
   859 +// 'src' and returns error string or NULL.
       
   860 +gchar *cmdarg_check_nonspace (cmdarg_value_t *arg)
       
   861 +{
       
   862 +    // current value
       
   863 +    gchar *val = arg -> value.arg;
       
   864 +
       
   865 +    // was value given at all?
       
   866 +    if (val) {
       
   867 +        // skip leading spaces
       
   868 +        while (isspace (*val))
       
   869 +            val ++;
       
   870 +        if (*val) { // valid arg - string contains non-space symbols
       
   871 +            // reassing value in case of stripped leading space
       
   872 +            arg -> value.arg = val;
       
   873 +            // strip trailing space
       
   874 +            while (*val)
       
   875 +                val ++;
       
   876 +            while (isspace (*val))
       
   877 +                val --;
       
   878 +            val ++;
       
   879 +            // Note: this needs write access, so, default value cannot contain
       
   880 +            // trailing spaces!
       
   881 +            if (*val)
       
   882 +                *val = '\0';
       
   883 +            // no error, argument is valid
       
   884 +            return NULL;
       
   885 +        }
       
   886 +    }
       
   887 +
       
   888 +    // Returned error may be ignored by parser, if 'required' flag is not set on
       
   889 +    // argument, so, we nullify argument to ensure, that invalid value will not
       
   890 +    // be passed to command.
       
   891 +    arg -> value.arg = NULL;
       
   892 +    return g_strdup ("Non-space value required.");
       
   893 +}
       
   894 +
       
   895 +// type definition
       
   896 +const cmdarg_type_t cmdarg_type_nonspace = {
       
   897 +    // our checker
       
   898 +    cmdarg_check_nonspace,
       
   899 +    // freeing callabck - no need for that
       
   900 +    NULL,
       
   901 +    // completion callabck - none, we can't know, what string may contain
       
   902 +    NULL,
       
   903 +};
       
   904 +
       
   905 +// -------------------------------------------------------------      """     ]]
       
   906 +
       
   907 +Quite simple, I hope. Now, let's look at more complex type - 'fjid':
       
   908 +
       
   909 +[[!format c """ // -------------------------------------------------------------
       
   910 +
       
   911 +// This checker checks syntax of fjid and expands "current-buddy" expressions
       
   912 +// "." and "./resource".
       
   913 +gchar *cmdarg_check_fjid (cmdarg_value_t *arg)
       
   914 +{
       
   915 +    gchar *error = NULL;
       
   916 +
       
   917 +    // We're using nonspace checker to check our value - empty string is not a
       
   918 +    // valid jid.
       
   919 +    if (!(error = cmdarg_check_nonspace(arg))) {
       
   920 +        // Now, we're sure, that we have non-space string
       
   921 +        const char *fjid = arg -> value.arg;
       
   922 +
       
   923 +        // We check for "current-buddy" expression.
       
   924 +        if (fjid[0] == '.' &&
       
   925 +                       (fjid[1] == JID_RESOURCE_SEPARATOR || fjid[1] == '\0')) {
       
   926 +            const char *jid;
       
   927 +            if (!current_buddy) {
       
   928 +              error = g_strdup_printf ("No buddy selected.");
       
   929 +            } else if (!(jid = buddy_getjid(BUDDATA(current_buddy)))) {
       
   930 +              error = g_strdup_printf ("Current buddy have no jid.");
       
   931 +            } else if (fjid[1] == '\0') {
       
   932 +              arg -> value.roarg = jid;
       
   933 +            } else {
       
   934 +              // We allocate value - we will need to free it, so, we as well set
       
   935 +              // 'freeme' flag.
       
   936 +              arg -> value.arg = g_strdup_printf ("%s%c%s",
       
   937 +                                         jid, JID_RESOURCE_SEPARATOR, fjid + 2);
       
   938 +              arg -> flags    |= cmdval_freeme;
       
   939 +            }
       
   940 +        // this is jid - check, that it is valid
       
   941 +        } else if (check_jid_syntax(fjid)) {
       
   942 +            error = g_strdup_printf ("Jid <%s> is invalid.", fjid);
       
   943 +        }
       
   944 +    }
       
   945 +
       
   946 +    // As before, nullify value in case of error
       
   947 +    if (error)
       
   948 +        arg -> value.arg = NULL;
       
   949 +    return error;
       
   950 +}
       
   951 +
       
   952 +// Free callback will be called only if freeme flag is set, so, we can
       
   953 +// just g_free() value without any checks.
       
   954 +void cmdarg_free_gfree (cmdarg_value_t *arg)
       
   955 +{
       
   956 +    g_free (arg -> value.arg);
       
   957 +}
       
   958 +
       
   959 +const cmdarg_type_t cmdarg_type_fjid = {
       
   960 +    // checker
       
   961 +    cmdarg_check_fjid,
       
   962 +    // freer
       
   963 +    cmdarg_free_gfree,
       
   964 +    // completor, while possible, is not implemented, as whole completion system is
       
   965 +    // not yet designed.
       
   966 +    NULL,
       
   967 +};
       
   968 +
       
   969 +// -------------------------------------------------------------      """     ]]
       
   970 +
       
   971 +If possible, you are encouraged to re-use existing checkers - for example, bjid
       
   972 +checker uses fjid checker to expand "current-buddy" expressions and check
       
   973 +syntax, and only strips resource afterwards:
       
   974 +
       
   975 +[[!format c """ // -------------------------------------------------------------
       
   976 +
       
   977 +gchar *cmdarg_check_bjid (cmdarg_value_t *arg)
       
   978 +{
       
   979 +    gchar *error = NULL;
       
   980 +
       
   981 +    if (!(error = cmdarg_check_fjid(arg))) {
       
   982 +        gchar *res = strchr (arg -> value.arg, JID_RESOURCE_SEPARATOR);
       
   983 +        if (res != NULL)
       
   984 +            *res = '\0';
       
   985 +    }
       
   986 +
       
   987 +    // Error can only happen inside fjid callback, that will nullify argument
       
   988 +    // for us.
       
   989 +    return error;
       
   990 +}
       
   991 +
       
   992 +const cmdarg_type_t cmdarg_type_bjid = {
       
   993 +    cmdarg_check_bjid,
       
   994 +    // may need to free value - we're using fjid checker internally
       
   995 +    cmdarg_free_gfree,
       
   996 +    NULL,
       
   997 +};
       
   998 +
       
   999 +// -------------------------------------------------------------      """     ]]
       
  1000 +
       
  1001 +So far we've only modified string in value. But checkers are not limited to
       
  1002 +this, for example, uint checker performs atoi() on value and assigns resulting
       
  1003 +number to value.uint. Take a look at definition of cmdarg_value_t struct - value
       
  1004 +is actually a union of different types of value. If you need something different
       
  1005 +from existing - you can always allocate your own struct and use value.ptr.
       
  1006 +However, if you think, that your case is generic enough - contact mcabber
       
  1007 +developers, we'll consider adding more variants there. Maybe we'll even add your
       
  1008 +argument type to built-in types.
       
  1009 +
       
  1010 +<!-- vim: se ts=4 sw=4 et filetype=markdown tw=80: -->
    40 diff -r 1b0b563a81e6 mcabber/doc/help/cs/hlp_buffer.txt
  1011 diff -r 1b0b563a81e6 mcabber/doc/help/cs/hlp_buffer.txt
    41 --- a/mcabber/doc/help/cs/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
  1012 --- a/mcabber/doc/help/cs/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
    42 +++ b/mcabber/doc/help/cs/hlp_buffer.txt	Mon Mar 18 02:16:22 2013 +0200
  1013 +++ b/mcabber/doc/help/cs/hlp_buffer.txt	Fri Mar 22 01:56:17 2013 +0200
    43 @@ -25,7 +25,7 @@
  1014 @@ -25,7 +25,7 @@
    44   Přesune se o [n] řádků nahoru (výchozí: polovina obrazovky).
  1015   Přesune se o [n] řádků nahoru (výchozí: polovina obrazovky).
    45  /buffer down [n]
  1016  /buffer down [n]
    46   Přesune se o [n] řádků dolů (výchozí: polovina obrazovky).
  1017   Přesune se o [n] řádků dolů (výchozí: polovina obrazovky).
    47 -/buffer date [datum]
  1018 -/buffer date [datum]
    49   Přesune se na první řádek po datu [datum] (formát: "RRRR-mm-dd").
  1020   Přesune se na první řádek po datu [datum] (formát: "RRRR-mm-dd").
    50  /buffer % n
  1021  /buffer % n
    51   Přesune se na procentuální pozici n%.
  1022   Přesune se na procentuální pozici n%.
    52 diff -r 1b0b563a81e6 mcabber/doc/help/cs/hlp_del.txt
  1023 diff -r 1b0b563a81e6 mcabber/doc/help/cs/hlp_del.txt
    53 --- a/mcabber/doc/help/cs/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
  1024 --- a/mcabber/doc/help/cs/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
    54 +++ b/mcabber/doc/help/cs/hlp_del.txt	Mon Mar 18 02:16:22 2013 +0200
  1025 +++ b/mcabber/doc/help/cs/hlp_del.txt	Fri Mar 22 01:56:17 2013 +0200
    55 @@ -1,4 +1,4 @@
  1026 @@ -1,4 +1,4 @@
    56  
  1027  
    57 - /DEL
  1028 - /DEL
    58 + /DEL [-n|--dryrun] [jid]
  1029 + /DEL [-n|--dryrun] [jid]
    59  
  1030  
    60  Smaže aktuální kontakt ze seznamu kontaktů (rosteru) a zruší povolení oznamování o stavu daného kontaktu (autorizaci) na obou stranách.
  1031  Smaže aktuální kontakt ze seznamu kontaktů (rosteru) a zruší povolení oznamování o stavu daného kontaktu (autorizaci) na obou stranách.
    61 diff -r 1b0b563a81e6 mcabber/doc/help/cs/hlp_move.txt
  1032 diff -r 1b0b563a81e6 mcabber/doc/help/cs/hlp_move.txt
    62 --- a/mcabber/doc/help/cs/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
  1033 --- a/mcabber/doc/help/cs/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
    63 +++ b/mcabber/doc/help/cs/hlp_move.txt	Mon Mar 18 02:16:22 2013 +0200
  1034 +++ b/mcabber/doc/help/cs/hlp_move.txt	Fri Mar 22 01:56:17 2013 +0200
    64 @@ -1,5 +1,6 @@
  1035 @@ -1,5 +1,6 @@
    65  
  1036  
    66 - /MOVE [skupina]
  1037 - /MOVE [skupina]
    67 + /MOVE [-j|--jid jid] [-n|--name name] [skupina]
  1038 + /MOVE [-j|--jid jid] [-n|--name name] [skupina]
    68  
  1039  
    69  Přesune aktuální kontakt do požadované skupiny. Není-li skupina zadána, přesune se kontakt do výchozí skupiny. Pokud skupina neexistuje, automaticky se založí.
  1040  Přesune aktuální kontakt do požadované skupiny. Není-li skupina zadána, přesune se kontakt do výchozí skupiny. Pokud skupina neexistuje, automaticky se založí.
    70 +You can select other buddy that current using options --jid and --name.
  1041 +You can select other buddy that current using options --jid and --name.
    71  Tip: V módu rozhovoru lze použít "/roster alternate" pro skok na přesunutý kontakt.
  1042  Tip: V módu rozhovoru lze použít "/roster alternate" pro skok na přesunutý kontakt.
    72 diff -r 1b0b563a81e6 mcabber/doc/help/cs/hlp_rename.txt
  1043 diff -r 1b0b563a81e6 mcabber/doc/help/cs/hlp_rename.txt
    73 --- a/mcabber/doc/help/cs/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
  1044 --- a/mcabber/doc/help/cs/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
    74 +++ b/mcabber/doc/help/cs/hlp_rename.txt	Mon Mar 18 02:16:22 2013 +0200
  1045 +++ b/mcabber/doc/help/cs/hlp_rename.txt	Fri Mar 22 01:56:17 2013 +0200
    75 @@ -1,4 +1,6 @@
  1046 @@ -1,4 +1,6 @@
    76  
  1047  
    77 - /RENAME jméno
  1048 - /RENAME jméno
    78 + /RENAME [-r|--reset] [-j|--jid jid] [-g|--group name] [-n|--name name] jméno
  1049 + /RENAME [-r|--reset] [-j|--jid jid] [-g|--group name] [-n|--name name] jméno
    79  
  1050  
    81 +Přejmenuje aktuálního uživatele nebo skupinu na 'jméno'.
  1052 +Přejmenuje aktuálního uživatele nebo skupinu na 'jméno'.
    82 +If --reset is specified, "newname" is ignored and name will be reset to default - jid or username.
  1053 +If --reset is specified, "newname" is ignored and name will be reset to default - jid or username.
    83 +Optionally you can use one of --jid, --group or --name to select object, different from current.
  1054 +Optionally you can use one of --jid, --group or --name to select object, different from current.
    84 diff -r 1b0b563a81e6 mcabber/doc/help/de/hlp_buffer.txt
  1055 diff -r 1b0b563a81e6 mcabber/doc/help/de/hlp_buffer.txt
    85 --- a/mcabber/doc/help/de/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
  1056 --- a/mcabber/doc/help/de/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
    86 +++ b/mcabber/doc/help/de/hlp_buffer.txt	Mon Mar 18 02:16:22 2013 +0200
  1057 +++ b/mcabber/doc/help/de/hlp_buffer.txt	Fri Mar 22 01:56:17 2013 +0200
    87 @@ -25,7 +25,7 @@
  1058 @@ -25,7 +25,7 @@
    88   Scrollt den Puffer um n Zeilen hoch. Gibt man keine Zahl an, scrollt er um einen halben Bildschirm
  1059   Scrollt den Puffer um n Zeilen hoch. Gibt man keine Zahl an, scrollt er um einen halben Bildschirm
    89  /buffer down [n]
  1060  /buffer down [n]
    90   Scrollt den Puffer um n Zeilen runter. Gibt man keine Zahl an, scrollt er um einen halben Bildschirm
  1061   Scrollt den Puffer um n Zeilen runter. Gibt man keine Zahl an, scrollt er um einen halben Bildschirm
    91 -/buffer date [date]
  1062 -/buffer date [date]
    93   Springe zu der ersten Zeile nach dem Datum, welches im Format "JJJJ-mm-tt" anstatt [date] angegeben werden muss
  1064   Springe zu der ersten Zeile nach dem Datum, welches im Format "JJJJ-mm-tt" anstatt [date] angegeben werden muss
    94  /buffer % n
  1065  /buffer % n
    95   Springe zur Position "n" im Chatpuffer
  1066   Springe zur Position "n" im Chatpuffer
    96 diff -r 1b0b563a81e6 mcabber/doc/help/de/hlp_del.txt
  1067 diff -r 1b0b563a81e6 mcabber/doc/help/de/hlp_del.txt
    97 --- a/mcabber/doc/help/de/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
  1068 --- a/mcabber/doc/help/de/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
    98 +++ b/mcabber/doc/help/de/hlp_del.txt	Mon Mar 18 02:16:22 2013 +0200
  1069 +++ b/mcabber/doc/help/de/hlp_del.txt	Fri Mar 22 01:56:17 2013 +0200
    99 @@ -1,4 +1,4 @@
  1070 @@ -1,4 +1,4 @@
   100  
  1071  
   101 - /DEL
  1072 - /DEL
   102 + /DEL [-n|--dryrun] [jid]
  1073 + /DEL [-n|--dryrun] [jid]
   103  
  1074  
   104  Löscht den gerade ausgewählten Buddy vom Roster. Außerdem werden die automatischen Presence Benachrichtigungen vom/zum Buddy gestoppt.
  1075  Löscht den gerade ausgewählten Buddy vom Roster. Außerdem werden die automatischen Presence Benachrichtigungen vom/zum Buddy gestoppt.
   105 diff -r 1b0b563a81e6 mcabber/doc/help/de/hlp_move.txt
  1076 diff -r 1b0b563a81e6 mcabber/doc/help/de/hlp_move.txt
   106 --- a/mcabber/doc/help/de/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
  1077 --- a/mcabber/doc/help/de/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
   107 +++ b/mcabber/doc/help/de/hlp_move.txt	Mon Mar 18 02:16:22 2013 +0200
  1078 +++ b/mcabber/doc/help/de/hlp_move.txt	Fri Mar 22 01:56:17 2013 +0200
   108 @@ -1,6 +1,7 @@
  1079 @@ -1,6 +1,7 @@
   109  
  1080  
   110 - /MOVE [groupname]
  1081 - /MOVE [groupname]
   111 + /MOVE [-j|--jid jid] [-n|--name name] [groupname]
  1082 + /MOVE [-j|--jid jid] [-n|--name name] [groupname]
   112  
  1083  
   114 +You can select other buddy that current using options --jid and --name.
  1085 +You can select other buddy that current using options --jid and --name.
   115  
  1086  
   116  Tipp: Wenn der Chatmodus aktiviert ist, kannst du "/roster alternate" benutzen um zu dem gerade bewegten Buddy zu springen.
  1087  Tipp: Wenn der Chatmodus aktiviert ist, kannst du "/roster alternate" benutzen um zu dem gerade bewegten Buddy zu springen.
   117 diff -r 1b0b563a81e6 mcabber/doc/help/de/hlp_rename.txt
  1088 diff -r 1b0b563a81e6 mcabber/doc/help/de/hlp_rename.txt
   118 --- a/mcabber/doc/help/de/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
  1089 --- a/mcabber/doc/help/de/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
   119 +++ b/mcabber/doc/help/de/hlp_rename.txt	Mon Mar 18 02:16:22 2013 +0200
  1090 +++ b/mcabber/doc/help/de/hlp_rename.txt	Fri Mar 22 01:56:17 2013 +0200
   120 @@ -1,4 +1,6 @@
  1091 @@ -1,4 +1,6 @@
   121  
  1092  
   122 - /RENAME name
  1093 - /RENAME name
   123 + /RENAME [-r|--reset] [-j|--jid jid] [-g|--group name] [-n|--name name] newname
  1094 + /RENAME [-r|--reset] [-j|--jid jid] [-g|--group name] [-n|--name name] newname
   124  
  1095  
   126 +Setzt den Namen des gerade ausgewählten Buddys bzw. der ausgewählten Gruppe auf "name".
  1097 +Setzt den Namen des gerade ausgewählten Buddys bzw. der ausgewählten Gruppe auf "name".
   127 +If --reset is specified, "newname" is ignored and name will be reset to default - jid or username.
  1098 +If --reset is specified, "newname" is ignored and name will be reset to default - jid or username.
   128 +Optionally you can use one of --jid, --group or --name to select object, different from current.
  1099 +Optionally you can use one of --jid, --group or --name to select object, different from current.
   129 diff -r 1b0b563a81e6 mcabber/doc/help/en/hlp_buffer.txt
  1100 diff -r 1b0b563a81e6 mcabber/doc/help/en/hlp_buffer.txt
   130 --- a/mcabber/doc/help/en/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
  1101 --- a/mcabber/doc/help/en/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
   131 +++ b/mcabber/doc/help/en/hlp_buffer.txt	Mon Mar 18 02:16:22 2013 +0200
  1102 +++ b/mcabber/doc/help/en/hlp_buffer.txt	Fri Mar 22 01:56:17 2013 +0200
   132 @@ -25,7 +25,7 @@
  1103 @@ -25,7 +25,7 @@
   133   Scroll the buffer up [n] lines (default: half a screen)
  1104   Scroll the buffer up [n] lines (default: half a screen)
   134  /buffer down [n]
  1105  /buffer down [n]
   135   Scroll the buffer down [n] lines (default: half a screen)
  1106   Scroll the buffer down [n] lines (default: half a screen)
   136 -/buffer date [date]
  1107 -/buffer date [date]
   138   Jump to the first line after the specified [date] in the chat buffer (date format: "YYYY-mm-dd")
  1109   Jump to the first line after the specified [date] in the chat buffer (date format: "YYYY-mm-dd")
   139  /buffer % n
  1110  /buffer % n
   140   Jump to position %n of the buddy chat buffer
  1111   Jump to position %n of the buddy chat buffer
   141 diff -r 1b0b563a81e6 mcabber/doc/help/en/hlp_del.txt
  1112 diff -r 1b0b563a81e6 mcabber/doc/help/en/hlp_del.txt
   142 --- a/mcabber/doc/help/en/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
  1113 --- a/mcabber/doc/help/en/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
   143 +++ b/mcabber/doc/help/en/hlp_del.txt	Mon Mar 18 02:16:22 2013 +0200
  1114 +++ b/mcabber/doc/help/en/hlp_del.txt	Fri Mar 22 01:56:17 2013 +0200
   144 @@ -1,4 +1,4 @@
  1115 @@ -1,4 +1,4 @@
   145  
  1116  
   146 - /DEL
  1117 - /DEL
   147 + /DEL [-n|--dryrun] [jid]
  1118 + /DEL [-n|--dryrun] [jid]
   148  
  1119  
   149 -Delete the current buddy from our roster, unsubscribe from its presence notification and unsubscribe it from ours.
  1120 -Delete the current buddy from our roster, unsubscribe from its presence notification and unsubscribe it from ours.
   150 +Delete the current buddy or one, specified with [jid] from our roster, unsubscribe from its presence notification and unsubscribe it from ours.
  1121 +Delete the current buddy or one, specified with [jid] from our roster, unsubscribe from its presence notification and unsubscribe it from ours.
   151 diff -r 1b0b563a81e6 mcabber/doc/help/en/hlp_move.txt
  1122 diff -r 1b0b563a81e6 mcabber/doc/help/en/hlp_move.txt
   152 --- a/mcabber/doc/help/en/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
  1123 --- a/mcabber/doc/help/en/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
   153 +++ b/mcabber/doc/help/en/hlp_move.txt	Mon Mar 18 02:16:22 2013 +0200
  1124 +++ b/mcabber/doc/help/en/hlp_move.txt	Fri Mar 22 01:56:17 2013 +0200
   154 @@ -1,5 +1,6 @@
  1125 @@ -1,5 +1,6 @@
   155  
  1126  
   156 - /MOVE [groupname]
  1127 - /MOVE [groupname]
   157 + /MOVE [-j|--jid jid] [-n|--name name] [groupname]
  1128 + /MOVE [-j|--jid jid] [-n|--name name] [groupname]
   158  
  1129  
   159  Move the current buddy to the requested group.  If no group is specified, then the buddy is moved to the default group.  If the group "groupname" doesn't exist, it is created.
  1130  Move the current buddy to the requested group.  If no group is specified, then the buddy is moved to the default group.  If the group "groupname" doesn't exist, it is created.
   160 +You can select other buddy that current using options --jid and --name.
  1131 +You can select other buddy that current using options --jid and --name.
   161  Tip: if the chatmode is enabled, you can use "/roster alternate" to jump to the moved buddy.
  1132  Tip: if the chatmode is enabled, you can use "/roster alternate" to jump to the moved buddy.
   162 diff -r 1b0b563a81e6 mcabber/doc/help/en/hlp_rename.txt
  1133 diff -r 1b0b563a81e6 mcabber/doc/help/en/hlp_rename.txt
   163 --- a/mcabber/doc/help/en/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
  1134 --- a/mcabber/doc/help/en/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
   164 +++ b/mcabber/doc/help/en/hlp_rename.txt	Mon Mar 18 02:16:22 2013 +0200
  1135 +++ b/mcabber/doc/help/en/hlp_rename.txt	Fri Mar 22 01:56:17 2013 +0200
   165 @@ -1,4 +1,6 @@
  1136 @@ -1,4 +1,6 @@
   166  
  1137  
   167 - /RENAME name
  1138 - /RENAME name
   168 + /RENAME [-r|--reset] [-j|--jid jid] [-g|--group name] [-n|--name name] newname
  1139 + /RENAME [-r|--reset] [-j|--jid jid] [-g|--group name] [-n|--name name] newname
   169  
  1140  
   171 +Rename the current buddy or group to the given "newname".
  1142 +Rename the current buddy or group to the given "newname".
   172 +If --reset is specified, "newname" is ignored and name will be reset to default - jid or username.
  1143 +If --reset is specified, "newname" is ignored and name will be reset to default - jid or username.
   173 +Optionally you can use one of --jid, --group or --name to select object, different from current.
  1144 +Optionally you can use one of --jid, --group or --name to select object, different from current.
   174 diff -r 1b0b563a81e6 mcabber/doc/help/fr/hlp_buffer.txt
  1145 diff -r 1b0b563a81e6 mcabber/doc/help/fr/hlp_buffer.txt
   175 --- a/mcabber/doc/help/fr/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
  1146 --- a/mcabber/doc/help/fr/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
   176 +++ b/mcabber/doc/help/fr/hlp_buffer.txt	Mon Mar 18 02:16:22 2013 +0200
  1147 +++ b/mcabber/doc/help/fr/hlp_buffer.txt	Fri Mar 22 01:56:17 2013 +0200
   177 @@ -25,7 +25,7 @@
  1148 @@ -25,7 +25,7 @@
   178   Défile vers le haut de [n] lignes (par défaut un demi écran)
  1149   Défile vers le haut de [n] lignes (par défaut un demi écran)
   179  /buffer down [n]
  1150  /buffer down [n]
   180   Défile vers le bas de [n] lignes (par défaut un demi écran)
  1151   Défile vers le bas de [n] lignes (par défaut un demi écran)
   181 -/buffer date [date]
  1152 -/buffer date [date]
   183   Va à la première ligne après la [date] dans le tampon actuel (format: "aaaa-mm-jj")
  1154   Va à la première ligne après la [date] dans le tampon actuel (format: "aaaa-mm-jj")
   184  /buffer % n
  1155  /buffer % n
   185   Va à la position n% du tampon
  1156   Va à la position n% du tampon
   186 diff -r 1b0b563a81e6 mcabber/doc/help/fr/hlp_del.txt
  1157 diff -r 1b0b563a81e6 mcabber/doc/help/fr/hlp_del.txt
   187 --- a/mcabber/doc/help/fr/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
  1158 --- a/mcabber/doc/help/fr/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
   188 +++ b/mcabber/doc/help/fr/hlp_del.txt	Mon Mar 18 02:16:22 2013 +0200
  1159 +++ b/mcabber/doc/help/fr/hlp_del.txt	Fri Mar 22 01:56:17 2013 +0200
   189 @@ -1,4 +1,4 @@
  1160 @@ -1,4 +1,4 @@
   190  
  1161  
   191 - /DEL
  1162 - /DEL
   192 + /DEL [-n|--dryrun] [jid]
  1163 + /DEL [-n|--dryrun] [jid]
   193  
  1164  
   194  Supprime le contact sélectionné du roster, supprime notre abonnement à ses notifications de présence et supprime son abonnement aux nôtres.
  1165  Supprime le contact sélectionné du roster, supprime notre abonnement à ses notifications de présence et supprime son abonnement aux nôtres.
   195 diff -r 1b0b563a81e6 mcabber/doc/help/fr/hlp_move.txt
  1166 diff -r 1b0b563a81e6 mcabber/doc/help/fr/hlp_move.txt
   196 --- a/mcabber/doc/help/fr/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
  1167 --- a/mcabber/doc/help/fr/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
   197 +++ b/mcabber/doc/help/fr/hlp_move.txt	Mon Mar 18 02:16:22 2013 +0200
  1168 +++ b/mcabber/doc/help/fr/hlp_move.txt	Fri Mar 22 01:56:17 2013 +0200
   198 @@ -1,5 +1,6 @@
  1169 @@ -1,5 +1,6 @@
   199  
  1170  
   200 - /MOVE [groupname]
  1171 - /MOVE [groupname]
   201 + /MOVE [-j|--jid jid] [-n|--name name] [groupname]
  1172 + /MOVE [-j|--jid jid] [-n|--name name] [groupname]
   202  
  1173  
   203  Déplace le contact sélectionné vers le groupe spécifié. Si aucun groupe n'est donné, le contact est déplacé vers le groupe par défaut. Si le groupe "groupname" n'existe pas, il est créé.
  1174  Déplace le contact sélectionné vers le groupe spécifié. Si aucun groupe n'est donné, le contact est déplacé vers le groupe par défaut. Si le groupe "groupname" n'existe pas, il est créé.
   204 +You can select other buddy that current using options --jid and --name.
  1175 +You can select other buddy that current using options --jid and --name.
   205  Astuce : si le mode discussion (chatmode) est activé, vous pouvez utiliser "/roster alternate" pour vous positionner sur le contact que vous venez de déplacer.
  1176  Astuce : si le mode discussion (chatmode) est activé, vous pouvez utiliser "/roster alternate" pour vous positionner sur le contact que vous venez de déplacer.
   206 diff -r 1b0b563a81e6 mcabber/doc/help/fr/hlp_rename.txt
  1177 diff -r 1b0b563a81e6 mcabber/doc/help/fr/hlp_rename.txt
   207 --- a/mcabber/doc/help/fr/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
  1178 --- a/mcabber/doc/help/fr/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
   208 +++ b/mcabber/doc/help/fr/hlp_rename.txt	Mon Mar 18 02:16:22 2013 +0200
  1179 +++ b/mcabber/doc/help/fr/hlp_rename.txt	Fri Mar 22 01:56:17 2013 +0200
   209 @@ -1,4 +1,6 @@
  1180 @@ -1,4 +1,6 @@
   210  
  1181  
   211 - /RENAME nom
  1182 - /RENAME nom
   212 + /RENAME [-r|--reset] [-j|--jid jid] [-g|--group name] [-n|--name name] nom
  1183 + /RENAME [-r|--reset] [-j|--jid jid] [-g|--group name] [-n|--name name] nom
   213  
  1184  
   215 +Renomme le contact/groupe sélectionné avec le "nom" spécifié.
  1186 +Renomme le contact/groupe sélectionné avec le "nom" spécifié.
   216 +If --reset is specified, "newname" is ignored and name will be reset to default - jid or username.
  1187 +If --reset is specified, "newname" is ignored and name will be reset to default - jid or username.
   217 +Optionally you can use one of --jid, --group or --name to select object, different from current.
  1188 +Optionally you can use one of --jid, --group or --name to select object, different from current.
   218 diff -r 1b0b563a81e6 mcabber/doc/help/it/hlp_buffer.txt
  1189 diff -r 1b0b563a81e6 mcabber/doc/help/it/hlp_buffer.txt
   219 --- a/mcabber/doc/help/it/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
  1190 --- a/mcabber/doc/help/it/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
   220 +++ b/mcabber/doc/help/it/hlp_buffer.txt	Mon Mar 18 02:16:22 2013 +0200
  1191 +++ b/mcabber/doc/help/it/hlp_buffer.txt	Fri Mar 22 01:56:17 2013 +0200
   221 @@ -25,7 +25,7 @@
  1192 @@ -25,7 +25,7 @@
   222   Fa scorrere indietro il buffer di [n] linee (default: metà schermo)
  1193   Fa scorrere indietro il buffer di [n] linee (default: metà schermo)
   223  /buffer down [n]
  1194  /buffer down [n]
   224   Fa scorrere avanti il buffer di [n] linee (default: metà schermo)
  1195   Fa scorrere avanti il buffer di [n] linee (default: metà schermo)
   225 -/buffer date [data]
  1196 -/buffer date [data]
   227   Salta alla prima linea successiva alla [data] specificata nel buffer di chat (formato della data: "YYYY-mm-dd")
  1198   Salta alla prima linea successiva alla [data] specificata nel buffer di chat (formato della data: "YYYY-mm-dd")
   228  /buffer % n
  1199  /buffer % n
   229   Salta alla posizione %n del buffer di chat corrente
  1200   Salta alla posizione %n del buffer di chat corrente
   230 diff -r 1b0b563a81e6 mcabber/doc/help/it/hlp_del.txt
  1201 diff -r 1b0b563a81e6 mcabber/doc/help/it/hlp_del.txt
   231 --- a/mcabber/doc/help/it/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
  1202 --- a/mcabber/doc/help/it/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
   232 +++ b/mcabber/doc/help/it/hlp_del.txt	Mon Mar 18 02:16:22 2013 +0200
  1203 +++ b/mcabber/doc/help/it/hlp_del.txt	Fri Mar 22 01:56:17 2013 +0200
   233 @@ -1,4 +1,4 @@
  1204 @@ -1,4 +1,4 @@
   234  
  1205  
   235 - /DEL
  1206 - /DEL
   236 + /DEL [-n|--dryrun] [jid]
  1207 + /DEL [-n|--dryrun] [jid]
   237  
  1208  
   238  Elimina il contatto corrente dal roster, cancellando la sottoscrizione alle reciproche notifiche della propria presenza.
  1209  Elimina il contatto corrente dal roster, cancellando la sottoscrizione alle reciproche notifiche della propria presenza.
   239 diff -r 1b0b563a81e6 mcabber/doc/help/it/hlp_move.txt
  1210 diff -r 1b0b563a81e6 mcabber/doc/help/it/hlp_move.txt
   240 --- a/mcabber/doc/help/it/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
  1211 --- a/mcabber/doc/help/it/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
   241 +++ b/mcabber/doc/help/it/hlp_move.txt	Mon Mar 18 02:16:22 2013 +0200
  1212 +++ b/mcabber/doc/help/it/hlp_move.txt	Fri Mar 22 01:56:17 2013 +0200
   242 @@ -1,5 +1,6 @@
  1213 @@ -1,5 +1,6 @@
   243  
  1214  
   244 - /MOVE [gruppo]
  1215 - /MOVE [gruppo]
   245 + /MOVE [-j|--jid jid] [-n|--name name] [grouppo]
  1216 + /MOVE [-j|--jid jid] [-n|--name name] [grouppo]
   246  
  1217  
   247  Muove il contatto corrente nel gruppo richiesto. Se non viene specificato alcun gruppo, il contatto viene spostato nel gruppo si default. Se il gruppo "gruppo" non esiste, viene creato.
  1218  Muove il contatto corrente nel gruppo richiesto. Se non viene specificato alcun gruppo, il contatto viene spostato nel gruppo si default. Se il gruppo "gruppo" non esiste, viene creato.
   248 +You can select other buddy that current using options --jid and --name.
  1219 +You can select other buddy that current using options --jid and --name.
   249  Trucco: se la modalità chat è abilitata, puoi usare "/roster alternate" per spostarti sul contatto appena mosso.
  1220  Trucco: se la modalità chat è abilitata, puoi usare "/roster alternate" per spostarti sul contatto appena mosso.
   250 diff -r 1b0b563a81e6 mcabber/doc/help/it/hlp_rename.txt
  1221 diff -r 1b0b563a81e6 mcabber/doc/help/it/hlp_rename.txt
   251 --- a/mcabber/doc/help/it/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
  1222 --- a/mcabber/doc/help/it/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
   252 +++ b/mcabber/doc/help/it/hlp_rename.txt	Mon Mar 18 02:16:22 2013 +0200
  1223 +++ b/mcabber/doc/help/it/hlp_rename.txt	Fri Mar 22 01:56:17 2013 +0200
   253 @@ -1,4 +1,6 @@
  1224 @@ -1,4 +1,6 @@
   254  
  1225  
   255 - /RENAME nome
  1226 - /RENAME nome
   256 + /RENAME [-r|--reset] [-j|--jid jid] [-g|--group name] [-n|--name name] nome
  1227 + /RENAME [-r|--reset] [-j|--jid jid] [-g|--group name] [-n|--name name] nome
   257  
  1228  
   259 +Rinomina il contatto od il gruppo correnti usando "nome".
  1230 +Rinomina il contatto od il gruppo correnti usando "nome".
   260 +If --reset is specified, "newname" is ignored and name will be reset to default - jid or username.
  1231 +If --reset is specified, "newname" is ignored and name will be reset to default - jid or username.
   261 +Optionally you can use one of --jid, --group or --name to select object, different from current.
  1232 +Optionally you can use one of --jid, --group or --name to select object, different from current.
   262 diff -r 1b0b563a81e6 mcabber/doc/help/nl/hlp_buffer.txt
  1233 diff -r 1b0b563a81e6 mcabber/doc/help/nl/hlp_buffer.txt
   263 --- a/mcabber/doc/help/nl/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
  1234 --- a/mcabber/doc/help/nl/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
   264 +++ b/mcabber/doc/help/nl/hlp_buffer.txt	Mon Mar 18 02:16:22 2013 +0200
  1235 +++ b/mcabber/doc/help/nl/hlp_buffer.txt	Fri Mar 22 01:56:17 2013 +0200
   265 @@ -25,7 +25,7 @@
  1236 @@ -25,7 +25,7 @@
   266   Scroll de buffer [n] regels omhoog (standaard: een half scherm)
  1237   Scroll de buffer [n] regels omhoog (standaard: een half scherm)
   267  /buffer down [n]
  1238  /buffer down [n]
   268   Scroll de buffer [n] regels omlaag (standaard: een half scherm)
  1239   Scroll de buffer [n] regels omlaag (standaard: een half scherm)
   269 -/buffer date [datum]
  1240 -/buffer date [datum]
   271   Spring naar de eerste regel na de aangeduide [datum] in de chat buffer (datum formaat: "YYYY-mm-dd")
  1242   Spring naar de eerste regel na de aangeduide [datum] in de chat buffer (datum formaat: "YYYY-mm-dd")
   272  /buffer % n
  1243  /buffer % n
   273   Spring naar positie %n in de buddy chat buffer
  1244   Spring naar positie %n in de buddy chat buffer
   274 diff -r 1b0b563a81e6 mcabber/doc/help/nl/hlp_del.txt
  1245 diff -r 1b0b563a81e6 mcabber/doc/help/nl/hlp_del.txt
   275 --- a/mcabber/doc/help/nl/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
  1246 --- a/mcabber/doc/help/nl/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
   276 +++ b/mcabber/doc/help/nl/hlp_del.txt	Mon Mar 18 02:16:22 2013 +0200
  1247 +++ b/mcabber/doc/help/nl/hlp_del.txt	Fri Mar 22 01:56:17 2013 +0200
   277 @@ -1,4 +1,4 @@
  1248 @@ -1,4 +1,4 @@
   278  
  1249  
   279 - /DEL
  1250 - /DEL
   280 + /DEL [-n|--dryrun] [jid]
  1251 + /DEL [-n|--dryrun] [jid]
   281  
  1252  
   282  Verwijder de actieve buddy uit ons roster, en zet het wederzijds toezenden van status veranderingen stop.
  1253  Verwijder de actieve buddy uit ons roster, en zet het wederzijds toezenden van status veranderingen stop.
   283 diff -r 1b0b563a81e6 mcabber/doc/help/nl/hlp_move.txt
  1254 diff -r 1b0b563a81e6 mcabber/doc/help/nl/hlp_move.txt
   284 --- a/mcabber/doc/help/nl/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
  1255 --- a/mcabber/doc/help/nl/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
   285 +++ b/mcabber/doc/help/nl/hlp_move.txt	Mon Mar 18 02:16:22 2013 +0200
  1256 +++ b/mcabber/doc/help/nl/hlp_move.txt	Fri Mar 22 01:56:17 2013 +0200
   286 @@ -1,5 +1,6 @@
  1257 @@ -1,5 +1,6 @@
   287  
  1258  
   288 - /MOVE [groepsnaam]
  1259 - /MOVE [groepsnaam]
   289 + /MOVE [-j|--jid jid] [-n|--name name] [groepsnaam]
  1260 + /MOVE [-j|--jid jid] [-n|--name name] [groepsnaam]
   290  
  1261  
   291  Verplaats de actieve buddy naar de aangegeven groep.  Indien geen groep werd gespecificeerd wordt buddy verplaatst naar de standaard groep.  Indien de groep "groepsnaam" niet bestaat, wordt die eerst aangemaakt.
  1262  Verplaats de actieve buddy naar de aangegeven groep.  Indien geen groep werd gespecificeerd wordt buddy verplaatst naar de standaard groep.  Indien de groep "groepsnaam" niet bestaat, wordt die eerst aangemaakt.
   292 +You can select other buddy that current using options --jid and --name.
  1263 +You can select other buddy that current using options --jid and --name.
   293  Tip: indien chatmode actief is, kun je "/roster alternate" gebruiken om direct naar de verplaatste buddy te springen.
  1264  Tip: indien chatmode actief is, kun je "/roster alternate" gebruiken om direct naar de verplaatste buddy te springen.
   294 diff -r 1b0b563a81e6 mcabber/doc/help/nl/hlp_rename.txt
  1265 diff -r 1b0b563a81e6 mcabber/doc/help/nl/hlp_rename.txt
   295 --- a/mcabber/doc/help/nl/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
  1266 --- a/mcabber/doc/help/nl/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
   296 +++ b/mcabber/doc/help/nl/hlp_rename.txt	Mon Mar 18 02:16:22 2013 +0200
  1267 +++ b/mcabber/doc/help/nl/hlp_rename.txt	Fri Mar 22 01:56:17 2013 +0200
   297 @@ -1,4 +1,6 @@
  1268 @@ -1,4 +1,6 @@
   298  
  1269  
   299 - /RENAME naam
  1270 - /RENAME naam
   300 + /RENAME [-r|--reset] [-j|--jid jid] [-g|--group name] [-n|--name name] naam
  1271 + /RENAME [-r|--reset] [-j|--jid jid] [-g|--group name] [-n|--name name] naam
   301  
  1272  
   303 +Hernoem de actieve buddy of groep in de aangegeven "naam".
  1274 +Hernoem de actieve buddy of groep in de aangegeven "naam".
   304 +If --reset is specified, "newname" is ignored and name will be reset to default - jid or username.
  1275 +If --reset is specified, "newname" is ignored and name will be reset to default - jid or username.
   305 +Optionally you can use one of --jid, --group or --name to select object, different from current.
  1276 +Optionally you can use one of --jid, --group or --name to select object, different from current.
   306 diff -r 1b0b563a81e6 mcabber/doc/help/pl/hlp_del.txt
  1277 diff -r 1b0b563a81e6 mcabber/doc/help/pl/hlp_del.txt
   307 --- a/mcabber/doc/help/pl/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
  1278 --- a/mcabber/doc/help/pl/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
   308 +++ b/mcabber/doc/help/pl/hlp_del.txt	Mon Mar 18 02:16:22 2013 +0200
  1279 +++ b/mcabber/doc/help/pl/hlp_del.txt	Fri Mar 22 01:56:17 2013 +0200
   309 @@ -1,4 +1,4 @@
  1280 @@ -1,4 +1,4 @@
   310  
  1281  
   311 - /DEL
  1282 - /DEL
   312 + /DEL [-n|--dryrun] [jid]
  1283 + /DEL [-n|--dryrun] [jid]
   313  
  1284  
   314  Usuwa aktualnie zaznaczoną osobę z rostera, usuwa subskrypcję powiadomienia dostępności u danej osoby oraz u nas.
  1285  Usuwa aktualnie zaznaczoną osobę z rostera, usuwa subskrypcję powiadomienia dostępności u danej osoby oraz u nas.
   315 diff -r 1b0b563a81e6 mcabber/doc/help/pl/hlp_move.txt
  1286 diff -r 1b0b563a81e6 mcabber/doc/help/pl/hlp_move.txt
   316 --- a/mcabber/doc/help/pl/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
  1287 --- a/mcabber/doc/help/pl/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
   317 +++ b/mcabber/doc/help/pl/hlp_move.txt	Mon Mar 18 02:16:22 2013 +0200
  1288 +++ b/mcabber/doc/help/pl/hlp_move.txt	Fri Mar 22 01:56:17 2013 +0200
   318 @@ -1,5 +1,6 @@
  1289 @@ -1,5 +1,6 @@
   319  
  1290  
   320 - /MOVE [nazwa grupy]
  1291 - /MOVE [nazwa grupy]
   321 + /MOVE [-j|--jid jid] [-n|--name name] [nazwa grupy]
  1292 + /MOVE [-j|--jid jid] [-n|--name name] [nazwa grupy]
   322  
  1293  
   323  Przenosi aktualną osobę do grupy "nazwa grupy".  Jeśli nie podano nazwy grupy, wtedy osoba jest przenoszona do grupy domyślnej.  Jeśli grupa "nazwa grupy" nie istnieje, zostaje utworzona.
  1294  Przenosi aktualną osobę do grupy "nazwa grupy".  Jeśli nie podano nazwy grupy, wtedy osoba jest przenoszona do grupy domyślnej.  Jeśli grupa "nazwa grupy" nie istnieje, zostaje utworzona.
   324 +You can select other buddy that current using options --jid and --name.
  1295 +You can select other buddy that current using options --jid and --name.
   325  Podpowiedź: jeśli jest włączony tryb czatu, możesz użyć "/roster alternate" aby skoczyć do przeniesionej osoby.
  1296  Podpowiedź: jeśli jest włączony tryb czatu, możesz użyć "/roster alternate" aby skoczyć do przeniesionej osoby.
   326 diff -r 1b0b563a81e6 mcabber/doc/help/pl/hlp_rename.txt
  1297 diff -r 1b0b563a81e6 mcabber/doc/help/pl/hlp_rename.txt
   327 --- a/mcabber/doc/help/pl/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
  1298 --- a/mcabber/doc/help/pl/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
   328 +++ b/mcabber/doc/help/pl/hlp_rename.txt	Mon Mar 18 02:16:22 2013 +0200
  1299 +++ b/mcabber/doc/help/pl/hlp_rename.txt	Fri Mar 22 01:56:17 2013 +0200
   329 @@ -1,4 +1,6 @@
  1300 @@ -1,4 +1,6 @@
   330  
  1301  
   331 - /RENAME nazwa
  1302 - /RENAME nazwa
   332 + /RENAME [-r|--reset] [-j|--jid jid] [-g|--group name] [-n|--name name] nazwa
  1303 + /RENAME [-r|--reset] [-j|--jid jid] [-g|--group name] [-n|--name name] nazwa
   333  
  1304  
   335 +Zmienia nazwę aktualnej osoby lub grupy na "nazwa". 
  1306 +Zmienia nazwę aktualnej osoby lub grupy na "nazwa". 
   336 +If --reset is specified, "newname" is ignored and name will be reset to default - jid or username.
  1307 +If --reset is specified, "newname" is ignored and name will be reset to default - jid or username.
   337 +Optionally you can use one of --jid, --group or --name to select object, different from current.
  1308 +Optionally you can use one of --jid, --group or --name to select object, different from current.
   338 diff -r 1b0b563a81e6 mcabber/doc/help/ru/hlp_buffer.txt
  1309 diff -r 1b0b563a81e6 mcabber/doc/help/ru/hlp_buffer.txt
   339 --- a/mcabber/doc/help/ru/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
  1310 --- a/mcabber/doc/help/ru/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
   340 +++ b/mcabber/doc/help/ru/hlp_buffer.txt	Mon Mar 18 02:16:22 2013 +0200
  1311 +++ b/mcabber/doc/help/ru/hlp_buffer.txt	Fri Mar 22 01:56:17 2013 +0200
   341 @@ -25,7 +25,7 @@
  1312 @@ -25,7 +25,7 @@
   342   Перемещает на [n] строк вверх в буфере (истории переписки) (по умолчанию: половина экрана)
  1313   Перемещает на [n] строк вверх в буфере (истории переписки) (по умолчанию: половина экрана)
   343  /buffer down [n]
  1314  /buffer down [n]
   344   Перемещает на [n] строк вниз в буфере (истории переписки) (по умолчанию: половина экрана)
  1315   Перемещает на [n] строк вниз в буфере (истории переписки) (по умолчанию: половина экрана)
   345 -/buffer date [date]
  1316 -/buffer date [date]
   347   Перемещает в первой строке после определенной даты [date] в буфере (истории переписки) (формат даты: "год-месяц-день", для примера "2006-01-01")
  1318   Перемещает в первой строке после определенной даты [date] в буфере (истории переписки) (формат даты: "год-месяц-день", для примера "2006-01-01")
   348  /buffer % n
  1319  /buffer % n
   349   Перемещает на позицию %n в текущем буфере (истории переписки)
  1320   Перемещает на позицию %n в текущем буфере (истории переписки)
   350 diff -r 1b0b563a81e6 mcabber/doc/help/ru/hlp_del.txt
  1321 diff -r 1b0b563a81e6 mcabber/doc/help/ru/hlp_del.txt
   351 --- a/mcabber/doc/help/ru/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
  1322 --- a/mcabber/doc/help/ru/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
   352 +++ b/mcabber/doc/help/ru/hlp_del.txt	Mon Mar 18 02:16:22 2013 +0200
  1323 +++ b/mcabber/doc/help/ru/hlp_del.txt	Fri Mar 22 01:56:17 2013 +0200
   353 @@ -1,4 +1,4 @@
  1324 @@ -1,4 +1,4 @@
   354  
  1325  
   355 - /DEL
  1326 - /DEL
   356 + /DEL [-n|--dryrun] [jid]
  1327 + /DEL [-n|--dryrun] [jid]
   357  
  1328  
   358 -Удаляет текущего пользователя из списка контактов, отключает уведомления о его статусе и отключает уведомления пользователя о вашем статусе.
  1329 -Удаляет текущего пользователя из списка контактов, отключает уведомления о его статусе и отключает уведомления пользователя о вашем статусе.
   359 +Удаляет текущего пользователя (или указанного с помощью jid) из списка контактов, отключает уведомления о его статусе и отключает уведомление пользователя о вашем статусе.
  1330 +Удаляет текущего пользователя (или указанного с помощью jid) из списка контактов, отключает уведомления о его статусе и отключает уведомление пользователя о вашем статусе.
   360 diff -r 1b0b563a81e6 mcabber/doc/help/ru/hlp_move.txt
  1331 diff -r 1b0b563a81e6 mcabber/doc/help/ru/hlp_move.txt
   361 --- a/mcabber/doc/help/ru/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
  1332 --- a/mcabber/doc/help/ru/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
   362 +++ b/mcabber/doc/help/ru/hlp_move.txt	Mon Mar 18 02:16:22 2013 +0200
  1333 +++ b/mcabber/doc/help/ru/hlp_move.txt	Fri Mar 22 01:56:17 2013 +0200
   363 @@ -1,6 +1,7 @@
  1334 @@ -1,6 +1,7 @@
   364  
  1335  
   365 - /MOVE [groupname]
  1336 - /MOVE [groupname]
   366 + /MOVE [-j|--jid jid] [-n|--name name] [groupname]
  1337 + /MOVE [-j|--jid jid] [-n|--name name] [groupname]
   367  
  1338  
   369 +С помощью параметров --jid и --name можно перемещать контакты, отличные от текущего.
  1340 +С помощью параметров --jid и --name можно перемещать контакты, отличные от текущего.
   370  Полезно: Если включен режим чата (chatmode), Вы можете использовать "/roster alternate" для перехода к перемещенному пользователю.
  1341  Полезно: Если включен режим чата (chatmode), Вы можете использовать "/roster alternate" для перехода к перемещенному пользователю.
   371  
  1342  
   372 diff -r 1b0b563a81e6 mcabber/doc/help/ru/hlp_rename.txt
  1343 diff -r 1b0b563a81e6 mcabber/doc/help/ru/hlp_rename.txt
   373 --- a/mcabber/doc/help/ru/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
  1344 --- a/mcabber/doc/help/ru/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
   374 +++ b/mcabber/doc/help/ru/hlp_rename.txt	Mon Mar 18 02:16:22 2013 +0200
  1345 +++ b/mcabber/doc/help/ru/hlp_rename.txt	Fri Mar 22 01:56:17 2013 +0200
   375 @@ -1,4 +1,6 @@
  1346 @@ -1,4 +1,6 @@
   376  
  1347  
   377 - /RENAME name
  1348 - /RENAME name
   378 + /RENAME [-r|--reset] [-j|--jid jid] [-g|--group name] [-n|--name name] newname
  1349 + /RENAME [-r|--reset] [-j|--jid jid] [-g|--group name] [-n|--name name] newname
   379  
  1350  
   381 +Переименовывает текущего пользователя или группу в заданное имя "newname".
  1352 +Переименовывает текущего пользователя или группу в заданное имя "newname".
   382 +Если указан параметр --reset, "newname" игнорируется, а имя сбрасывается (mcabber будет отображать JID или имя пользователя по умолчанию).
  1353 +Если указан параметр --reset, "newname" игнорируется, а имя сбрасывается (mcabber будет отображать JID или имя пользователя по умолчанию).
   383 +Для указания обьекта, отличного от текущего, можно использовать опции --jid, --group и --name.
  1354 +Для указания обьекта, отличного от текущего, можно использовать опции --jid, --group и --name.
   384 diff -r 1b0b563a81e6 mcabber/doc/help/uk/hlp_buffer.txt
  1355 diff -r 1b0b563a81e6 mcabber/doc/help/uk/hlp_buffer.txt
   385 --- a/mcabber/doc/help/uk/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
  1356 --- a/mcabber/doc/help/uk/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
   386 +++ b/mcabber/doc/help/uk/hlp_buffer.txt	Mon Mar 18 02:16:22 2013 +0200
  1357 +++ b/mcabber/doc/help/uk/hlp_buffer.txt	Fri Mar 22 01:56:17 2013 +0200
   387 @@ -25,7 +25,7 @@
  1358 @@ -25,7 +25,7 @@
   388   Посунути буфер вверх на n рядків (якщо не вказано - пів екрану).
  1359   Посунути буфер вверх на n рядків (якщо не вказано - пів екрану).
   389  /buffer down [n]
  1360  /buffer down [n]
   390   Посунути буфер вниз на n рядків (якщо не вказано - пів екрану).
  1361   Посунути буфер вниз на n рядків (якщо не вказано - пів екрану).
   391 -/buffer date [дата]
  1362 -/buffer date [дата]
   393   Перейти до першого повідомлення після дати (дата вигляду РРРР-ММ-ДД).
  1364   Перейти до першого повідомлення після дати (дата вигляду РРРР-ММ-ДД).
   394  /buffer % процент
  1365  /buffer % процент
   395   Перейти до вказаної у процентах позиції.
  1366   Перейти до вказаної у процентах позиції.
   396 diff -r 1b0b563a81e6 mcabber/doc/help/uk/hlp_del.txt
  1367 diff -r 1b0b563a81e6 mcabber/doc/help/uk/hlp_del.txt
   397 --- a/mcabber/doc/help/uk/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
  1368 --- a/mcabber/doc/help/uk/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
   398 +++ b/mcabber/doc/help/uk/hlp_del.txt	Mon Mar 18 02:16:22 2013 +0200
  1369 +++ b/mcabber/doc/help/uk/hlp_del.txt	Fri Mar 22 01:56:17 2013 +0200
   399 @@ -1,4 +1,4 @@
  1370 @@ -1,4 +1,4 @@
   400  
  1371  
   401 - /DEL
  1372 - /DEL
   402 + /DEL [-n|--dryrun] [jid]
  1373 + /DEL [-n|--dryrun] [jid]
   403  
  1374  
   404 -Потерти поточний контакт зі списку. На додачу відписатися від його повідомлень про статус і відписати його від ваших.
  1375 -Потерти поточний контакт зі списку. На додачу відписатися від його повідомлень про статус і відписати його від ваших.
   405 +Потерти поточний контакт (або контакт, що має вказаний jid) зі списку. Також відписатися від його сповіщень про статус і відписати його від ваших.
  1376 +Потерти поточний контакт (або контакт, що має вказаний jid) зі списку. Також відписатися від його сповіщень про статус і відписати його від ваших.
   406 diff -r 1b0b563a81e6 mcabber/doc/help/uk/hlp_move.txt
  1377 diff -r 1b0b563a81e6 mcabber/doc/help/uk/hlp_move.txt
   407 --- a/mcabber/doc/help/uk/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
  1378 --- a/mcabber/doc/help/uk/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
   408 +++ b/mcabber/doc/help/uk/hlp_move.txt	Mon Mar 18 02:16:22 2013 +0200
  1379 +++ b/mcabber/doc/help/uk/hlp_move.txt	Fri Mar 22 01:56:17 2013 +0200
   409 @@ -1,5 +1,6 @@
  1380 @@ -1,5 +1,6 @@
   410  
  1381  
   411 - /MOVE [група]
  1382 - /MOVE [група]
   412 + /MOVE [-j|--jid jid] [-n|--name ім’я] [група]
  1383 + /MOVE [-j|--jid jid] [-n|--name ім’я] [група]
   413  
  1384  
   415 +Переносить поточний контакт до вказаної групи. Якщо групу не вказати контакт опиниться у головній групі. Якщо групи не існує, її буде створено.
  1386 +Переносить поточний контакт до вказаної групи. Якщо групу не вказати контакт опиниться у головній групі. Якщо групи не існує, її буде створено.
   416 +За допомогою опцій --jid та --name можна перемістити контакт, відмінний від поточного.
  1387 +За допомогою опцій --jid та --name можна перемістити контакт, відмінний від поточного.
   417  Примітка: в режимі розмови можна використати "/roster alternate", щоб перейти до нового місця контакту контакту.
  1388  Примітка: в режимі розмови можна використати "/roster alternate", щоб перейти до нового місця контакту контакту.
   418 diff -r 1b0b563a81e6 mcabber/doc/help/uk/hlp_rename.txt
  1389 diff -r 1b0b563a81e6 mcabber/doc/help/uk/hlp_rename.txt
   419 --- a/mcabber/doc/help/uk/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
  1390 --- a/mcabber/doc/help/uk/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
   420 +++ b/mcabber/doc/help/uk/hlp_rename.txt	Mon Mar 18 02:16:22 2013 +0200
  1391 +++ b/mcabber/doc/help/uk/hlp_rename.txt	Fri Mar 22 01:56:17 2013 +0200
   421 @@ -1,4 +1,6 @@
  1392 @@ -1,4 +1,6 @@
   422  
  1393  
   423 - /RENAME ім'я
  1394 - /RENAME ім'я
   424 + /RENAME [-r|--reset] [-j|--jid jid] [-g|--group ім’я] [-n|--name ім’я] нове ім’я
  1395 + /RENAME [-r|--reset] [-j|--jid jid] [-g|--group ім’я] [-n|--name ім’я] нове ім’я
   425  
  1396  
   426  Змінює прізвисько поточного контакту або назву групи.
  1397  Змінює прізвисько поточного контакту або назву групи.
   427 +За допомогою параметра --reset можна повернути контакту типову назву. При цьому нове ім’я (якщо вказане) ігнорується.
  1398 +За допомогою параметра --reset можна повернути контакту типову назву. При цьому нове ім’я (якщо вказане) ігнорується.
   428 +Опції --jid, --group та --name дозволяють перейменовувати об’єкти, відмінні від поточного.
  1399 +Опції --jid, --group та --name дозволяють перейменовувати об’єкти, відмінні від поточного.
   429 diff -r 1b0b563a81e6 mcabber/mcabber/commands.c
  1400 diff -r 1b0b563a81e6 mcabber/mcabber/commands.c
   430 --- a/mcabber/mcabber/commands.c	Wed Mar 13 16:11:16 2013 +0200
  1401 --- a/mcabber/mcabber/commands.c	Wed Mar 13 16:11:16 2013 +0200
   431 +++ b/mcabber/mcabber/commands.c	Mon Mar 18 02:16:22 2013 +0200
  1402 +++ b/mcabber/mcabber/commands.c	Fri Mar 22 01:56:17 2013 +0200
   432 @@ -19,7 +19,7 @@
  1403 @@ -19,7 +19,7 @@
   433   * USA
  1404   * USA
   434   */
  1405   */
   435  
  1406  
   436 -#include <string.h>
  1407 -#include <string.h>
   470 +static void group_cmd (gpointer group, scmd_group_t action);
  1441 +static void group_cmd (gpointer group, scmd_group_t action);
   471 +static void say_cmd (char *arg, msgtype_t msgtype);
  1442 +static void say_cmd (char *arg, msgtype_t msgtype);
   472 +
  1443 +
   473 +//static void room_bookmark(gpointer bud, char *arg);
  1444 +//static void room_bookmark(gpointer bud, char *arg);
   474 +
  1445 +
   475 +#define BUILTIN_COUNT 8
  1446 +#define BUILTIN_COUNT 9
   476 +static cmdopts_t def_roster,
  1447 +static cmdopts_t def_roster,
   477 +                 def_color,
  1448 +                 def_color,
   478 +                 def_status,
  1449 +                 def_status,
   479 +                 def_status_to,
  1450 +                 def_status_to,
   480 +                 def_add,
  1451 +                 def_add,
   481 +                 def_del,
  1452 +                 def_del,
   482 +                 def_group,
  1453 +                 def_group,
   483 +                 def_say;
  1454 +                 def_say;
       
  1455 +                 def_msay,
   484 +#if 0
  1456 +#if 0
   485 +                 def_msay,
       
   486 +                 def_say_to,
  1457 +                 def_say_to,
   487 +                 def_buffer,
  1458 +                 def_buffer,
   488 +                 def_clear,
  1459 +                 def_clear,
   489 +                 def_info,
  1460 +                 def_info,
   490 +                 def_rename,
  1461 +                 def_rename,
   595 +  cmd_list[3]  = &def_status_to;
  1566 +  cmd_list[3]  = &def_status_to;
   596 +  cmd_list[4]  = &def_add;
  1567 +  cmd_list[4]  = &def_add;
   597 +  cmd_list[5]  = &def_del;
  1568 +  cmd_list[5]  = &def_del;
   598 +  cmd_list[6]  = &def_group;
  1569 +  cmd_list[6]  = &def_group;
   599 +  cmd_list[7]  = &def_say;
  1570 +  cmd_list[7]  = &def_say;
       
  1571 +  cmd_list[8]  = &def_msay;
   600 +#if 0
  1572 +#if 0
   601 +  cmd_list[8]  = &def_msay;
       
   602 +  cmd_list[9]  = &def_say_to;
  1573 +  cmd_list[9]  = &def_say_to;
   603 +  cmd_list[10] = &def_buffer;
  1574 +  cmd_list[10] = &def_buffer;
   604 +  cmd_list[11] = &def_clear;
  1575 +  cmd_list[11] = &def_clear;
   605 +  cmd_list[12] = &def_info;
  1576 +  cmd_list[12] = &def_info;
   606 +  cmd_list[13] = &def_rename;
  1577 +  cmd_list[13] = &def_rename;
  2340 +    xmpp_set_storage_rosternotes(bjid, NULL);
  3311 +    xmpp_set_storage_rosternotes(bjid, NULL);
  2341 +  else { // display a note
  3312 +  else { // display a note
  2342      struct annotation *note = xmpp_get_storage_rosternotes(bjid, FALSE);
  3313      struct annotation *note = xmpp_get_storage_rosternotes(bjid, FALSE);
  2343      if (note) {
  3314      if (note) {
  2344        display_and_free_note(note, bjid);
  3315        display_and_free_note(note, bjid);
  2345 @@ -800,484 +1377,618 @@
  3316 @@ -800,484 +1377,622 @@
  2346    }
  3317    }
  2347  }
  3318  }
  2348  
  3319  
  2349 -//  roster_updown(updown, nitems)
  3320 -//  roster_updown(updown, nitems)
  2350 -// updown: -1=up, +1=down
  3321 -// updown: -1=up, +1=down
  2384 +  "roster",
  3355 +  "roster",
  2385 +  cmd_default,
  3356 +  cmd_default,
  2386 +  NULL,
  3357 +  NULL,
  2387 +  do_roster,
  3358 +  do_roster,
  2388 +  NULL,
  3359 +  NULL,
  2389 +  (cmdarg_t[2]){{"subcommand", pos_roster_scmd, cmdarg_subcmd | cmdarg_check, NULL, NULL},{NULL}},
  3360 +  (cmdarg_t[2]){{"subcommand", pos_roster_scmd, cmdarg_subcmd | cmdarg_chreq, NULL, NULL},{NULL}},
  2390 +  (cmdopts_t[25]){
  3361 +  (cmdopts_t[25]){
  2391 +    SCMD_ROSTER(bottom, NULL),
  3362 +    SCMD_ROSTER(bottom, NULL),
  2392 +    SCMD_ROSTER(top,    NULL),
  3363 +    SCMD_ROSTER(top,    NULL),
  2393 +    SCMD_ROSTER(up,   (cmdarg_t[2]){{"n", pos_roster_up_n, cmdarg_chreq, "1", &cmdarg_type_uint},{NULL}}),
  3364 +    SCMD_ROSTER(up,   (cmdarg_t[2]){{"n", pos_roster_up_n, cmdarg_chreq, "1", &cmdarg_type_uint},{NULL}}),
  2394 +    SCMD_ROSTER(down, (cmdarg_t[2]){{"n", pos_roster_down_n, cmdarg_chreq, "1", &cmdarg_type_uint},{NULL}}),
  3365 +    SCMD_ROSTER(down, (cmdarg_t[2]){{"n", pos_roster_down_n, cmdarg_chreq, "1", &cmdarg_type_uint},{NULL}}),
  2699 +  "color",
  3670 +  "color",
  2700 +  cmd_safe,
  3671 +  cmd_safe,
  2701 +  NULL,
  3672 +  NULL,
  2702 +  do_color,
  3673 +  do_color,
  2703 +  NULL,
  3674 +  NULL,
  2704 +  (cmdarg_t[2]){{ "subcommand", pos_color_scmd, cmdarg_subcmd | cmdarg_check, NULL, NULL },{NULL}},
  3675 +  (cmdarg_t[2]){{ "subcommand", pos_color_scmd, cmdarg_subcmd | cmdarg_chreq, NULL, NULL },{NULL}},
  2705 +  (cmdopts_t[4]){
  3676 +  (cmdopts_t[4]){
  2706 +    {"roster", cmd_default, NULL, NULL, NULL, (cmdarg_t[4]){
  3677 +    {"roster", cmd_default, NULL, NULL, NULL, (cmdarg_t[4]){
  2707 +        { "statusmask|clear", pos_color_roster_status, cmdarg_chreq,   NULL, &cmdarg_type_color_statusmask, (gpointer)"ofdna_?" },
  3678 +        { "statusmask|clear", pos_color_roster_status, cmdarg_chreq, NULL, &cmdarg_type_color_statusmask, (gpointer)"ofdna_?" },
  2708 +        { "jidmask",          pos_color_roster_jid,    cmdarg_default, NULL, &cmdarg_type_bjidmask },
  3679 +        { "jidmask",          pos_color_roster_jid,    cmdarg_check, NULL, &cmdarg_type_bjidmask },
  2709 +        { "color|-",          pos_color_roster_color,  cmdarg_default, NULL, &cmdarg_type_color    },
  3680 +        { "color|-",          pos_color_roster_color,  cmdarg_check, NULL, &cmdarg_type_color    },
  2710 +        {NULL}
  3681 +        {NULL}
  2711 +      }, NULL, (gpointer)scmd_color_roster},
  3682 +      }, NULL, (gpointer)scmd_color_roster},
  2712 +    {"muc", cmd_default, NULL, NULL, NULL, (cmdarg_t[3]){
  3683 +    {"muc", cmd_default, NULL, NULL, NULL, (cmdarg_t[3]){
  2713 +        { "roomjid",         pos_color_muc_room, cmdarg_chreq, NULL, &cmdarg_type_color_roomjid, (gpointer)ROSTER_TYPE_ROOM },
  3684 +        { "roomjid",         pos_color_muc_room, cmdarg_chreq, NULL, &cmdarg_type_color_roomjid, (gpointer)ROSTER_TYPE_ROOM },
  2714 +        { "on|off|preset|-", pos_color_muc_mode, cmdarg_chreq, "on", &cmdarg_type_string2enum,   (gpointer)s2e_color_muc },
  3685 +        { "on|off|preset|-", pos_color_muc_mode, cmdarg_chreq, "on", &cmdarg_type_string2enum,   (gpointer)s2e_color_muc },
  2735        scr_roster_clear_color();
  3706        scr_roster_clear_color();
  2736        update_roster = TRUE;
  3707        update_roster = TRUE;
  2737      } else {
  3708      } else {
  2738 -      if (!status || !*status || !wildcard || !*wildcard || !color || !*color) {
  3709 -      if (!status || !*status || !wildcard || !*wildcard || !color || !*color) {
  2739 -        scr_LogPrint(LPRINT_NORMAL, "Missing argument");
  3710 -        scr_LogPrint(LPRINT_NORMAL, "Missing argument");
  2740 +      if (!wildcard || !*wildcard || !color || !*color) {
  3711 +      if ((!wildcard) || (!color)) {
  2741 +        // freaking "clear" :(
  3712 +        // freaking "clear" :(
  2742 +        return g_strdup ("Missing argument.");
  3713 +        return g_strdup ("Missing argument.");
  2743        } else {
  3714        } else {
  2744          update_roster = scr_roster_color(status, wildcard, color) ||
  3715          update_roster = scr_roster_color(status, wildcard, color) ||
  2745                          update_roster;
  3716                          update_roster;
  2856 +
  3827 +
  2857 +static gchar *do_status (cmdopts_t *command, cmdarg_value_t *values);
  3828 +static gchar *do_status (cmdopts_t *command, cmdarg_value_t *values);
  2858 +
  3829 +
  2859 +typedef enum {
  3830 +typedef enum {
  2860 +  pos_status_status  = 0,
  3831 +  pos_status_status  = 0,
  2861 +  pos_status_message = 1,
  3832 +  pos_status_jid     = 1,
       
  3833 +  pos_status_message = 2,
  2862 +} pos_status_t;
  3834 +} pos_status_t;
  2863 +
  3835 +
  2864 +static const string2enum_t s2e_status2[] = {
  3836 +static const string2enum_t s2e_status2[] = {
  2865 +  { "away",      away        },
  3837 +  { "away",      away        },
  2866 +  { "offline",   offline     },
  3838 +  { "offline",   offline     },
  2913 +static cmdopts_t def_status = {
  3885 +static cmdopts_t def_status = {
  2914 +  "status",
  3886 +  "status",
  2915 +  cmd_safe,
  3887 +  cmd_safe,
  2916 +  NULL,
  3888 +  NULL,
  2917 +  do_status,
  3889 +  do_status,
  2918 +  NULL,
  3890 +  (cmdopt_t[2]){
       
  3891 +    {'t', "to", {"jid", pos_status_jid, cmdarg_required, NULL, &cmdarg_type_fjid}},
       
  3892 +  },
  2919 +  (cmdarg_t[3]){
  3893 +  (cmdarg_t[3]){
  2920 +    {"status",  pos_status_status,  cmdarg_chreq, "show", &cmdarg_type_status_status, (gpointer)s2e_status2},
  3894 +    {"status",  pos_status_status,  cmdarg_chreq, "show", &cmdarg_type_status_status, (gpointer)s2e_status2},
  2921 +    {"message", pos_status_message, cmdarg_eol,   NULL,   &cmdarg_type_nonspace},
  3895 +    {"message", pos_status_message, cmdarg_eol,   NULL,   &cmdarg_type_nonspace},
  2922 +    {NULL}
  3896 +    {NULL}
  2923 +  },
  3897 +  },
  2935 -    return;
  3909 -    return;
  2936 +  } else {
  3910 +  } else {
  2937 +    if (!xmpp_is_online())
  3911 +    if (!xmpp_is_online())
  2938 +      scr_LogPrint(LPRINT_NORMAL, "You are currently not connected...");
  3912 +      scr_LogPrint(LPRINT_NORMAL, "You are currently not connected...");
  2939 +    scr_check_auto_away(TRUE);
  3913 +    scr_check_auto_away(TRUE);
  2940 +    xmpp_setstatus(values[pos_status_status].value.uint, NULL,
  3914 +    xmpp_setstatus(values[pos_status_status].value.uint,
       
  3915 +                   values[pos_status_jid].value.arg,
  2941 +                   values[pos_status_message].value.arg, FALSE);
  3916 +                   values[pos_status_message].value.arg, FALSE);
  2942    }
  3917    }
  2943 -  arg = to_utf8(arg);
  3918 -  arg = to_utf8(arg);
  2944 -  cmd_setstatus(NULL, arg);
  3919 -  cmd_setstatus(NULL, arg);
  2945 -  g_free(arg);
  3920 -  g_free(arg);
  3378 -                           LmMessageSubType type_overwrite, bool quiet)
  4353 -                           LmMessageSubType type_overwrite, bool quiet)
  3379 +                           msgtype_t msg_type, bool quiet)
  4354 +                           msgtype_t msg_type, bool quiet)
  3380  {
  4355  {
  3381    char *bare_jid, *rp;
  4356    char *bare_jid, *rp;
  3382    char *hmsg;
  4357    char *hmsg;
  3383 @@ -1285,6 +1996,7 @@
  4358 @@ -1285,6 +2000,7 @@
  3384    gint retval = 0;
  4359    gint retval = 0;
  3385    int isroom;
  4360    int isroom;
  3386    gpointer xep184 = NULL;
  4361    gpointer xep184 = NULL;
  3387 +  LmMessageSubType type_overwrite = LM_MESSAGE_SUB_TYPE_NOT_SET;
  4362 +  LmMessageSubType type_overwrite = LM_MESSAGE_SUB_TYPE_NOT_SET;
  3388  
  4363  
  3389    if (!xmpp_is_online()) {
  4364    if (!xmpp_is_online()) {
  3390      scr_LogPrint(LPRINT_NORMAL, "You are not connected.");
  4365      scr_LogPrint(LPRINT_NORMAL, "You are not connected.");
  3391 @@ -1299,11 +2011,15 @@
  4366 @@ -1299,11 +2015,15 @@
  3392      return 1;
  4367      return 1;
  3393    }
  4368    }
  3394    if (check_jid_syntax((char*)fjid)) {
  4369    if (check_jid_syntax((char*)fjid)) {
  3395 -    scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,
  4370 -    scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,
  3396 -                 "<%s> is not a valid Jabber ID.", fjid);
  4371 -                 "<%s> is not a valid Jabber ID.", fjid);
  3404 +    type_overwrite = LM_MESSAGE_SUB_TYPE_HEADLINE;
  4379 +    type_overwrite = LM_MESSAGE_SUB_TYPE_HEADLINE;
  3405 +
  4380 +
  3406    // We must use the bare jid in hk_message_out()
  4381    // We must use the bare jid in hk_message_out()
  3407    rp = strchr(fjid, JID_RESOURCE_SEPARATOR);
  4382    rp = strchr(fjid, JID_RESOURCE_SEPARATOR);
  3408    if (rp)
  4383    if (rp)
  3409 @@ -1354,8 +2070,7 @@
  4384 @@ -1354,8 +2074,7 @@
  3410  //  send_message(msg, subj, type_overwrite)
  4385  //  send_message(msg, subj, type_overwrite)
  3411  // Write the message in the buddy's window and send the message on
  4386  // Write the message in the buddy's window and send the message on
  3412  // the network.
  4387  // the network.
  3413 -static void send_message(const char *msg, const char *subj,
  4388 -static void send_message(const char *msg, const char *subj,
  3414 -                         LmMessageSubType type_overwrite)
  4389 -                         LmMessageSubType type_overwrite)
  3415 +static void send_message(const char *msg, const char *subj, msgtype_t msgtype)
  4390 +static void send_message(const char *msg, const char *subj, msgtype_t msgtype)
  3416  {
  4391  {
  3417    const char *bjid;
  4392    const char *bjid;
  3418    char *jid;
  4393    char *jid;
  3419 @@ -1378,34 +2093,13 @@
  4394 @@ -1378,34 +2097,13 @@
  3420    else
  4395    else
  3421      jid = g_strdup(bjid);
  4396      jid = g_strdup(bjid);
  3422  
  4397  
  3423 -  send_message_to(jid, msg, subj, type_overwrite, FALSE);
  4398 -  send_message_to(jid, msg, subj, type_overwrite, FALSE);
  3424 +  send_message_to(jid, msg, subj, msgtype, FALSE);
  4399 +  send_message_to(jid, msg, subj, msgtype, FALSE);
  3451    gpointer bud;
  4426    gpointer bud;
  3452 -  LmMessageSubType msgtype = LM_MESSAGE_SUB_TYPE_NOT_SET;
  4427 -  LmMessageSubType msgtype = LM_MESSAGE_SUB_TYPE_NOT_SET;
  3453  
  4428  
  3454    scr_set_chatmode(TRUE);
  4429    scr_set_chatmode(TRUE);
  3455    scr_show_buddy_window();
  4430    scr_show_buddy_window();
  3456 @@ -1424,80 +2118,137 @@
  4431 @@ -1424,135 +2122,190 @@
  3457    }
  4432    }
  3458  
  4433  
  3459    buddy_setflags(bud, ROSTER_FLAG_LOCK, TRUE);
  4434    buddy_setflags(bud, ROSTER_FLAG_LOCK, TRUE);
  3460 -  if (parse_flags)
  4435 -  if (parse_flags)
  3461 -    msgtype = scan_mtype(&arg);
  4436 -    msgtype = scan_mtype(&arg);
  3496 +  say_cmd(values[pos_say_msg].value.arg,
  4471 +  say_cmd(values[pos_say_msg].value.arg,
  3497 +          (msgtype_t) (values[pos_say_msgtype].src -> userdata));
  4472 +          (msgtype_t) (values[pos_say_msgtype].src -> userdata));
  3498 +  return NULL;
  4473 +  return NULL;
  3499  }
  4474  }
  3500  
  4475  
  3501 +#if 0
  4476 -static void do_msay(char *arg)
  3502 +
  4477 +//
  3503  static void do_msay(char *arg)
  4478 +//  /msay
       
  4479 +//
       
  4480 +
       
  4481 +static gchar *do_msay (cmdopts_t *command, cmdarg_value_t *values);
       
  4482 +
       
  4483 +typedef enum {
       
  4484 +  scmd_msay_begin, scmd_msay_verbatim,
       
  4485 +  scmd_msay_send, scmd_msay_send_to,
       
  4486 +  scmd_msay_toggle, scmd_msay_toggle_verbatim,
       
  4487 +  scmd_msay_abort,
       
  4488 +} scmd_msay_t;
       
  4489 +
       
  4490 +typedef enum {
       
  4491 +  pos_msay_scmd    = 0,
       
  4492 +  pos_msay_subject = 1,
       
  4493 +  pos_msay_jid     = 1,
       
  4494 +  pos_msay_msgtype = 2,
       
  4495 +} pos_msay_t;
       
  4496 +
       
  4497 +static cmdopts_t def_msay = {
       
  4498 +  "msay",
       
  4499 +  cmd_default,
       
  4500 +  NULL,
       
  4501 +  do_msay,
       
  4502 +  NULL,
       
  4503 +  (cmdarg_t[2]){
       
  4504 +    { "subcommand", pos_msay_scmd, cmdarg_subcmd|cmdarg_chreq, NULL, NULL },
       
  4505 +    {NULL},
       
  4506 +  },
       
  4507 +  (cmdopts_t[8]){
       
  4508 +    { "begin", cmd_default, NULL, NULL, NULL,
       
  4509 +      (cmdarg_t[2]){{"subject", pos_msay_subject, cmdarg_eol, NULL, &cmdarg_type_nonspace}, {NULL}},
       
  4510 +      NULL, (gpointer)scmd_msay_begin },
       
  4511 +    { "verbatim", cmd_default, NULL, NULL, NULL,
       
  4512 +      (cmdarg_t[2]){{"subject", pos_msay_subject, cmdarg_eol, NULL, &cmdarg_type_nonspace}, {NULL}},
       
  4513 +      NULL, (gpointer)scmd_msay_verbatim },
       
  4514 +    { "send", cmd_default, NULL, NULL,
       
  4515 +      (cmdopt_t[5]){
       
  4516 +        {'t', "to",       {"jid",      pos_msay_jid,     cmdarg_required, NULL, &cmdarg_type_fjid}},
       
  4517 +        {'n', "normal",   {"normal",   pos_msay_msgtype, cmdarg_switch, NULL, NULL, NULL, (gpointer)msgtype_normal}},
       
  4518 +        {'h', "headline", {"headline", pos_msay_msgtype, cmdarg_switch, NULL, NULL, NULL, (gpointer)msgtype_headline}},
       
  4519 +        {'d', "default",  {"default",  pos_msay_msgtype, cmdarg_switch, NULL, NULL, NULL, (gpointer)msgtype_not_set}},
       
  4520 +        {0}
       
  4521 +      },
       
  4522 +      NULL, NULL, (gpointer)scmd_msay_send, 0 },
       
  4523 +    { "send_to", cmd_default, NULL, NULL,
       
  4524 +      (cmdopt_t[4]){
       
  4525 +        {'n', "normal",   {"normal",   pos_msay_msgtype, cmdarg_switch, NULL, NULL, NULL, (gpointer)msgtype_normal}},
       
  4526 +        {'h', "headline", {"headline", pos_msay_msgtype, cmdarg_switch, NULL, NULL, NULL, (gpointer)msgtype_headline}},
       
  4527 +        {'d', "default",  {"default",  pos_msay_msgtype, cmdarg_switch, NULL, NULL, NULL, (gpointer)msgtype_not_set}},
       
  4528 +        {0}
       
  4529 +      },
       
  4530 +      (cmdarg_t[2]){{"jid", pos_msay_jid, cmdarg_chreq, NULL, &cmdarg_type_fjid}, {NULL}}, 
       
  4531 +      NULL, (gpointer)scmd_msay_send_to },
       
  4532 +    { "toggle", cmd_default, NULL, NULL, NULL, NULL, NULL, (gpointer)scmd_msay_toggle },
       
  4533 +    { "toggle_verbatim", cmd_default, NULL, NULL, NULL, NULL, NULL, (gpointer)scmd_msay_toggle_verbatim },
       
  4534 +    { "abort", cmd_default, NULL, NULL, NULL, NULL, NULL, (gpointer)scmd_msay_abort },
       
  4535 +  },
       
  4536 +};
       
  4537 +
       
  4538 +static gchar *do_msay (cmdopts_t *command, cmdarg_value_t *values)
  3504  {
  4539  {
  3505 -  /* Parameters: begin verbatim abort send send_to */
  4540 -  /* Parameters: begin verbatim abort send send_to */
  3506 -  char **paramlst;
  4541 -  char **paramlst;
  3507 -  char *subcmd;
  4542 -  char *subcmd;
  3508 -
  4543 -
  3515 -    scr_LogPrint(LPRINT_NORMAL, "Please read the manual before using "
  4550 -    scr_LogPrint(LPRINT_NORMAL, "Please read the manual before using "
  3516 -                 "the /msay command.");
  4551 -                 "the /msay command.");
  3517 -    scr_LogPrint(LPRINT_NORMAL, "(Use \"%s begin\" to enter "
  4552 -    scr_LogPrint(LPRINT_NORMAL, "(Use \"%s begin\" to enter "
  3518 -                 "multi-line mode...)", mkcmdstr("msay"));
  4553 -                 "multi-line mode...)", mkcmdstr("msay"));
  3519 -    goto do_msay_return;
  4554 -    goto do_msay_return;
  3520 +  enum msay_scmd_t {
       
  3521 +    msay_scmd_begin, msay_scmd_verbatim,
       
  3522 +    msay_scmd_send, msay_scmd_send_to,
       
  3523 +    msay_scmd_toggle, msay_scmd_toggle_verbatim,
       
  3524 +    msay_scmd_abort,
       
  3525 +  } subcmd;
       
  3526 +  cmdopts_t options = {
       
  3527 +    "msay",
       
  3528 +    NULL,
       
  3529 +    (cmdarg_t[1]){
       
  3530 +      // subcommand
       
  3531 +      { CMDOPT_SUBCOMMAND | CMDOPT_REQUIRED | CMDOPT_LAST, { .cmd = NULL } },
       
  3532 +    },
       
  3533 +    (cmdopts_t[7]){
       
  3534 +      { "begin", NULL,
       
  3535 +        (cmdarg_t[1]){
       
  3536 +          // subject
       
  3537 +          { CMDOPT_CATCHALL | CMDOPT_PLAIN | CMDOPT_LAST, { .arg = NULL } },
       
  3538 +        },
       
  3539 +        NULL, (gpointer)msay_scmd_begin, 0 },
       
  3540 +      { "verbatim", NULL,
       
  3541 +        (cmdarg_t[1]){
       
  3542 +          // subject
       
  3543 +          { CMDOPT_CATCHALL | CMDOPT_PLAIN | CMDOPT_LAST, { .arg = NULL } },
       
  3544 +        },
       
  3545 +        NULL, (gpointer)msay_scmd_verbatim, 0 },
       
  3546 +      { "send",
       
  3547 +        (cmdopt_t[2]){
       
  3548 +          { CMDOPT_SWITCH,               'n', "normal",   { .swc = 0 } },
       
  3549 +          { CMDOPT_SWITCH | CMDOPT_LAST, 'h', "headline", { .swc = 0 } },
       
  3550 +        },
       
  3551 +        NULL, NULL, (gpointer)msay_scmd_send, 0 },
       
  3552 +      { "send_to",
       
  3553 +        (cmdopt_t[2]){
       
  3554 +          { CMDOPT_SWITCH,               'n', "normal",   { .swc = 0 } },
       
  3555 +          { CMDOPT_SWITCH | CMDOPT_LAST, 'h', "headline", { .swc = 0 } },
       
  3556 +        },
       
  3557 +        (cmdarg_t[1]){
       
  3558 +          // jid
       
  3559 +          { CMDOPT_REQUIRED | CMDOPT_LAST, { .arg = NULL } },
       
  3560 +        }, 
       
  3561 +        NULL, (gpointer)msay_scmd_send_to, 0 },
       
  3562 +      { "toggle", NULL, NULL, NULL, (gpointer)msay_scmd_toggle, 0 },
       
  3563 +      { "toggle_verbatim", NULL, NULL, NULL,
       
  3564 +        (gpointer)msay_scmd_toggle_verbatim, 0 },
       
  3565 +      { "abort", NULL, NULL, NULL, (gpointer)msay_scmd_abort, CMDOPT_LAST },
       
  3566 +    },
       
  3567 +  };
       
  3568 +  const char *msg;
  4555 +  const char *msg;
  3569 +
  4556 +
  3570 +  if (cmdopts_parse(arg, &options))
  4557 +  subcmd = (scmd_msay_t) (values[pos_msay_scmd].src -> userdata);
  3571 +    return;
  4558 +
  3572 +
  4559 +  if (subcmd == scmd_msay_toggle) {
  3573 +  subcmd = (enum msay_scmd_t) options.args[0].value.cmd -> userdata;
       
  3574 +
       
  3575 +  if (subcmd == msay_scmd_toggle) {
       
  3576 +    if (scr_get_multimode())
  4560 +    if (scr_get_multimode())
  3577 +      subcmd = msay_scmd_send;
  4561 +      subcmd = scmd_msay_send;
  3578 +    else
  4562 +    else
  3579 +      subcmd = msay_scmd_begin;
  4563 +      subcmd = scmd_msay_begin;
  3580 +  } else if (subcmd == msay_scmd_toggle_verbatim) {
  4564 +  } else if (subcmd == scmd_msay_toggle_verbatim) {
  3581 +    if (scr_get_multimode())
  4565 +    if (scr_get_multimode())
  3582 +      subcmd = msay_scmd_send;
  4566 +      subcmd = scmd_msay_send;
  3583 +    else
  4567 +    else
  3584 +      subcmd = msay_scmd_verbatim;
  4568 +      subcmd = scmd_msay_verbatim;
  3585    }
  4569    }
  3586  
  4570  
  3587 -  if (!strcasecmp(subcmd, "toggle")) {
  4571 -  if (!strcasecmp(subcmd, "toggle")) {
  3588 -    if (scr_get_multimode())
  4572 -    if (scr_get_multimode())
  3589 -      subcmd = "send";
  4573 -      subcmd = "send";
  3595 -    else
  4579 -    else
  3596 -      subcmd = "verbatim";
  4580 -      subcmd = "verbatim";
  3597 -  }
  4581 -  }
  3598 -
  4582 -
  3599 -  if (!strcasecmp(subcmd, "abort")) {
  4583 -  if (!strcasecmp(subcmd, "abort")) {
  3600 +  if (subcmd == msay_scmd_abort) {
  4584 +  if (subcmd == scmd_msay_abort) {
  3601      if (scr_get_multimode())
  4585      if (scr_get_multimode())
  3602        scr_LogPrint(LPRINT_NORMAL, "Leaving multi-line message mode.");
  4586        scr_LogPrint(LPRINT_NORMAL, "Leaving multi-line message mode.");
  3603      scr_set_multimode(FALSE, NULL);
  4587      scr_set_multimode(FALSE, NULL);
  3604      goto do_msay_return;
  4588 -    goto do_msay_return;
  3605 -  } else if ((!strcasecmp(subcmd, "begin")) ||
  4589 -  } else if ((!strcasecmp(subcmd, "begin")) ||
  3606 -             (!strcasecmp(subcmd, "verbatim"))) {
  4590 -             (!strcasecmp(subcmd, "verbatim"))) {
  3607 -    bool verbat;
  4591 -    bool verbat;
  3608 -    gchar *subj_utf8 = to_utf8(arg);
  4592 -    gchar *subj_utf8 = to_utf8(arg);
  3609 -    if (!strcasecmp(subcmd, "verbatim")) {
  4593 -    if (!strcasecmp(subcmd, "verbatim")) {
  3610 -      scr_set_multimode(2, subj_utf8);
  4594 -      scr_set_multimode(2, subj_utf8);
  3611 -      verbat = TRUE;
  4595 -      verbat = TRUE;
  3612 +  } else if (subcmd == msay_scmd_begin || subcmd == msay_scmd_verbatim) {
  4596 +    return NULL;
  3613 +    gchar *subject = options.args[0].value.cmd -> args[0].value.arg;
  4597 +  } else if (subcmd == scmd_msay_begin || subcmd == scmd_msay_verbatim) {
  3614 +
  4598 +    gchar *subject = values[pos_msay_subject].value.arg;
  3615 +    if (subcmd == msay_scmd_verbatim) {
  4599 +
       
  4600 +    if (subcmd == scmd_msay_verbatim) {
  3616 +      scr_set_multimode(2, subject);
  4601 +      scr_set_multimode(2, subject);
  3617      } else {
  4602      } else {
  3618 -      scr_set_multimode(1, subj_utf8);
  4603 -      scr_set_multimode(1, subj_utf8);
  3619 -      verbat = FALSE;
  4604 -      verbat = FALSE;
  3620 +      scr_set_multimode(1, subject);
  4605 +      scr_set_multimode(1, subject);
  3621      }
  4606      }
  3622  
  4607  
  3623      scr_LogPrint(LPRINT_NORMAL, "Entered %smulti-line message mode.",
  4608      scr_LogPrint(LPRINT_NORMAL, "Entered %smulti-line message mode.",
  3624 -                 verbat ? "VERBATIM " : "");
  4609 -                 verbat ? "VERBATIM " : "");
  3625 +                 subcmd == msay_scmd_verbatim ? "VERBATIM " : "");
  4610 +                 subcmd == scmd_msay_verbatim ? "VERBATIM " : "");
  3626      scr_LogPrint(LPRINT_NORMAL, "Select a buddy and use \"%s send\" "
  4611      scr_LogPrint(LPRINT_NORMAL, "Select a buddy and use \"%s send\" "
  3627                   "when your message is ready.", mkcmdstr("msay"));
  4612                   "when your message is ready.", mkcmdstr("msay"));
  3628 -    if (verbat)
  4613 -    if (verbat)
  3629 +    if (subcmd == msay_scmd_verbatim)
  4614 +    if (subcmd == scmd_msay_verbatim)
  3630        scr_LogPrint(LPRINT_NORMAL, "Use \"%s abort\" to abort this mode.",
  4615        scr_LogPrint(LPRINT_NORMAL, "Use \"%s abort\" to abort this mode.",
  3631                     mkcmdstr("msay"));
  4616                     mkcmdstr("msay"));
  3632 -    g_free(subj_utf8);
  4617 -    g_free(subj_utf8);
  3633 -    goto do_msay_return;
  4618 -    goto do_msay_return;
  3634 -  } else if (strcasecmp(subcmd, "send") && strcasecmp(subcmd, "send_to")) {
  4619 -  } else if (strcasecmp(subcmd, "send") && strcasecmp(subcmd, "send_to")) {
  3635 -    scr_LogPrint(LPRINT_NORMAL, "Unrecognized parameter!");
  4620 -    scr_LogPrint(LPRINT_NORMAL, "Unrecognized parameter!");
  3636      goto do_msay_return;
  4621 -    goto do_msay_return;
       
  4622 +    return NULL;
  3637    }
  4623    }
  3638  
  4624  
  3639 -  /* send/send_to command */
  4625 -  /* send/send_to command */
  3640 +  /* msay_scmd_send or msay_scmd_send_to */
  4626 +  /* scmd_msay_send or scmd_msay_send_to */
  3641  
  4627  
  3642    if (!scr_get_multimode()) {
  4628    if (!scr_get_multimode()) {
  3643      scr_LogPrint(LPRINT_NORMAL, "No message to send.  "
  4629 -    scr_LogPrint(LPRINT_NORMAL, "No message to send.  "
  3644 @@ -1508,49 +2259,47 @@
  4630 +    return g_strdup_printf ("No message to send.  "
       
  4631                   "Use \"%s begin\" first.", mkcmdstr("msay"));
       
  4632 -    goto do_msay_return;
       
  4633    }
       
  4634  
  3645    scr_set_chatmode(TRUE);
  4635    scr_set_chatmode(TRUE);
  3646    scr_show_buddy_window();
  4636    scr_show_buddy_window();
  3647  
  4637  
  3648 -  if (!strcasecmp(subcmd, "send_to")) {
  4638 -  if (!strcasecmp(subcmd, "send_to")) {
  3649 -    int err = FALSE;
  4639 -    int err = FALSE;
  3681 -    msg_utf8 = to_utf8(scr_get_multiline());
  4671 -    msg_utf8 = to_utf8(scr_get_multiline());
  3682 -    if (msg_utf8) {
  4672 -    if (msg_utf8) {
  3683 -      send_message(msg_utf8, scr_get_multimode_subj(), scan_mtype(&arg));
  4673 -      send_message(msg_utf8, scr_get_multimode_subj(), scan_mtype(&arg));
  3684 -      g_free(msg_utf8);
  4674 -      g_free(msg_utf8);
  3685 +  if ((msg = scr_get_multiline())) {
  4675 +  if ((msg = scr_get_multiline())) {
  3686 +    msgtype_t msg_type = msgtype_not_set;
  4676 +    msgtype_t msg_type = (msgtype_t) (values[pos_msay_msgtype].src -> userdata);
  3687 +
  4677 +
  3688 +    if (options.args[0].value.cmd -> opts[0].value.swc) // n
  4678 +    if (subcmd == scmd_msay_send_to) {
  3689 +      msg_type = msgtype_normal;
  4679 +      const char *jid = values[pos_msay_jid].value.arg;
  3690 +    else if (options.args[0].value.cmd -> opts[1].value.swc) // h
       
  3691 +      msg_type = msgtype_headline;
       
  3692 +
       
  3693 +    if (subcmd == msay_scmd_send_to) {
       
  3694 +      const char *jid = options.cmds[3].args[0].value.arg;
       
  3695 +
  4680 +
  3696 +      // Let's send to the specified JID.  We leave now if there
  4681 +      // Let's send to the specified JID.  We leave now if there
  3697 +      // has been an error (so we don't leave multi-line mode).
  4682 +      // has been an error (so we don't leave multi-line mode).
  3698 +      if (send_message_to(jid, msg, scr_get_multimode_subj(),
  4683 +      if (send_message_to(jid, msg, scr_get_multimode_subj(),
  3699 +                          msg_type, FALSE))
  4684 +                          msg_type, FALSE))
  3700 +        goto do_msay_return;
  4685 +        return NULL;
  3701 +    } else { // Send to currently selected buddy
  4686 +    } else { // Send to currently selected buddy
  3702 +      gpointer bud;
  4687 +      gpointer bud;
  3703 +
  4688 +
  3704 +      if (!current_buddy) {
  4689 +      if (!current_buddy) {
  3705 +        scr_LogPrint(LPRINT_NORMAL, "Whom are you talking to?");
  4690 +        return g_strdup ("Whom are you talking to?");
  3706 +        goto do_msay_return;
       
  3707 +      }
  4691 +      }
  3708 +
  4692 +
  3709 +      bud = BUDDATA(current_buddy);
  4693 +      bud = BUDDATA(current_buddy);
  3710 +      if (!(buddy_gettype(bud) &
  4694 +      if (!(buddy_gettype(bud) &
  3711 +            (ROSTER_TYPE_USER|ROSTER_TYPE_AGENT|ROSTER_TYPE_ROOM))) {
  4695 +            (ROSTER_TYPE_USER|ROSTER_TYPE_AGENT|ROSTER_TYPE_ROOM))) {
  3712 +        scr_LogPrint(LPRINT_NORMAL, "This is not a user.");
  4696 +        return g_strdup ("This is not a user.");
  3713 +        goto do_msay_return;
       
  3714 +      }
  4697 +      }
  3715 +
  4698 +
  3716 +      buddy_setflags(bud, ROSTER_FLAG_LOCK, TRUE);
  4699 +      buddy_setflags(bud, ROSTER_FLAG_LOCK, TRUE);
  3717 +      send_message(msg, scr_get_multimode_subj(), msg_type);
  4700 +      send_message(msg, scr_get_multimode_subj(), msg_type);
  3718      }
  4701      }
  3719    }
  4702    }
  3720 +
  4703 +
  3721    scr_set_multimode(FALSE, NULL);
  4704    scr_set_multimode(FALSE, NULL);
  3722    scr_LogPrint(LPRINT_NORMAL, "You have left multi-line message mode.");
  4705    scr_LogPrint(LPRINT_NORMAL, "You have left multi-line message mode.");
  3723 +
  4706 -do_msay_return:
  3724  do_msay_return:
       
  3725 -  free_arg_lst(paramlst);
  4707 -  free_arg_lst(paramlst);
  3726 +  cmdopts_free(&options);
  4708 +
       
  4709 +  return NULL;
  3727  }
  4710  }
  3728  
  4711  
       
  4712 +#if 0
  3729  //  load_message_from_file(filename)
  4713  //  load_message_from_file(filename)
  3730 @@ -1566,7 +2315,7 @@
  4714  // Read the whole content of a file.
       
  4715  // The data are converted to UTF8, they should be freed by the caller after
       
  4716 @@ -1566,7 +2319,7 @@
  3731    char *next_utf8_char;
  4717    char *next_utf8_char;
  3732    size_t len;
  4718    size_t len;
  3733  
  4719  
  3734 -  fd = fopen(filename, "r");
  4720 -  fd = fopen(filename, "r");
  3735 +  fd = fopen(filename, "r"); // FIXME g_from_utf8
  4721 +  fd = fopen(filename, "r"); // FIXME g_from_utf8
  3736  
  4722  
  3737    if (!fd || fstat(fileno(fd), &buf)) {
  4723    if (!fd || fstat(fileno(fd), &buf)) {
  3738      scr_LogPrint(LPRINT_LOGNORM, "Cannot open message file (%s)", filename);
  4724      scr_LogPrint(LPRINT_LOGNORM, "Cannot open message file (%s)", filename);
  3739 @@ -1634,130 +2383,103 @@
  4725 @@ -1634,130 +2387,103 @@
  3740  
  4726  
  3741  static void do_say_to(char *arg)
  4727  static void do_say_to(char *arg)
  3742  {
  4728  {
  3743 -  char **paramlst;
  4729 -  char **paramlst;
  3744 -  char *fjid, *msg_utf8;
  4730 -  char *fjid, *msg_utf8;
  3921 +  g_free(freeme);
  4907 +  g_free(freeme);
  3922 +  g_free(freeme2);
  4908 +  g_free(freeme2);
  3923  }
  4909  }
  3924  
  4910  
  3925  //  buffer_updown(updown, nblines)
  4911  //  buffer_updown(updown, nblines)
  3926 @@ -1775,27 +2497,10 @@
  4912 @@ -1775,27 +2501,10 @@
  3927      scr_buffer_scroll_up_down(updown, nblines);
  4913      scr_buffer_scroll_up_down(updown, nblines);
  3928  }
  4914  }
  3929  
  4915  
  3930 -static void buffer_search(int direction, char *arg)
  4916 -static void buffer_search(int direction, char *arg)
  3931 -{
  4917 -{
  3949 -  strip_arg_special_chars(date);
  4935 -  strip_arg_special_chars(date);
  3950 -
  4936 -
  3951    t = from_iso8601(date, 0);
  4937    t = from_iso8601(date, 0);
  3952    if (t)
  4938    if (t)
  3953      scr_buffer_date(t);
  4939      scr_buffer_date(t);
  3954 @@ -1804,98 +2509,156 @@
  4940 @@ -1804,98 +2513,156 @@
  3955                   "not correctly formatted or invalid.");
  4941                   "not correctly formatted or invalid.");
  3956  }
  4942  }
  3957  
  4943  
  3958 -static void buffer_percent(char *arg1, char *arg2)
  4944 -static void buffer_percent(char *arg1, char *arg2)
  3959 +// XXX % command before was able to handle %50
  4945 +// XXX % command before was able to handle %50
  4188 -  do_buffer("clear");
  5174 -  do_buffer("clear");
  4189 +  scr_buffer_clear();
  5175 +  scr_buffer_clear();
  4190  }
  5176  }
  4191  
  5177  
  4192  static void do_info(char *arg)
  5178  static void do_info(char *arg)
  4193 @@ -2033,29 +2796,20 @@
  5179 @@ -2033,29 +2800,20 @@
  4194    }
  5180    }
  4195  }
  5181  }
  4196  
  5182  
  4197 +enum room_names_style_t {
  5183 +enum room_names_style_t {
  4198 +  room_names_style_normal = 0,
  5184 +  room_names_style_normal = 0,
  4227 -    }
  5213 -    }
  4228 -  }
  5214 -  }
  4229  
  5215  
  4230    // Enter chat mode
  5216    // Enter chat mode
  4231    scr_set_chatmode(TRUE);
  5217    scr_set_chatmode(TRUE);
  4232 @@ -2075,12 +2829,12 @@
  5218 @@ -2075,12 +2833,12 @@
  4233      rstatus = buddy_getstatus(bud, p_res->data);
  5219      rstatus = buddy_getstatus(bud, p_res->data);
  4234      rst_msg = buddy_getstatusmsg(bud, p_res->data);
  5220      rst_msg = buddy_getstatusmsg(bud, p_res->data);
  4235  
  5221  
  4236 -    if (style == style_short) {
  5222 -    if (style == style_short) {
  4237 +    if (style == room_names_style_short) {
  5223 +    if (style == room_names_style_short) {
  4242 -    } else if (style == style_compact) {
  5228 -    } else if (style == style_compact) {
  4243 +    } else if (style == room_names_style_compact) {
  5229 +    } else if (style == room_names_style_compact) {
  4244          enum imrole role = buddy_getrole(bud, p_res->data);
  5230          enum imrole role = buddy_getrole(bud, p_res->data);
  4245          enum imaffiliation affil = buddy_getaffil(bud, p_res->data);
  5231          enum imaffiliation affil = buddy_getaffil(bud, p_res->data);
  4246          bool showaffil = (affil != affil_none);
  5232          bool showaffil = (affil != affil_none);
  4247 @@ -2096,12 +2850,12 @@
  5233 @@ -2096,12 +2854,12 @@
  4248        snprintf(buffer, 4095, "[%c] %s", imstatus2char[rstatus],
  5234        snprintf(buffer, 4095, "[%c] %s", imstatus2char[rstatus],
  4249                 (char*)p_res->data);
  5235                 (char*)p_res->data);
  4250        scr_WriteIncomingMessage(bjid, buffer, 0, HBB_PREFIX_INFO, 0);
  5236        scr_WriteIncomingMessage(bjid, buffer, 0, HBB_PREFIX_INFO, 0);
  4251 -      if (rst_msg && style != style_quiet) {
  5237 -      if (rst_msg && style != style_quiet) {
  4252 +      if (rst_msg && style != room_names_style_quiet) {
  5238 +      if (rst_msg && style != room_names_style_quiet) {
  4257 -      if (style == style_detail) {
  5243 -      if (style == style_detail) {
  4258 +      if (style == room_names_style_detail) {
  5244 +      if (style == room_names_style_detail) {
  4259          enum imrole role = buddy_getrole(bud, p_res->data);
  5245          enum imrole role = buddy_getrole(bud, p_res->data);
  4260          enum imaffiliation affil = buddy_getaffil(bud, p_res->data);
  5246          enum imaffiliation affil = buddy_getaffil(bud, p_res->data);
  4261  
  5247  
  4262 @@ -2145,16 +2899,69 @@
  5248 @@ -2145,16 +2903,69 @@
  4263  
  5249  
  4264  static void do_rename(char *arg)
  5250  static void do_rename(char *arg)
  4265  {
  5251  {
  4266 +  cmdopts_t options = {
  5252 +  cmdopts_t options = {
  4267 +    "rename",
  5253 +    "rename",
  4332 +  }
  5318 +  }
  4333 +    
  5319 +    
  4334    bjid   = buddy_getjid(bud);
  5320    bjid   = buddy_getjid(bud);
  4335    group  = buddy_getgroupname(bud);
  5321    group  = buddy_getgroupname(bud);
  4336    type   = buddy_gettype(bud);
  5322    type   = buddy_gettype(bud);
  4337 @@ -2162,11 +2969,13 @@
  5323 @@ -2162,11 +2973,13 @@
  4338  
  5324  
  4339    if (type & ROSTER_TYPE_SPECIAL) {
  5325    if (type & ROSTER_TYPE_SPECIAL) {
  4340      scr_LogPrint(LPRINT_NORMAL, "You can't rename this item.");
  5326      scr_LogPrint(LPRINT_NORMAL, "You can't rename this item.");
  4341 +    cmdopts_free(&options);
  5327 +    cmdopts_free(&options);
  4342      return;
  5328      return;
  4347      scr_LogPrint(LPRINT_NORMAL, "Please specify a new name.");
  5333      scr_LogPrint(LPRINT_NORMAL, "Please specify a new name.");
  4348 +    cmdopts_free(&options);
  5334 +    cmdopts_free(&options);
  4349      return;
  5335      return;
  4350    }
  5336    }
  4351  
  5337  
  4352 @@ -2181,90 +2990,117 @@
  5338 @@ -2181,90 +2994,117 @@
  4353    //  }
  5339    //  }
  4354    //}
  5340    //}
  4355  
  5341  
  4356 -  newname = g_strdup(arg);
  5342 -  newname = g_strdup(arg);
  4357    // Remove trailing space
  5343    // Remove trailing space
  4496 +      // We do not move the buddy right now because the server could reject
  5482 +      // We do not move the buddy right now because the server could reject
  4497 +      // the request.  Let's wait for the server answer.
  5483 +      // the request.  Let's wait for the server answer.
  4498      } else {
  5484      } else {
  4499        // This is a local item, we move it without adding to roster.
  5485        // This is a local item, we move it without adding to roster.
  4500        guint msgflag;
  5486        guint msgflag;
  4501 @@ -2276,7 +3112,7 @@
  5487 @@ -2276,7 +3116,7 @@
  4502        msgflag = buddy_getflags(bud) & ROSTER_FLAG_MSG;
  5488        msgflag = buddy_getflags(bud) & ROSTER_FLAG_MSG;
  4503        if (msgflag)
  5489        if (msgflag)
  4504          roster_msg_setflag(bjid, FALSE, FALSE);
  5490          roster_msg_setflag(bjid, FALSE, FALSE);
  4505 -      buddy_setgroup(bud, group_utf8);
  5491 -      buddy_setgroup(bud, group_utf8);
  4506 +      buddy_setgroup(bud, newgroupname);
  5492 +      buddy_setgroup(bud, newgroupname);
  4507        if (msgflag)
  5493        if (msgflag)
  4508          roster_msg_setflag(bjid, FALSE, TRUE);
  5494          roster_msg_setflag(bjid, FALSE, TRUE);
  4509        if ((type & ROSTER_TYPE_ROOM) && xmpp_is_bookmarked(bjid) &&
  5495        if ((type & ROSTER_TYPE_ROOM) && xmpp_is_bookmarked(bjid) &&
  4510 @@ -2285,8 +3121,7 @@
  5496 @@ -2285,8 +3125,7 @@
  4511      }
  5497      }
  4512    }
  5498    }
  4513  
  5499  
  4514 -  g_free(group_utf8);
  5500 -  g_free(group_utf8);
  4515 -  g_free(newgroupname);
  5501 -  g_free(newgroupname);
  4516 +  cmdopts_free(&options);
  5502 +  cmdopts_free(&options);
  4517    update_roster = TRUE;
  5503    update_roster = TRUE;
  4518  }
  5504  }
  4519  
  5505  
  4520 @@ -2468,50 +3303,33 @@
  5506 @@ -2468,50 +3307,33 @@
  4521  
  5507  
  4522  static void do_rawxml(char *arg)
  5508  static void do_rawxml(char *arg)
  4523  {
  5509  {
  4524 -  char **paramlst;
  5510 -  char **paramlst;
  4525 -  char *subcmd;
  5511 -  char *subcmd;
  4586 +  lm_connection_send_raw(lconnection, options.cmds[0].args[0].value.arg, NULL);
  5572 +  lm_connection_send_raw(lconnection, options.cmds[0].args[0].value.arg, NULL);
  4587 +  cmdopts_free(&options);
  5573 +  cmdopts_free(&options);
  4588  }
  5574  }
  4589  
  5575  
  4590  //  check_room_subcommand(arg, param_needed, buddy_must_be_a_room)
  5576  //  check_room_subcommand(arg, param_needed, buddy_must_be_a_room)
  4591 @@ -2815,6 +3633,8 @@
  5577 @@ -2815,6 +3637,8 @@
  4592    free_arg_lst(paramlst);
  5578    free_arg_lst(paramlst);
  4593  }
  5579  }
  4594  
  5580  
  4595 +#endif
  5581 +#endif
  4596 +
  5582 +
  4597  void cmd_room_leave(gpointer bud, char *arg)
  5583  void cmd_room_leave(gpointer bud, char *arg)
  4598  {
  5584  {
  4599    gchar *roomid, *desc;
  5585    gchar *roomid, *desc;
  4600 @@ -2833,6 +3653,8 @@
  5586 @@ -2833,6 +3657,8 @@
  4601    g_free(roomid);
  5587    g_free(roomid);
  4602  }
  5588  }
  4603  
  5589  
  4604 +#if 0
  5590 +#if 0
  4605 +
  5591 +
  4606  static void room_nick(gpointer bud, char *arg)
  5592  static void room_nick(gpointer bud, char *arg)
  4607  {
  5593  {
  4608    if (!buddy_getinsideroom(bud)) {
  5594    if (!buddy_getinsideroom(bud)) {
  4609 @@ -2874,7 +3696,7 @@
  5595 @@ -2874,7 +3700,7 @@
  4610    fjid_utf8 = g_strdup_printf("%s/%s", buddy_getjid(bud), nick_utf8);
  5596    fjid_utf8 = g_strdup_printf("%s/%s", buddy_getjid(bud), nick_utf8);
  4611    g_free (nick_utf8);
  5597    g_free (nick_utf8);
  4612    msg = to_utf8(arg);
  5598    msg = to_utf8(arg);
  4613 -  send_message_to(fjid_utf8, msg, NULL, LM_MESSAGE_SUB_TYPE_NOT_SET, FALSE);
  5599 -  send_message_to(fjid_utf8, msg, NULL, LM_MESSAGE_SUB_TYPE_NOT_SET, FALSE);
  4614 +  send_message_to(fjid_utf8, msg, NULL, msgtype_not_set, FALSE);
  5600 +  send_message_to(fjid_utf8, msg, NULL, msgtype_not_set, FALSE);
  4615    g_free(fjid_utf8);
  5601    g_free(fjid_utf8);
  4616    g_free(msg);
  5602    g_free(msg);
  4617    free_arg_lst(paramlst);
  5603    free_arg_lst(paramlst);
  4618 @@ -3052,6 +3874,8 @@
  5604 @@ -3052,6 +3878,8 @@
  4619    free_arg_lst(paramlst);
  5605    free_arg_lst(paramlst);
  4620  }
  5606  }
  4621  
  5607  
  4622 +#endif
  5608 +#endif
  4623 +
  5609 +
  4624  //  cmd_room_whois(..)
  5610  //  cmd_room_whois(..)
  4625  // If interactive is TRUE, chatmode can be enabled.
  5611  // If interactive is TRUE, chatmode can be enabled.
  4626  // Please note that usernick is expected in UTF-8 locale iff interactive is
  5612  // Please note that usernick is expected in UTF-8 locale iff interactive is
  4627 @@ -3146,6 +3970,8 @@
  5613 @@ -3146,6 +3974,8 @@
  4628      free_arg_lst(paramlst);
  5614      free_arg_lst(paramlst);
  4629  }
  5615  }
  4630  
  5616  
  4631 +#if 0
  5617 +#if 0
  4632 +
  5618 +
  4633  static void room_bookmark(gpointer bud, char *arg)
  5619  static void room_bookmark(gpointer bud, char *arg)
  4634  {
  5620  {
  4635    const char *roomid;
  5621    const char *roomid;
  4636 @@ -3290,6 +4116,207 @@
  5622 @@ -3290,6 +4120,207 @@
  4637  
  5623  
  4638  static void do_room(char *arg)
  5624  static void do_room(char *arg)
  4639  {
  5625  {
  4640 +  enum room_scmd_t {
  5626 +  enum room_scmd_t {
  4641 +    room_scmd_join, room_scmd_leave,
  5627 +    room_scmd_join, room_scmd_leave,
  4839 +    },
  5825 +    },
  4840 +  };
  5826 +  };
  4841    char **paramlst;
  5827    char **paramlst;
  4842    char *subcmd;
  5828    char *subcmd;
  4843    gpointer bud;
  5829    gpointer bud;
  4844 @@ -3347,7 +4374,7 @@
  5830 @@ -3347,7 +4378,7 @@
  4845        cmd_room_leave(bud, arg);
  5831        cmd_room_leave(bud, arg);
  4846    } else if (!strcasecmp(subcmd, "names"))  {
  5832    } else if (!strcasecmp(subcmd, "names"))  {
  4847      if ((arg = check_room_subcommand(arg, FALSE, bud)) != NULL)
  5833      if ((arg = check_room_subcommand(arg, FALSE, bud)) != NULL)
  4848 -      room_names(bud, arg);
  5834 -      room_names(bud, arg);
  4849 +      room_names(bud, room_names_style_normal); // FIXME
  5835 +      room_names(bud, room_names_style_normal); // FIXME
  4850    } else if (!strcasecmp(subcmd, "nick"))  {
  5836    } else if (!strcasecmp(subcmd, "nick"))  {
  4851      if ((arg = check_room_subcommand(arg, FALSE, bud)) != NULL)
  5837      if ((arg = check_room_subcommand(arg, FALSE, bud)) != NULL)
  4852        room_nick(bud, arg);
  5838        room_nick(bud, arg);
  4853 @@ -4162,5 +5189,6 @@
  5839 @@ -4162,5 +5193,6 @@
  4854    }
  5840    }
  4855    mcabber_set_terminate_ui();
  5841    mcabber_set_terminate_ui();
  4856  }
  5842  }
  4857 +#endif
  5843 +#endif
  4858  
  5844  
  4859  /* vim: set expandtab cindent cinoptions=>2\:2(0 sw=2 ts=2:  For Vim users... */
  5845  /* vim: set expandtab cindent cinoptions=>2\:2(0 sw=2 ts=2:  For Vim users... */
  4860 diff -r 1b0b563a81e6 mcabber/mcabber/commands.h
  5846 diff -r 1b0b563a81e6 mcabber/mcabber/commands.h
  4861 --- a/mcabber/mcabber/commands.h	Wed Mar 13 16:11:16 2013 +0200
  5847 --- a/mcabber/mcabber/commands.h	Wed Mar 13 16:11:16 2013 +0200
  4862 +++ b/mcabber/mcabber/commands.h	Mon Mar 18 02:16:22 2013 +0200
  5848 +++ b/mcabber/mcabber/commands.h	Fri Mar 22 01:56:17 2013 +0200
  4863 @@ -5,32 +5,338 @@
  5849 @@ -5,32 +5,345 @@
  4864  
  5850  
  4865  #include <mcabber/config.h>
  5851  #include <mcabber/config.h>
  4866  
  5852  
  4867 -// Command structure
  5853 -// Command structure
  4868 +//
  5854 +//
  5011 +  cmdval_freeme   = 0x0200, // marks argument, that needs freeing
  5997 +  cmdval_freeme   = 0x0200, // marks argument, that needs freeing
  5012 +} cmdval_flags_t;
  5998 +} cmdval_flags_t;
  5013 +
  5999 +
  5014 +// command description
  6000 +// command description
  5015 +struct cmdopts_struct {
  6001 +struct cmdopts_struct {
  5016 +  const char    *name;     // [user,req] command name (error messages, help, subcommands)
  6002 +  const char          *name;     // [user,req] command name (error messages, help, subcommands)
  5017 +  cmd_flags_t   flags;     // [user,req] safe
  6003 +  const cmd_flags_t   flags;     // [user,req] safe
  5018 +  cmd_checker_t check;     // [user,req] checker routine
  6004 +  const cmd_checker_t check;     // [user,req] checker routine
  5019 +  cmd_handler_t handle;    // [user,req] main command processing function
  6005 +  const cmd_handler_t handle;    // [user,req] main command processing function
  5020 +  cmdopt_t      *opts;     // [user,req] options
  6006 +  const cmdopt_t      *opts;     // [user,req] options
  5021 +  cmdarg_t      *args;     // [user,req] arguments
  6007 +  const cmdarg_t      *args;     // [user,req] arguments
  5022 +  cmdopts_t     *cmds;     // [user,req] subcommands
  6008 +  const cmdopts_t     *cmds;     // [user,req] subcommands
  5023 +  gpointer      userdata;  // [user]
  6009 +  gconstpointer       userdata;  // [user]
  5024 +  size_t        valno;     // internal, number of values to allocate
  6010 +  size_t              valno;     // internal, number of values to allocate
  5025 +};
  6011 +};
  5026 +// positional/option argument description
  6012 +// positional/option argument description
  5027 +struct cmdarg_struct {
  6013 +struct cmdarg_struct {
  5028 +  const char           *name;    // [user,req] argument name - errors, help (unused for switches, but must be initialized)
  6014 +  const char           *name;    // [user,req] argument name - errors, help (unused for switches, but must be initialized)
  5029 +  const guint          pos;      // [user,req] value positional number
  6015 +  const size_t         pos;      // [user,req] value positional number
  5030 +  const cmdarg_flags_t flags;    // [user,req] catchall, plain, check, required, subcommand, switch
  6016 +  const cmdarg_flags_t flags;    // [user,req] catchall, plain, check, required, subcommand, switch
  5031 +  const char           *defval;  // [user,req] default value (unused for switches)
  6017 +  const char           *defval;  // [user,req] default value (unused for switches)
  5032 +  const cmdarg_type_t  *type;    // [user,req] type cbs - checker and completor (unused for switches and subcommands)
  6018 +  const cmdarg_type_t  *type;    // [user,req] type cbs - checker and completor (unused for switches and subcommands)
  5033 +  gconstpointer        chkdata;  // [user] instance data for type checker - eg string2enum list (unused for switches and subcommands)
  6019 +  gconstpointer        chkdata;  // [user] instance data for type checker - eg string2enum list (unused for switches and subcommands)
  5034 +  gconstpointer        userdata; // [user]
  6020 +  gconstpointer        userdata; // [user]
  5113 +// Returns 255 if the line is the /quit command, 0 on success and some other
  6099 +// Returns 255 if the line is the /quit command, 0 on success and some other
  5114 +// error codes.
  6100 +// error codes.
  5115 +cmd_result_t process_line(const char *line);
  6101 +cmd_result_t process_line(const char *line);
  5116 +
  6102 +
  5117 +//
  6103 +//
       
  6104 +//  Command checkers
       
  6105 +//
       
  6106 +
       
  6107 +// checks if connection is available
       
  6108 +gchar *cmd_check_online (cmdopts_t *command, cmdarg_value_t *values);
       
  6109 +
       
  6110 +//
  5118 +//  Standard argument types
  6111 +//  Standard argument types
  5119 +//
  6112 +//
  5120 +
  6113 +
  5121  typedef struct {
  6114  typedef struct {
  5122 -  char name[32];
  6115 -  char name[32];
  5219  
  6212  
  5220  #endif /* __MCABBER_COMMANDS_H__ */
  6213  #endif /* __MCABBER_COMMANDS_H__ */
  5221  
  6214  
  5222 diff -r 1b0b563a81e6 mcabber/mcabber/hooks.c
  6215 diff -r 1b0b563a81e6 mcabber/mcabber/hooks.c
  5223 --- a/mcabber/mcabber/hooks.c	Wed Mar 13 16:11:16 2013 +0200
  6216 --- a/mcabber/mcabber/hooks.c	Wed Mar 13 16:11:16 2013 +0200
  5224 +++ b/mcabber/mcabber/hooks.c	Mon Mar 18 02:16:22 2013 +0200
  6217 +++ b/mcabber/mcabber/hooks.c	Fri Mar 22 01:56:17 2013 +0200
  5225 @@ -638,10 +638,9 @@
  6218 @@ -638,10 +638,9 @@
  5226  
  6219  
  5227    scr_LogPrint(LPRINT_LOGNORM, "Running hook-post-connect...");
  6220    scr_LogPrint(LPRINT_LOGNORM, "Running hook-post-connect...");
  5228  
  6221  
  5229 -  cmdline = from_utf8(hook_command);
  6222 -  cmdline = from_utf8(hook_command);
  5248    g_free(cmdline);
  6241    g_free(cmdline);
  5249  }
  6242  }
  5250  
  6243  
  5251 diff -r 1b0b563a81e6 mcabber/mcabber/roster.c
  6244 diff -r 1b0b563a81e6 mcabber/mcabber/roster.c
  5252 --- a/mcabber/mcabber/roster.c	Wed Mar 13 16:11:16 2013 +0200
  6245 --- a/mcabber/mcabber/roster.c	Wed Mar 13 16:11:16 2013 +0200
  5253 +++ b/mcabber/mcabber/roster.c	Mon Mar 18 02:16:22 2013 +0200
  6246 +++ b/mcabber/mcabber/roster.c	Fri Mar 22 01:56:17 2013 +0200
  5254 @@ -1586,13 +1586,14 @@
  6247 @@ -1586,13 +1586,14 @@
  5255  // Look for a buddy whose name or jid contains string.
  6248  // Look for a buddy whose name or jid contains string.
  5256  // Search begins at current_buddy; if no match is found in the the buddylist,
  6249  // Search begins at current_buddy; if no match is found in the the buddylist,
  5257  // return NULL;
  6250  // return NULL;
  5258 +// Note: before this function considered its argument to be in local encoding,
  6251 +// Note: before this function considered its argument to be in local encoding,
  5289        if (found)
  6282        if (found)
  5290          return buddy;
  6283          return buddy;
  5291      }
  6284      }
  5292 diff -r 1b0b563a81e6 mcabber/mcabber/screen.c
  6285 diff -r 1b0b563a81e6 mcabber/mcabber/screen.c
  5293 --- a/mcabber/mcabber/screen.c	Wed Mar 13 16:11:16 2013 +0200
  6286 --- a/mcabber/mcabber/screen.c	Wed Mar 13 16:11:16 2013 +0200
  5294 +++ b/mcabber/mcabber/screen.c	Mon Mar 18 02:16:22 2013 +0200
  6287 +++ b/mcabber/mcabber/screen.c	Fri Mar 22 01:56:17 2013 +0200
  5295 @@ -3630,7 +3630,7 @@
  6288 @@ -3630,7 +3630,7 @@
  5296  {
  6289  {
  5297    scr_check_auto_away(TRUE);
  6290    scr_check_auto_away(TRUE);
  5298    last_activity_buddy = current_buddy;
  6291    last_activity_buddy = current_buddy;
  5299 -  if (process_line(inputLine))
  6292 -  if (process_line(inputLine))
  5359      g_free(cmdline);
  6352      g_free(cmdline);
  5360      return 0;
  6353      return 0;
  5361    }
  6354    }
  5362 diff -r 1b0b563a81e6 mcabber/mcabber/settings.c
  6355 diff -r 1b0b563a81e6 mcabber/mcabber/settings.c
  5363 --- a/mcabber/mcabber/settings.c	Wed Mar 13 16:11:16 2013 +0200
  6356 --- a/mcabber/mcabber/settings.c	Wed Mar 13 16:11:16 2013 +0200
  5364 +++ b/mcabber/mcabber/settings.c	Mon Mar 18 02:16:22 2013 +0200
  6357 +++ b/mcabber/mcabber/settings.c	Fri Mar 22 01:56:17 2013 +0200
  5365 @@ -183,28 +183,12 @@
  6358 @@ -183,28 +183,12 @@
  5366      if ((*line == '\n') || (*line == '\0') || (*line == '#'))
  6359      if ((*line == '\n') || (*line == '\0') || (*line == '#'))
  5367        continue;
  6360        continue;
  5368  
  6361  
  5369 -    // If we aren't in runtime (i.e. startup) we'll only accept "safe" commands
  6362 -    // If we aren't in runtime (i.e. startup) we'll only accept "safe" commands
  5396    }
  6389    }
  5397    g_free(buf);
  6390    g_free(buf);
  5398    fclose(fp);
  6391    fclose(fp);
  5399 diff -r 1b0b563a81e6 mcabber/mcabber/xmpp_iq.c
  6392 diff -r 1b0b563a81e6 mcabber/mcabber/xmpp_iq.c
  5400 --- a/mcabber/mcabber/xmpp_iq.c	Wed Mar 13 16:11:16 2013 +0200
  6393 --- a/mcabber/mcabber/xmpp_iq.c	Wed Mar 13 16:11:16 2013 +0200
  5401 +++ b/mcabber/mcabber/xmpp_iq.c	Mon Mar 18 02:16:22 2013 +0200
  6394 +++ b/mcabber/mcabber/xmpp_iq.c	Fri Mar 22 01:56:17 2013 +0200
  5402 @@ -71,20 +71,20 @@
  6395 @@ -71,20 +71,20 @@
  5403  struct adhoc_status {
  6396  struct adhoc_status {
  5404    char *name;   // the name used by adhoc
  6397    char *name;   // the name used by adhoc
  5405    char *description;
  6398    char *description;
  5406 -  char *status; // the string, used by setstus
  6399 -  char *status; // the string, used by setstus
  5445            lm_message_node_set_attribute(command, "status", "completed");
  6438            lm_message_node_set_attribute(command, "status", "completed");
  5446            lm_message_node_add_dataform_result(command,
  6439            lm_message_node_add_dataform_result(command,
  5447                                                "Status has been changed");
  6440                                                "Status has been changed");
  5448 diff -r 1b0b563a81e6 mcabber/modules/beep/beep.c
  6441 diff -r 1b0b563a81e6 mcabber/modules/beep/beep.c
  5449 --- a/mcabber/modules/beep/beep.c	Wed Mar 13 16:11:16 2013 +0200
  6442 --- a/mcabber/modules/beep/beep.c	Wed Mar 13 16:11:16 2013 +0200
  5450 +++ b/mcabber/modules/beep/beep.c	Mon Mar 18 02:16:22 2013 +0200
  6443 +++ b/mcabber/modules/beep/beep.c	Fri Mar 22 01:56:17 2013 +0200
  5451 @@ -31,6 +31,7 @@
  6444 @@ -31,6 +31,7 @@
  5452  
  6445  
  5453  static void beep_init   (void);
  6446  static void beep_init   (void);
  5454  static void beep_uninit (void);
  6447  static void beep_uninit (void);
  5455 +static gchar *do_beep (cmdopts_t *command, cmdarg_value_t *values);
  6448 +static gchar *do_beep (cmdopts_t *command, cmdarg_value_t *values);