os/ossrv/ofdbus/dbus/bus/signals.c
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
/* -*- mode: C; c-file-style: "gnu" -*- */
sl@0
     2
/* signals.c  Bus signal connection implementation
sl@0
     3
 *
sl@0
     4
 * Copyright (C) 2003, 2005  Red Hat, Inc.
sl@0
     5
 * Portion Copyright © 2008 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
sl@0
     6
 * Licensed under the Academic Free License version 2.1
sl@0
     7
 *
sl@0
     8
 * This program is free software; you can redistribute it and/or modify
sl@0
     9
 * it under the terms of the GNU General Public License as published by
sl@0
    10
 * the Free Software Foundation; either version 2 of the License, or
sl@0
    11
 * (at your option) any later version.
sl@0
    12
 *
sl@0
    13
 * This program is distributed in the hope that it will be useful,
sl@0
    14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
sl@0
    15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
sl@0
    16
 * GNU General Public License for more details.
sl@0
    17
 *
sl@0
    18
 * You should have received a copy of the GNU General Public License
sl@0
    19
 * along with this program; if not, write to the Free Software
sl@0
    20
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
sl@0
    21
 *
sl@0
    22
 */
sl@0
    23
#include "signals.h"
sl@0
    24
#include "services.h"
sl@0
    25
#include "utils.h"
sl@0
    26
#ifndef __SYMBIAN32__
sl@0
    27
#include <dbus/dbus-marshal-validate.h>
sl@0
    28
#else
sl@0
    29
#include "dbus-marshal-validate.h"
sl@0
    30
#include "config.h"
sl@0
    31
#endif //__SYMBIAN32__
sl@0
    32
sl@0
    33
struct BusMatchRule
sl@0
    34
{
sl@0
    35
  int refcount;       /**< reference count */
sl@0
    36
sl@0
    37
  DBusConnection *matches_go_to; /**< Owner of the rule */
sl@0
    38
sl@0
    39
  unsigned int flags; /**< BusMatchFlags */
sl@0
    40
sl@0
    41
  int   message_type;
sl@0
    42
  char *interface;
sl@0
    43
  char *member;
sl@0
    44
  char *sender;
sl@0
    45
  char *destination;
sl@0
    46
  char *path;
sl@0
    47
sl@0
    48
  char **args;
sl@0
    49
  int args_len;
sl@0
    50
};
sl@0
    51
sl@0
    52
BusMatchRule*
sl@0
    53
bus_match_rule_new (DBusConnection *matches_go_to)
sl@0
    54
{
sl@0
    55
  BusMatchRule *rule;
sl@0
    56
sl@0
    57
  rule = dbus_new0 (BusMatchRule, 1);
sl@0
    58
  if (rule == NULL)
sl@0
    59
    return NULL;
sl@0
    60
sl@0
    61
  rule->refcount = 1;
sl@0
    62
  rule->matches_go_to = matches_go_to;
sl@0
    63
sl@0
    64
#ifndef DBUS_BUILD_TESTS
sl@0
    65
  _dbus_assert (rule->matches_go_to != NULL);
sl@0
    66
#endif
sl@0
    67
  
sl@0
    68
  return rule;
sl@0
    69
}
sl@0
    70
sl@0
    71
BusMatchRule *
sl@0
    72
bus_match_rule_ref (BusMatchRule *rule)
sl@0
    73
{
sl@0
    74
  _dbus_assert (rule->refcount > 0);
sl@0
    75
sl@0
    76
  rule->refcount += 1;
sl@0
    77
sl@0
    78
  return rule;
sl@0
    79
}
sl@0
    80
sl@0
    81
void
sl@0
    82
bus_match_rule_unref (BusMatchRule *rule)
sl@0
    83
{
sl@0
    84
  _dbus_assert (rule->refcount > 0);
sl@0
    85
sl@0
    86
  rule->refcount -= 1;
sl@0
    87
  if (rule->refcount == 0)
sl@0
    88
    {
sl@0
    89
      dbus_free (rule->interface);
sl@0
    90
      dbus_free (rule->member);
sl@0
    91
      dbus_free (rule->sender);
sl@0
    92
      dbus_free (rule->destination);
sl@0
    93
      dbus_free (rule->path);
sl@0
    94
sl@0
    95
      /* can't use dbus_free_string_array() since there
sl@0
    96
       * are embedded NULL
sl@0
    97
       */
sl@0
    98
      if (rule->args)
sl@0
    99
        {
sl@0
   100
          int i;
sl@0
   101
sl@0
   102
          i = 0;
sl@0
   103
          while (i < rule->args_len)
sl@0
   104
            {
sl@0
   105
              if (rule->args[i])
sl@0
   106
                dbus_free (rule->args[i]);
sl@0
   107
              ++i;
sl@0
   108
            }
sl@0
   109
sl@0
   110
          dbus_free (rule->args);
sl@0
   111
        }
sl@0
   112
      
sl@0
   113
      dbus_free (rule);
sl@0
   114
    }
sl@0
   115
}
sl@0
   116
sl@0
   117
#ifdef DBUS_ENABLE_VERBOSE_MODE
sl@0
   118
/* Note this function does not do escaping, so it's only
sl@0
   119
 * good for debug spew at the moment
sl@0
   120
 */
sl@0
   121
static char*
sl@0
   122
match_rule_to_string (BusMatchRule *rule)
sl@0
   123
{
sl@0
   124
  DBusString str;
sl@0
   125
  char *ret;
sl@0
   126
  
sl@0
   127
  if (!_dbus_string_init (&str))
sl@0
   128
    {
sl@0
   129
      char *s;
sl@0
   130
      while ((s = _dbus_strdup ("nomem")) == NULL)
sl@0
   131
        ; /* only OK for debug spew... */
sl@0
   132
      return s;
sl@0
   133
    }
sl@0
   134
  
sl@0
   135
  if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
sl@0
   136
    {
sl@0
   137
      /* FIXME make type readable */
sl@0
   138
      if (!_dbus_string_append_printf (&str, "type='%d'", rule->message_type))
sl@0
   139
        goto nomem;
sl@0
   140
    }
sl@0
   141
sl@0
   142
  if (rule->flags & BUS_MATCH_INTERFACE)
sl@0
   143
    {
sl@0
   144
      if (_dbus_string_get_length (&str) > 0)
sl@0
   145
        {
sl@0
   146
          if (!_dbus_string_append (&str, ","))
sl@0
   147
            goto nomem;
sl@0
   148
        }
sl@0
   149
      
sl@0
   150
      if (!_dbus_string_append_printf (&str, "interface='%s'", rule->interface))
sl@0
   151
        goto nomem;
sl@0
   152
    }
sl@0
   153
sl@0
   154
  if (rule->flags & BUS_MATCH_MEMBER)
sl@0
   155
    {
sl@0
   156
      if (_dbus_string_get_length (&str) > 0)
sl@0
   157
        {
sl@0
   158
          if (!_dbus_string_append (&str, ","))
sl@0
   159
            goto nomem;
sl@0
   160
        }
sl@0
   161
      
sl@0
   162
      if (!_dbus_string_append_printf (&str, "member='%s'", rule->member))
sl@0
   163
        goto nomem;
sl@0
   164
    }
sl@0
   165
sl@0
   166
  if (rule->flags & BUS_MATCH_PATH)
sl@0
   167
    {
sl@0
   168
      if (_dbus_string_get_length (&str) > 0)
sl@0
   169
        {
sl@0
   170
          if (!_dbus_string_append (&str, ","))
sl@0
   171
            goto nomem;
sl@0
   172
        }
sl@0
   173
      
sl@0
   174
      if (!_dbus_string_append_printf (&str, "path='%s'", rule->path))
sl@0
   175
        goto nomem;
sl@0
   176
    }
sl@0
   177
sl@0
   178
  if (rule->flags & BUS_MATCH_SENDER)
sl@0
   179
    {
sl@0
   180
      if (_dbus_string_get_length (&str) > 0)
sl@0
   181
        {
sl@0
   182
          if (!_dbus_string_append (&str, ","))
sl@0
   183
            goto nomem;
sl@0
   184
        }
sl@0
   185
      
sl@0
   186
      if (!_dbus_string_append_printf (&str, "sender='%s'", rule->sender))
sl@0
   187
        goto nomem;
sl@0
   188
    }
sl@0
   189
sl@0
   190
  if (rule->flags & BUS_MATCH_DESTINATION)
sl@0
   191
    {
sl@0
   192
      if (_dbus_string_get_length (&str) > 0)
sl@0
   193
        {
sl@0
   194
          if (!_dbus_string_append (&str, ","))
sl@0
   195
            goto nomem;
sl@0
   196
        }
sl@0
   197
      
sl@0
   198
      if (!_dbus_string_append_printf (&str, "destination='%s'", rule->destination))
sl@0
   199
        goto nomem;
sl@0
   200
    }
sl@0
   201
sl@0
   202
  if (rule->flags & BUS_MATCH_ARGS)
sl@0
   203
    {
sl@0
   204
      int i;
sl@0
   205
      
sl@0
   206
      _dbus_assert (rule->args != NULL);
sl@0
   207
sl@0
   208
      i = 0;
sl@0
   209
      while (i < rule->args_len)
sl@0
   210
        {
sl@0
   211
          if (rule->args[i] != NULL)
sl@0
   212
            {
sl@0
   213
              if (_dbus_string_get_length (&str) > 0)
sl@0
   214
                {
sl@0
   215
                  if (!_dbus_string_append (&str, ","))
sl@0
   216
                    goto nomem;
sl@0
   217
                }
sl@0
   218
              
sl@0
   219
              if (!_dbus_string_append_printf (&str,
sl@0
   220
                                               "arg%d='%s'",
sl@0
   221
                                               i,
sl@0
   222
                                               rule->args[i]))
sl@0
   223
                goto nomem;
sl@0
   224
            }
sl@0
   225
          
sl@0
   226
          ++i;
sl@0
   227
        }
sl@0
   228
    }
sl@0
   229
  
sl@0
   230
  if (!_dbus_string_steal_data (&str, &ret))
sl@0
   231
    goto nomem;
sl@0
   232
sl@0
   233
  _dbus_string_free (&str);
sl@0
   234
  return ret;
sl@0
   235
  
sl@0
   236
 nomem:
sl@0
   237
  _dbus_string_free (&str);
sl@0
   238
  {
sl@0
   239
    char *s;
sl@0
   240
    while ((s = _dbus_strdup ("nomem")) == NULL)
sl@0
   241
      ;  /* only OK for debug spew... */
sl@0
   242
    return s;
sl@0
   243
  }
sl@0
   244
}
sl@0
   245
#endif /* DBUS_ENABLE_VERBOSE_MODE */
sl@0
   246
sl@0
   247
dbus_bool_t
sl@0
   248
bus_match_rule_set_message_type (BusMatchRule *rule,
sl@0
   249
                                 int           type)
sl@0
   250
{
sl@0
   251
  rule->flags |= BUS_MATCH_MESSAGE_TYPE;
sl@0
   252
sl@0
   253
  rule->message_type = type;
sl@0
   254
sl@0
   255
  return TRUE;
sl@0
   256
}
sl@0
   257
sl@0
   258
dbus_bool_t
sl@0
   259
bus_match_rule_set_interface (BusMatchRule *rule,
sl@0
   260
                              const char   *interface)
sl@0
   261
{
sl@0
   262
  char *new;
sl@0
   263
sl@0
   264
  _dbus_assert (interface != NULL);
sl@0
   265
sl@0
   266
  new = _dbus_strdup (interface);
sl@0
   267
  if (new == NULL)
sl@0
   268
    return FALSE;
sl@0
   269
sl@0
   270
  rule->flags |= BUS_MATCH_INTERFACE;
sl@0
   271
  dbus_free (rule->interface);
sl@0
   272
  rule->interface = new;
sl@0
   273
sl@0
   274
  return TRUE;
sl@0
   275
}
sl@0
   276
sl@0
   277
dbus_bool_t
sl@0
   278
bus_match_rule_set_member (BusMatchRule *rule,
sl@0
   279
                           const char   *member)
sl@0
   280
{
sl@0
   281
  char *new;
sl@0
   282
sl@0
   283
  _dbus_assert (member != NULL);
sl@0
   284
sl@0
   285
  new = _dbus_strdup (member);
sl@0
   286
  if (new == NULL)
sl@0
   287
    return FALSE;
sl@0
   288
sl@0
   289
  rule->flags |= BUS_MATCH_MEMBER;
sl@0
   290
  dbus_free (rule->member);
sl@0
   291
  rule->member = new;
sl@0
   292
sl@0
   293
  return TRUE;
sl@0
   294
}
sl@0
   295
sl@0
   296
dbus_bool_t
sl@0
   297
bus_match_rule_set_sender (BusMatchRule *rule,
sl@0
   298
                           const char   *sender)
sl@0
   299
{
sl@0
   300
  char *new;
sl@0
   301
sl@0
   302
  _dbus_assert (sender != NULL);
sl@0
   303
sl@0
   304
  new = _dbus_strdup (sender);
sl@0
   305
  if (new == NULL)
sl@0
   306
    return FALSE;
sl@0
   307
sl@0
   308
  rule->flags |= BUS_MATCH_SENDER;
sl@0
   309
  dbus_free (rule->sender);
sl@0
   310
  rule->sender = new;
sl@0
   311
sl@0
   312
  return TRUE;
sl@0
   313
}
sl@0
   314
sl@0
   315
dbus_bool_t
sl@0
   316
bus_match_rule_set_destination (BusMatchRule *rule,
sl@0
   317
                                const char   *destination)
sl@0
   318
{
sl@0
   319
  char *new;
sl@0
   320
sl@0
   321
  _dbus_assert (destination != NULL);
sl@0
   322
sl@0
   323
  new = _dbus_strdup (destination);
sl@0
   324
  if (new == NULL)
sl@0
   325
    return FALSE;
sl@0
   326
sl@0
   327
  rule->flags |= BUS_MATCH_DESTINATION;
sl@0
   328
  dbus_free (rule->destination);
sl@0
   329
  rule->destination = new;
sl@0
   330
sl@0
   331
  return TRUE;
sl@0
   332
}
sl@0
   333
sl@0
   334
dbus_bool_t
sl@0
   335
bus_match_rule_set_path (BusMatchRule *rule,
sl@0
   336
                         const char   *path)
sl@0
   337
{
sl@0
   338
  char *new;
sl@0
   339
sl@0
   340
  _dbus_assert (path != NULL);
sl@0
   341
sl@0
   342
  new = _dbus_strdup (path);
sl@0
   343
  if (new == NULL)
sl@0
   344
    return FALSE;
sl@0
   345
sl@0
   346
  rule->flags |= BUS_MATCH_PATH;
sl@0
   347
  dbus_free (rule->path);
sl@0
   348
  rule->path = new;
sl@0
   349
sl@0
   350
  return TRUE;
sl@0
   351
}
sl@0
   352
sl@0
   353
dbus_bool_t
sl@0
   354
bus_match_rule_set_arg (BusMatchRule *rule,
sl@0
   355
                        int           arg,
sl@0
   356
                        const char   *value)
sl@0
   357
{
sl@0
   358
  char *new;
sl@0
   359
sl@0
   360
  _dbus_assert (value != NULL);
sl@0
   361
sl@0
   362
  new = _dbus_strdup (value);
sl@0
   363
  if (new == NULL)
sl@0
   364
    return FALSE;
sl@0
   365
sl@0
   366
  /* args_len is the number of args not including null termination
sl@0
   367
   * in the char**
sl@0
   368
   */
sl@0
   369
  if (arg >= rule->args_len)
sl@0
   370
    {
sl@0
   371
      char **new_args;
sl@0
   372
      int new_args_len;
sl@0
   373
      int i;
sl@0
   374
sl@0
   375
      new_args_len = arg + 1;
sl@0
   376
sl@0
   377
      /* add another + 1 here for null termination */
sl@0
   378
      new_args = dbus_realloc (rule->args,
sl@0
   379
                               sizeof(rule->args[0]) * (new_args_len + 1));
sl@0
   380
      if (new_args == NULL)
sl@0
   381
        {
sl@0
   382
          dbus_free (new);
sl@0
   383
          return FALSE;
sl@0
   384
        }
sl@0
   385
sl@0
   386
      /* NULL the new slots */
sl@0
   387
      i = rule->args_len;
sl@0
   388
      while (i <= new_args_len) /* <= for null termination */
sl@0
   389
        {
sl@0
   390
          new_args[i] = NULL;
sl@0
   391
          ++i;
sl@0
   392
        }
sl@0
   393
      
sl@0
   394
      rule->args = new_args;
sl@0
   395
      rule->args_len = new_args_len;
sl@0
   396
    }
sl@0
   397
sl@0
   398
  rule->flags |= BUS_MATCH_ARGS;
sl@0
   399
sl@0
   400
  dbus_free (rule->args[arg]);
sl@0
   401
  rule->args[arg] = new;
sl@0
   402
sl@0
   403
  /* NULL termination didn't get busted */
sl@0
   404
  _dbus_assert (rule->args[rule->args_len] == NULL);
sl@0
   405
sl@0
   406
  return TRUE;
sl@0
   407
}
sl@0
   408
sl@0
   409
#define ISWHITE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r'))
sl@0
   410
sl@0
   411
static dbus_bool_t
sl@0
   412
find_key (const DBusString *str,
sl@0
   413
          int               start,
sl@0
   414
          DBusString       *key,
sl@0
   415
          int              *value_pos,
sl@0
   416
          DBusError        *error)
sl@0
   417
{
sl@0
   418
  const char *p;
sl@0
   419
  const char *s;
sl@0
   420
  const char *key_start;
sl@0
   421
  const char *key_end;
sl@0
   422
sl@0
   423
  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
sl@0
   424
  
sl@0
   425
  s = _dbus_string_get_const_data (str);
sl@0
   426
sl@0
   427
  p = s + start;
sl@0
   428
sl@0
   429
  while (*p && ISWHITE (*p))
sl@0
   430
    ++p;
sl@0
   431
sl@0
   432
  key_start = p;
sl@0
   433
sl@0
   434
  while (*p && *p != '=' && !ISWHITE (*p))
sl@0
   435
    ++p;
sl@0
   436
sl@0
   437
  key_end = p;
sl@0
   438
sl@0
   439
  while (*p && ISWHITE (*p))
sl@0
   440
    ++p;
sl@0
   441
  
sl@0
   442
  if (key_start == key_end)
sl@0
   443
    {
sl@0
   444
      /* Empty match rules or trailing whitespace are OK */
sl@0
   445
      *value_pos = p - s;
sl@0
   446
      return TRUE;
sl@0
   447
    }
sl@0
   448
sl@0
   449
  if (*p != '=')
sl@0
   450
    {
sl@0
   451
      dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
sl@0
   452
                      "Match rule has a key with no subsequent '=' character");
sl@0
   453
      return FALSE;
sl@0
   454
    }
sl@0
   455
  ++p;
sl@0
   456
  
sl@0
   457
  if (!_dbus_string_append_len (key, key_start, key_end - key_start))
sl@0
   458
    {
sl@0
   459
      BUS_SET_OOM (error);
sl@0
   460
      return FALSE;
sl@0
   461
    }
sl@0
   462
sl@0
   463
  *value_pos = p - s;
sl@0
   464
  
sl@0
   465
  return TRUE;
sl@0
   466
}
sl@0
   467
sl@0
   468
static dbus_bool_t
sl@0
   469
find_value (const DBusString *str,
sl@0
   470
            int               start,
sl@0
   471
            const char       *key,
sl@0
   472
            DBusString       *value,
sl@0
   473
            int              *value_end,
sl@0
   474
            DBusError        *error)
sl@0
   475
{
sl@0
   476
  const char *p;
sl@0
   477
  const char *s;
sl@0
   478
  char quote_char;
sl@0
   479
  int orig_len;
sl@0
   480
sl@0
   481
  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
sl@0
   482
  
sl@0
   483
  orig_len = _dbus_string_get_length (value);
sl@0
   484
  
sl@0
   485
  s = _dbus_string_get_const_data (str);
sl@0
   486
sl@0
   487
  p = s + start;
sl@0
   488
sl@0
   489
  quote_char = '\0';
sl@0
   490
sl@0
   491
  while (*p)
sl@0
   492
    {
sl@0
   493
      if (quote_char == '\0')
sl@0
   494
        {
sl@0
   495
          switch (*p)
sl@0
   496
            {
sl@0
   497
            case '\0':
sl@0
   498
              goto done;
sl@0
   499
sl@0
   500
            case '\'':
sl@0
   501
              quote_char = '\'';
sl@0
   502
              goto next;
sl@0
   503
              
sl@0
   504
            case ',':
sl@0
   505
              ++p;
sl@0
   506
              goto done;
sl@0
   507
sl@0
   508
            case '\\':
sl@0
   509
              quote_char = '\\';
sl@0
   510
              goto next;
sl@0
   511
              
sl@0
   512
            default:
sl@0
   513
              if (!_dbus_string_append_byte (value, *p))
sl@0
   514
                {
sl@0
   515
                  BUS_SET_OOM (error);
sl@0
   516
                  goto failed;
sl@0
   517
                }
sl@0
   518
            }
sl@0
   519
        }
sl@0
   520
      else if (quote_char == '\\')
sl@0
   521
        {
sl@0
   522
          /* \ only counts as an escape if escaping a quote mark */
sl@0
   523
          if (*p != '\'')
sl@0
   524
            {
sl@0
   525
              if (!_dbus_string_append_byte (value, '\\'))
sl@0
   526
                {
sl@0
   527
                  BUS_SET_OOM (error);
sl@0
   528
                  goto failed;
sl@0
   529
                }
sl@0
   530
            }
sl@0
   531
sl@0
   532
          if (!_dbus_string_append_byte (value, *p))
sl@0
   533
            {
sl@0
   534
              BUS_SET_OOM (error);
sl@0
   535
              goto failed;
sl@0
   536
            }
sl@0
   537
          
sl@0
   538
          quote_char = '\0';
sl@0
   539
        }
sl@0
   540
      else
sl@0
   541
        {
sl@0
   542
          _dbus_assert (quote_char == '\'');
sl@0
   543
sl@0
   544
          if (*p == '\'')
sl@0
   545
            {
sl@0
   546
              quote_char = '\0';
sl@0
   547
            }
sl@0
   548
          else
sl@0
   549
            {
sl@0
   550
              if (!_dbus_string_append_byte (value, *p))
sl@0
   551
                {
sl@0
   552
                  BUS_SET_OOM (error);
sl@0
   553
                  goto failed;
sl@0
   554
                }
sl@0
   555
            }
sl@0
   556
        }
sl@0
   557
sl@0
   558
    next:
sl@0
   559
      ++p;
sl@0
   560
    }
sl@0
   561
sl@0
   562
 done:
sl@0
   563
sl@0
   564
  if (quote_char == '\\')
sl@0
   565
    {
sl@0
   566
      if (!_dbus_string_append_byte (value, '\\'))
sl@0
   567
        {
sl@0
   568
          BUS_SET_OOM (error);
sl@0
   569
          goto failed;
sl@0
   570
        }
sl@0
   571
    }
sl@0
   572
  else if (quote_char == '\'')
sl@0
   573
    {
sl@0
   574
      dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
sl@0
   575
                      "Unbalanced quotation marks in match rule");
sl@0
   576
      goto failed;
sl@0
   577
    }
sl@0
   578
  else
sl@0
   579
    _dbus_assert (quote_char == '\0');
sl@0
   580
sl@0
   581
  /* Zero-length values are allowed */
sl@0
   582
  
sl@0
   583
  *value_end = p - s;
sl@0
   584
  
sl@0
   585
  return TRUE;
sl@0
   586
sl@0
   587
 failed:
sl@0
   588
  _DBUS_ASSERT_ERROR_IS_SET (error);
sl@0
   589
  _dbus_string_set_length (value, orig_len);
sl@0
   590
  return FALSE;
sl@0
   591
}
sl@0
   592
sl@0
   593
/* duplicates aren't allowed so the real legitimate max is only 6 or
sl@0
   594
 * so. Leaving extra so we don't have to bother to update it.
sl@0
   595
 * FIXME this is sort of busted now with arg matching, but we let
sl@0
   596
 * you match on up to 10 args for now
sl@0
   597
 */
sl@0
   598
#define MAX_RULE_TOKENS 16
sl@0
   599
sl@0
   600
/* this is slightly too high level to be termed a "token"
sl@0
   601
 * but let's not be pedantic.
sl@0
   602
 */
sl@0
   603
typedef struct
sl@0
   604
{
sl@0
   605
  char *key;
sl@0
   606
  char *value;
sl@0
   607
} RuleToken;
sl@0
   608
sl@0
   609
static dbus_bool_t
sl@0
   610
tokenize_rule (const DBusString *rule_text,
sl@0
   611
               RuleToken         tokens[MAX_RULE_TOKENS],
sl@0
   612
               DBusError        *error) 
sl@0
   613
{
sl@0
   614
  int i;
sl@0
   615
  int pos;
sl@0
   616
  DBusString key;
sl@0
   617
  DBusString value;
sl@0
   618
  dbus_bool_t retval;
sl@0
   619
sl@0
   620
  retval = FALSE;
sl@0
   621
  
sl@0
   622
  if (!_dbus_string_init (&key))
sl@0
   623
    {
sl@0
   624
      BUS_SET_OOM (error);
sl@0
   625
      return FALSE;
sl@0
   626
    }
sl@0
   627
sl@0
   628
  if (!_dbus_string_init (&value))
sl@0
   629
    {
sl@0
   630
      _dbus_string_free (&key);
sl@0
   631
      BUS_SET_OOM (error);
sl@0
   632
      return FALSE;
sl@0
   633
    }
sl@0
   634
sl@0
   635
  i = 0;
sl@0
   636
  pos = 0;
sl@0
   637
  while (i < MAX_RULE_TOKENS &&
sl@0
   638
         pos < _dbus_string_get_length (rule_text))
sl@0
   639
    {
sl@0
   640
      _dbus_assert (tokens[i].key == NULL);
sl@0
   641
      _dbus_assert (tokens[i].value == NULL);
sl@0
   642
sl@0
   643
      if (!find_key (rule_text, pos, &key, &pos, error))
sl@0
   644
        goto out;
sl@0
   645
sl@0
   646
      if (_dbus_string_get_length (&key) == 0)
sl@0
   647
        goto next;
sl@0
   648
      
sl@0
   649
      if (!_dbus_string_steal_data (&key, &tokens[i].key))
sl@0
   650
        {
sl@0
   651
          BUS_SET_OOM (error);
sl@0
   652
          goto out;
sl@0
   653
        }
sl@0
   654
sl@0
   655
      if (!find_value (rule_text, pos, tokens[i].key, &value, &pos, error))
sl@0
   656
        goto out;
sl@0
   657
sl@0
   658
      if (!_dbus_string_steal_data (&value, &tokens[i].value))
sl@0
   659
        {
sl@0
   660
          BUS_SET_OOM (error);
sl@0
   661
          goto out;
sl@0
   662
        }
sl@0
   663
sl@0
   664
    next:
sl@0
   665
      ++i;
sl@0
   666
    }
sl@0
   667
sl@0
   668
  retval = TRUE;
sl@0
   669
  
sl@0
   670
 out:
sl@0
   671
  if (!retval)
sl@0
   672
    {
sl@0
   673
      i = 0;
sl@0
   674
      while (tokens[i].key || tokens[i].value)
sl@0
   675
        {
sl@0
   676
          dbus_free (tokens[i].key);
sl@0
   677
          dbus_free (tokens[i].value);
sl@0
   678
          tokens[i].key = NULL;
sl@0
   679
          tokens[i].value = NULL;
sl@0
   680
          ++i;
sl@0
   681
        }
sl@0
   682
    }
sl@0
   683
  
sl@0
   684
  _dbus_string_free (&key);
sl@0
   685
  _dbus_string_free (&value);
sl@0
   686
  
sl@0
   687
  return retval;
sl@0
   688
}
sl@0
   689
sl@0
   690
static dbus_bool_t
sl@0
   691
bus_match_rule_parse_arg_match (BusMatchRule     *rule,
sl@0
   692
                                const char       *key,
sl@0
   693
                                const DBusString *value,
sl@0
   694
                                DBusError        *error)
sl@0
   695
{
sl@0
   696
  DBusString key_str;
sl@0
   697
  unsigned long arg;
sl@0
   698
  int end;
sl@0
   699
sl@0
   700
  /* For now, arg0='foo' always implies that 'foo' is a
sl@0
   701
   * DBUS_TYPE_STRING. Someday we could add an arg0type='int32' thing
sl@0
   702
   * if we wanted, which would specify another type, in which case
sl@0
   703
   * arg0='5' would have the 5 parsed as an int rather than string.
sl@0
   704
   */
sl@0
   705
  
sl@0
   706
  /* First we need to parse arg0 = 0, arg27 = 27 */
sl@0
   707
sl@0
   708
  _dbus_string_init_const (&key_str, key);
sl@0
   709
sl@0
   710
  if (_dbus_string_get_length (&key_str) < 4)
sl@0
   711
    {
sl@0
   712
      dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
sl@0
   713
                      "Key '%s' in match rule starts with 'arg' but lacks an arg number. Should be 'arg0' or 'arg7' for example.\n", key);
sl@0
   714
      goto failed;
sl@0
   715
    }
sl@0
   716
sl@0
   717
  if (!_dbus_string_parse_uint (&key_str, 3, &arg, &end) ||
sl@0
   718
      end != _dbus_string_get_length (&key_str))
sl@0
   719
    {
sl@0
   720
      dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
sl@0
   721
                      "Key '%s' in match rule starts with 'arg' but could not parse arg number. Should be 'arg0' or 'arg7' for example.\n", key);
sl@0
   722
      goto failed;
sl@0
   723
    }
sl@0
   724
sl@0
   725
  /* If we didn't check this we could allocate a huge amount of RAM */
sl@0
   726
  if (arg > DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER)
sl@0
   727
    {
sl@0
   728
      dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
sl@0
   729
                      "Key '%s' in match rule has arg number %lu but the maximum is %d.\n", key, (unsigned long) arg, DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER);
sl@0
   730
      goto failed;
sl@0
   731
    }
sl@0
   732
  
sl@0
   733
  if ((rule->flags & BUS_MATCH_ARGS) &&
sl@0
   734
      rule->args_len > (int) arg &&
sl@0
   735
      rule->args[arg] != NULL)
sl@0
   736
    {
sl@0
   737
      dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
sl@0
   738
                      "Key '%s' specified twice in match rule\n", key);
sl@0
   739
      goto failed;
sl@0
   740
    }
sl@0
   741
  
sl@0
   742
  if (!bus_match_rule_set_arg (rule, arg,
sl@0
   743
                               _dbus_string_get_const_data (value)))
sl@0
   744
    {
sl@0
   745
      BUS_SET_OOM (error);
sl@0
   746
      goto failed;
sl@0
   747
    }
sl@0
   748
sl@0
   749
  return TRUE;
sl@0
   750
sl@0
   751
 failed:
sl@0
   752
  _DBUS_ASSERT_ERROR_IS_SET (error);
sl@0
   753
  return FALSE;
sl@0
   754
}
sl@0
   755
sl@0
   756
/*
sl@0
   757
 * The format is comma-separated with strings quoted with single quotes
sl@0
   758
 * as for the shell (to escape a literal single quote, use '\'').
sl@0
   759
 *
sl@0
   760
 * type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='Foo',
sl@0
   761
 * path='/bar/foo',destination=':452345.34'
sl@0
   762
 *
sl@0
   763
 */
sl@0
   764
BusMatchRule*
sl@0
   765
bus_match_rule_parse (DBusConnection   *matches_go_to,
sl@0
   766
                      const DBusString *rule_text,
sl@0
   767
                      DBusError        *error)
sl@0
   768
{
sl@0
   769
  BusMatchRule *rule;
sl@0
   770
  RuleToken tokens[MAX_RULE_TOKENS+1]; /* NULL termination + 1 */
sl@0
   771
  int i;
sl@0
   772
  
sl@0
   773
  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
sl@0
   774
sl@0
   775
  if (_dbus_string_get_length (rule_text) > DBUS_MAXIMUM_MATCH_RULE_LENGTH)
sl@0
   776
    {
sl@0
   777
      dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
sl@0
   778
                      "Match rule text is %d bytes, maximum is %d",
sl@0
   779
                      _dbus_string_get_length (rule_text),
sl@0
   780
                      DBUS_MAXIMUM_MATCH_RULE_LENGTH);
sl@0
   781
      return NULL;
sl@0
   782
    }
sl@0
   783
  
sl@0
   784
  memset (tokens, '\0', sizeof (tokens));
sl@0
   785
  
sl@0
   786
  rule = bus_match_rule_new (matches_go_to);
sl@0
   787
  if (rule == NULL)
sl@0
   788
    {
sl@0
   789
      BUS_SET_OOM (error);
sl@0
   790
      goto failed;
sl@0
   791
    }
sl@0
   792
  
sl@0
   793
  if (!tokenize_rule (rule_text, tokens, error))
sl@0
   794
    goto failed;
sl@0
   795
  
sl@0
   796
  i = 0;
sl@0
   797
  while (tokens[i].key != NULL)
sl@0
   798
    {
sl@0
   799
      DBusString tmp_str;
sl@0
   800
      int len;
sl@0
   801
      const char *key = tokens[i].key;
sl@0
   802
      const char *value = tokens[i].value;
sl@0
   803
      
sl@0
   804
      _dbus_string_init_const (&tmp_str, value);
sl@0
   805
      len = _dbus_string_get_length (&tmp_str);
sl@0
   806
sl@0
   807
      if (strcmp (key, "type") == 0)
sl@0
   808
        {
sl@0
   809
          int t;
sl@0
   810
sl@0
   811
          if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
sl@0
   812
            {
sl@0
   813
              dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
sl@0
   814
                              "Key %s specified twice in match rule\n", key);
sl@0
   815
              goto failed;
sl@0
   816
            }
sl@0
   817
          
sl@0
   818
          t = dbus_message_type_from_string (value);
sl@0
   819
          
sl@0
   820
          if (t == DBUS_MESSAGE_TYPE_INVALID)
sl@0
   821
            {
sl@0
   822
              dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
sl@0
   823
                              "Invalid message type (%s) in match rule\n", value);
sl@0
   824
              goto failed;
sl@0
   825
            }
sl@0
   826
sl@0
   827
          if (!bus_match_rule_set_message_type (rule, t))
sl@0
   828
            {
sl@0
   829
              BUS_SET_OOM (error);
sl@0
   830
              goto failed;
sl@0
   831
            }
sl@0
   832
        }
sl@0
   833
      else if (strcmp (key, "sender") == 0)
sl@0
   834
        {
sl@0
   835
          if (rule->flags & BUS_MATCH_SENDER)
sl@0
   836
            {
sl@0
   837
              dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
sl@0
   838
                              "Key %s specified twice in match rule\n", key);
sl@0
   839
              goto failed;
sl@0
   840
            }
sl@0
   841
sl@0
   842
          if (!_dbus_validate_bus_name (&tmp_str, 0, len))
sl@0
   843
            {
sl@0
   844
              dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
sl@0
   845
                              "Sender name '%s' is invalid\n", value);
sl@0
   846
              goto failed;
sl@0
   847
            }
sl@0
   848
sl@0
   849
          if (!bus_match_rule_set_sender (rule, value))
sl@0
   850
            {
sl@0
   851
              BUS_SET_OOM (error);
sl@0
   852
              goto failed;
sl@0
   853
            }
sl@0
   854
        }
sl@0
   855
      else if (strcmp (key, "interface") == 0)
sl@0
   856
        {
sl@0
   857
          if (rule->flags & BUS_MATCH_INTERFACE)
sl@0
   858
            {
sl@0
   859
              dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
sl@0
   860
                              "Key %s specified twice in match rule\n", key);
sl@0
   861
              goto failed;
sl@0
   862
            }
sl@0
   863
sl@0
   864
          if (!_dbus_validate_interface (&tmp_str, 0, len))
sl@0
   865
            {
sl@0
   866
              dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
sl@0
   867
                              "Interface name '%s' is invalid\n", value);
sl@0
   868
              goto failed;
sl@0
   869
            }
sl@0
   870
sl@0
   871
          if (!bus_match_rule_set_interface (rule, value))
sl@0
   872
            {
sl@0
   873
              BUS_SET_OOM (error);
sl@0
   874
              goto failed;
sl@0
   875
            }
sl@0
   876
        }
sl@0
   877
      else if (strcmp (key, "member") == 0)
sl@0
   878
        {
sl@0
   879
          if (rule->flags & BUS_MATCH_MEMBER)
sl@0
   880
            {
sl@0
   881
              dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
sl@0
   882
                              "Key %s specified twice in match rule\n", key);
sl@0
   883
              goto failed;
sl@0
   884
            }
sl@0
   885
sl@0
   886
          if (!_dbus_validate_member (&tmp_str, 0, len))
sl@0
   887
            {
sl@0
   888
              dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
sl@0
   889
                              "Member name '%s' is invalid\n", value);
sl@0
   890
              goto failed;
sl@0
   891
            }
sl@0
   892
sl@0
   893
          if (!bus_match_rule_set_member (rule, value))
sl@0
   894
            {
sl@0
   895
              BUS_SET_OOM (error);
sl@0
   896
              goto failed;
sl@0
   897
            }
sl@0
   898
        }
sl@0
   899
      else if (strcmp (key, "path") == 0)
sl@0
   900
        {
sl@0
   901
          if (rule->flags & BUS_MATCH_PATH)
sl@0
   902
            {
sl@0
   903
              dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
sl@0
   904
                              "Key %s specified twice in match rule\n", key);
sl@0
   905
              goto failed;
sl@0
   906
            }
sl@0
   907
sl@0
   908
          if (!_dbus_validate_path (&tmp_str, 0, len))
sl@0
   909
            {
sl@0
   910
              dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
sl@0
   911
                              "Path '%s' is invalid\n", value);
sl@0
   912
              goto failed;
sl@0
   913
            }
sl@0
   914
sl@0
   915
          if (!bus_match_rule_set_path (rule, value))
sl@0
   916
            {
sl@0
   917
              BUS_SET_OOM (error);
sl@0
   918
              goto failed;
sl@0
   919
            }
sl@0
   920
        }
sl@0
   921
      else if (strcmp (key, "destination") == 0)
sl@0
   922
        {
sl@0
   923
          if (rule->flags & BUS_MATCH_DESTINATION)
sl@0
   924
            {
sl@0
   925
              dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
sl@0
   926
                              "Key %s specified twice in match rule\n", key);
sl@0
   927
              goto failed;
sl@0
   928
            }
sl@0
   929
sl@0
   930
          if (!_dbus_validate_bus_name (&tmp_str, 0, len))
sl@0
   931
            {
sl@0
   932
              dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
sl@0
   933
                              "Destination name '%s' is invalid\n", value);
sl@0
   934
              goto failed;
sl@0
   935
            }
sl@0
   936
sl@0
   937
          if (!bus_match_rule_set_destination (rule, value))
sl@0
   938
            {
sl@0
   939
              BUS_SET_OOM (error);
sl@0
   940
              goto failed;
sl@0
   941
            }
sl@0
   942
        }
sl@0
   943
      else if (strncmp (key, "arg", 3) == 0)
sl@0
   944
        {
sl@0
   945
          if (!bus_match_rule_parse_arg_match (rule, key, &tmp_str, error))
sl@0
   946
            goto failed;
sl@0
   947
        }
sl@0
   948
      else
sl@0
   949
        {
sl@0
   950
          dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
sl@0
   951
                          "Unknown key \"%s\" in match rule",
sl@0
   952
                          key);
sl@0
   953
          goto failed;
sl@0
   954
        }
sl@0
   955
sl@0
   956
      ++i;
sl@0
   957
    }
sl@0
   958
  
sl@0
   959
sl@0
   960
  goto out;
sl@0
   961
  
sl@0
   962
 failed:
sl@0
   963
  _DBUS_ASSERT_ERROR_IS_SET (error);
sl@0
   964
  if (rule)
sl@0
   965
    {
sl@0
   966
      bus_match_rule_unref (rule);
sl@0
   967
      rule = NULL;
sl@0
   968
    }
sl@0
   969
sl@0
   970
 out:
sl@0
   971
  
sl@0
   972
  i = 0;
sl@0
   973
  while (tokens[i].key || tokens[i].value)
sl@0
   974
    {
sl@0
   975
      _dbus_assert (i < MAX_RULE_TOKENS);
sl@0
   976
      dbus_free (tokens[i].key);
sl@0
   977
      dbus_free (tokens[i].value);
sl@0
   978
      ++i;
sl@0
   979
    }
sl@0
   980
  
sl@0
   981
  return rule;
sl@0
   982
}
sl@0
   983
sl@0
   984
struct BusMatchmaker
sl@0
   985
{
sl@0
   986
  int refcount;
sl@0
   987
sl@0
   988
  DBusList *all_rules;
sl@0
   989
};
sl@0
   990
sl@0
   991
BusMatchmaker*
sl@0
   992
bus_matchmaker_new (void)
sl@0
   993
{
sl@0
   994
  BusMatchmaker *matchmaker;
sl@0
   995
sl@0
   996
  matchmaker = dbus_new0 (BusMatchmaker, 1);
sl@0
   997
  if (matchmaker == NULL)
sl@0
   998
    return NULL;
sl@0
   999
sl@0
  1000
  matchmaker->refcount = 1;
sl@0
  1001
  
sl@0
  1002
  return matchmaker;
sl@0
  1003
}
sl@0
  1004
sl@0
  1005
BusMatchmaker *
sl@0
  1006
bus_matchmaker_ref (BusMatchmaker *matchmaker)
sl@0
  1007
{
sl@0
  1008
  _dbus_assert (matchmaker->refcount > 0);
sl@0
  1009
sl@0
  1010
  matchmaker->refcount += 1;
sl@0
  1011
sl@0
  1012
  return matchmaker;
sl@0
  1013
}
sl@0
  1014
sl@0
  1015
void
sl@0
  1016
bus_matchmaker_unref (BusMatchmaker *matchmaker)
sl@0
  1017
{
sl@0
  1018
  _dbus_assert (matchmaker->refcount > 0);
sl@0
  1019
sl@0
  1020
  matchmaker->refcount -= 1;
sl@0
  1021
  if (matchmaker->refcount == 0)
sl@0
  1022
    {
sl@0
  1023
      while (matchmaker->all_rules != NULL)
sl@0
  1024
        {
sl@0
  1025
          BusMatchRule *rule;
sl@0
  1026
sl@0
  1027
          rule = matchmaker->all_rules->data;
sl@0
  1028
          bus_match_rule_unref (rule);
sl@0
  1029
          _dbus_list_remove_link (&matchmaker->all_rules,
sl@0
  1030
                                  matchmaker->all_rules);
sl@0
  1031
        }
sl@0
  1032
sl@0
  1033
      dbus_free (matchmaker);
sl@0
  1034
    }
sl@0
  1035
}
sl@0
  1036
sl@0
  1037
/* The rule can't be modified after it's added. */
sl@0
  1038
dbus_bool_t
sl@0
  1039
bus_matchmaker_add_rule (BusMatchmaker   *matchmaker,
sl@0
  1040
                         BusMatchRule    *rule)
sl@0
  1041
{
sl@0
  1042
  _dbus_assert (bus_connection_is_active (rule->matches_go_to));
sl@0
  1043
sl@0
  1044
  if (!_dbus_list_append (&matchmaker->all_rules, rule))
sl@0
  1045
    return FALSE;
sl@0
  1046
sl@0
  1047
  if (!bus_connection_add_match_rule (rule->matches_go_to, rule))
sl@0
  1048
    {
sl@0
  1049
      _dbus_list_remove_last (&matchmaker->all_rules, rule);
sl@0
  1050
      return FALSE;
sl@0
  1051
    }
sl@0
  1052
  
sl@0
  1053
  bus_match_rule_ref (rule);
sl@0
  1054
sl@0
  1055
#ifdef DBUS_ENABLE_VERBOSE_MODE
sl@0
  1056
  {
sl@0
  1057
    char *s = match_rule_to_string (rule);
sl@0
  1058
sl@0
  1059
    _dbus_verbose ("Added match rule %s to connection %p\n",
sl@0
  1060
                   s, rule->matches_go_to);
sl@0
  1061
    dbus_free (s);
sl@0
  1062
  }
sl@0
  1063
#endif
sl@0
  1064
  
sl@0
  1065
  return TRUE;
sl@0
  1066
}
sl@0
  1067
sl@0
  1068
static dbus_bool_t
sl@0
  1069
match_rule_equal (BusMatchRule *a,
sl@0
  1070
                  BusMatchRule *b)
sl@0
  1071
{
sl@0
  1072
  if (a->flags != b->flags)
sl@0
  1073
    return FALSE;
sl@0
  1074
sl@0
  1075
  if (a->matches_go_to != b->matches_go_to)
sl@0
  1076
    return FALSE;
sl@0
  1077
sl@0
  1078
  if ((a->flags & BUS_MATCH_MESSAGE_TYPE) &&
sl@0
  1079
      a->message_type != b->message_type)
sl@0
  1080
    return FALSE;
sl@0
  1081
sl@0
  1082
  if ((a->flags & BUS_MATCH_MEMBER) &&
sl@0
  1083
      strcmp (a->member, b->member) != 0)
sl@0
  1084
    return FALSE;
sl@0
  1085
sl@0
  1086
  if ((a->flags & BUS_MATCH_PATH) &&
sl@0
  1087
      strcmp (a->path, b->path) != 0)
sl@0
  1088
    return FALSE;
sl@0
  1089
  
sl@0
  1090
  if ((a->flags & BUS_MATCH_INTERFACE) &&
sl@0
  1091
      strcmp (a->interface, b->interface) != 0)
sl@0
  1092
    return FALSE;
sl@0
  1093
sl@0
  1094
  if ((a->flags & BUS_MATCH_SENDER) &&
sl@0
  1095
      strcmp (a->sender, b->sender) != 0)
sl@0
  1096
    return FALSE;
sl@0
  1097
sl@0
  1098
  if ((a->flags & BUS_MATCH_DESTINATION) &&
sl@0
  1099
      strcmp (a->destination, b->destination) != 0)
sl@0
  1100
    return FALSE;
sl@0
  1101
sl@0
  1102
  if (a->flags & BUS_MATCH_ARGS)
sl@0
  1103
    {
sl@0
  1104
      int i;
sl@0
  1105
      
sl@0
  1106
      if (a->args_len != b->args_len)
sl@0
  1107
        return FALSE;
sl@0
  1108
      
sl@0
  1109
      i = 0;
sl@0
  1110
      while (i < a->args_len)
sl@0
  1111
        {
sl@0
  1112
          if ((a->args[i] != NULL) != (b->args[i] != NULL))
sl@0
  1113
            return FALSE;
sl@0
  1114
sl@0
  1115
          if (a->args[i] != NULL)
sl@0
  1116
            {
sl@0
  1117
              _dbus_assert (b->args[i] != NULL);
sl@0
  1118
              if (strcmp (a->args[i], b->args[i]) != 0)
sl@0
  1119
                return FALSE;
sl@0
  1120
            }
sl@0
  1121
          
sl@0
  1122
          ++i;
sl@0
  1123
        }
sl@0
  1124
    }
sl@0
  1125
  
sl@0
  1126
  return TRUE;
sl@0
  1127
}
sl@0
  1128
sl@0
  1129
static void
sl@0
  1130
bus_matchmaker_remove_rule_link (BusMatchmaker   *matchmaker,
sl@0
  1131
                                 DBusList        *link)
sl@0
  1132
{
sl@0
  1133
  BusMatchRule *rule = link->data;
sl@0
  1134
  
sl@0
  1135
  bus_connection_remove_match_rule (rule->matches_go_to, rule);
sl@0
  1136
  _dbus_list_remove_link (&matchmaker->all_rules, link);
sl@0
  1137
sl@0
  1138
#ifdef DBUS_ENABLE_VERBOSE_MODE
sl@0
  1139
  {
sl@0
  1140
    char *s = match_rule_to_string (rule);
sl@0
  1141
sl@0
  1142
    _dbus_verbose ("Removed match rule %s for connection %p\n",
sl@0
  1143
                   s, rule->matches_go_to);
sl@0
  1144
    dbus_free (s);
sl@0
  1145
  }
sl@0
  1146
#endif
sl@0
  1147
  
sl@0
  1148
  bus_match_rule_unref (rule);  
sl@0
  1149
}
sl@0
  1150
sl@0
  1151
void
sl@0
  1152
bus_matchmaker_remove_rule (BusMatchmaker   *matchmaker,
sl@0
  1153
                            BusMatchRule    *rule)
sl@0
  1154
{
sl@0
  1155
  bus_connection_remove_match_rule (rule->matches_go_to, rule);
sl@0
  1156
  _dbus_list_remove (&matchmaker->all_rules, rule);
sl@0
  1157
sl@0
  1158
#ifdef DBUS_ENABLE_VERBOSE_MODE
sl@0
  1159
  {
sl@0
  1160
    char *s = match_rule_to_string (rule);
sl@0
  1161
sl@0
  1162
    _dbus_verbose ("Removed match rule %s for connection %p\n",
sl@0
  1163
                   s, rule->matches_go_to);
sl@0
  1164
    dbus_free (s);
sl@0
  1165
  }
sl@0
  1166
#endif
sl@0
  1167
  
sl@0
  1168
  bus_match_rule_unref (rule);
sl@0
  1169
}
sl@0
  1170
sl@0
  1171
/* Remove a single rule which is equal to the given rule by value */
sl@0
  1172
dbus_bool_t
sl@0
  1173
bus_matchmaker_remove_rule_by_value (BusMatchmaker   *matchmaker,
sl@0
  1174
                                     BusMatchRule    *value,
sl@0
  1175
                                     DBusError       *error)
sl@0
  1176
{
sl@0
  1177
  /* FIXME this is an unoptimized linear scan */
sl@0
  1178
sl@0
  1179
  DBusList *link;
sl@0
  1180
sl@0
  1181
  /* we traverse backward because bus_connection_remove_match_rule()
sl@0
  1182
   * removes the most-recently-added rule
sl@0
  1183
   */
sl@0
  1184
  link = _dbus_list_get_last_link (&matchmaker->all_rules);
sl@0
  1185
  while (link != NULL)
sl@0
  1186
    {
sl@0
  1187
      BusMatchRule *rule;
sl@0
  1188
      DBusList *prev;
sl@0
  1189
sl@0
  1190
      rule = link->data;
sl@0
  1191
      prev = _dbus_list_get_prev_link (&matchmaker->all_rules, link);
sl@0
  1192
sl@0
  1193
      if (match_rule_equal (rule, value))
sl@0
  1194
        {
sl@0
  1195
          bus_matchmaker_remove_rule_link (matchmaker, link);
sl@0
  1196
          break;
sl@0
  1197
        }
sl@0
  1198
sl@0
  1199
      link = prev;
sl@0
  1200
    }
sl@0
  1201
sl@0
  1202
  if (link == NULL)
sl@0
  1203
    {
sl@0
  1204
      dbus_set_error (error, DBUS_ERROR_MATCH_RULE_NOT_FOUND,
sl@0
  1205
                      "The given match rule wasn't found and can't be removed");
sl@0
  1206
      return FALSE;
sl@0
  1207
    }
sl@0
  1208
sl@0
  1209
  return TRUE;
sl@0
  1210
}
sl@0
  1211
sl@0
  1212
void
sl@0
  1213
bus_matchmaker_disconnected (BusMatchmaker   *matchmaker,
sl@0
  1214
                             DBusConnection  *disconnected)
sl@0
  1215
{
sl@0
  1216
  DBusList *link;
sl@0
  1217
sl@0
  1218
  /* FIXME
sl@0
  1219
   *
sl@0
  1220
   * This scans all match rules on the bus. We could avoid that
sl@0
  1221
   * for the rules belonging to the connection, since we keep
sl@0
  1222
   * a list of those; but for the rules that just refer to
sl@0
  1223
   * the connection we'd need to do something more elaborate.
sl@0
  1224
   * 
sl@0
  1225
   */
sl@0
  1226
  
sl@0
  1227
  _dbus_assert (bus_connection_is_active (disconnected));
sl@0
  1228
sl@0
  1229
  link = _dbus_list_get_first_link (&matchmaker->all_rules);
sl@0
  1230
  while (link != NULL)
sl@0
  1231
    {
sl@0
  1232
      BusMatchRule *rule;
sl@0
  1233
      DBusList *next;
sl@0
  1234
sl@0
  1235
      rule = link->data;
sl@0
  1236
      next = _dbus_list_get_next_link (&matchmaker->all_rules, link);
sl@0
  1237
sl@0
  1238
      if (rule->matches_go_to == disconnected)
sl@0
  1239
        {
sl@0
  1240
          bus_matchmaker_remove_rule_link (matchmaker, link);
sl@0
  1241
        }
sl@0
  1242
      else if (((rule->flags & BUS_MATCH_SENDER) && *rule->sender == ':') ||
sl@0
  1243
               ((rule->flags & BUS_MATCH_DESTINATION) && *rule->destination == ':'))
sl@0
  1244
        {
sl@0
  1245
          /* The rule matches to/from a base service, see if it's the
sl@0
  1246
           * one being disconnected, since we know this service name
sl@0
  1247
           * will never be recycled.
sl@0
  1248
           */
sl@0
  1249
          const char *name;
sl@0
  1250
sl@0
  1251
          name = bus_connection_get_name (disconnected);
sl@0
  1252
          _dbus_assert (name != NULL); /* because we're an active connection */
sl@0
  1253
sl@0
  1254
          if (((rule->flags & BUS_MATCH_SENDER) &&
sl@0
  1255
               strcmp (rule->sender, name) == 0) ||
sl@0
  1256
              ((rule->flags & BUS_MATCH_DESTINATION) &&
sl@0
  1257
               strcmp (rule->destination, name) == 0))
sl@0
  1258
            {
sl@0
  1259
              bus_matchmaker_remove_rule_link (matchmaker, link);
sl@0
  1260
            }
sl@0
  1261
        }
sl@0
  1262
sl@0
  1263
      link = next;
sl@0
  1264
    }
sl@0
  1265
}
sl@0
  1266
sl@0
  1267
static dbus_bool_t
sl@0
  1268
connection_is_primary_owner (DBusConnection *connection,
sl@0
  1269
                             const char     *service_name)
sl@0
  1270
{
sl@0
  1271
  BusService *service;
sl@0
  1272
  DBusString str;
sl@0
  1273
  BusRegistry *registry;
sl@0
  1274
sl@0
  1275
  _dbus_assert (connection != NULL);
sl@0
  1276
  
sl@0
  1277
  registry = bus_connection_get_registry (connection);
sl@0
  1278
sl@0
  1279
  _dbus_string_init_const (&str, service_name);
sl@0
  1280
  service = bus_registry_lookup (registry, &str);
sl@0
  1281
sl@0
  1282
  if (service == NULL)
sl@0
  1283
    return FALSE; /* Service doesn't exist so connection can't own it. */
sl@0
  1284
sl@0
  1285
  return bus_service_get_primary_owners_connection (service) == connection;
sl@0
  1286
}
sl@0
  1287
sl@0
  1288
static dbus_bool_t
sl@0
  1289
match_rule_matches (BusMatchRule    *rule,
sl@0
  1290
                    DBusConnection  *sender,
sl@0
  1291
                    DBusConnection  *addressed_recipient,
sl@0
  1292
                    DBusMessage     *message)
sl@0
  1293
{
sl@0
  1294
  /* All features of the match rule are AND'd together,
sl@0
  1295
   * so FALSE if any of them don't match.
sl@0
  1296
   */
sl@0
  1297
sl@0
  1298
  /* sender/addressed_recipient of #NULL may mean bus driver,
sl@0
  1299
   * or for addressed_recipient may mean a message with no
sl@0
  1300
   * specific recipient (i.e. a signal)
sl@0
  1301
   */
sl@0
  1302
  
sl@0
  1303
  if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
sl@0
  1304
    {
sl@0
  1305
      _dbus_assert (rule->message_type != DBUS_MESSAGE_TYPE_INVALID);
sl@0
  1306
sl@0
  1307
      if (rule->message_type != dbus_message_get_type (message))
sl@0
  1308
        return FALSE;
sl@0
  1309
    }
sl@0
  1310
sl@0
  1311
  if (rule->flags & BUS_MATCH_INTERFACE)
sl@0
  1312
    {
sl@0
  1313
      const char *iface;
sl@0
  1314
sl@0
  1315
      _dbus_assert (rule->interface != NULL);
sl@0
  1316
sl@0
  1317
      iface = dbus_message_get_interface (message);
sl@0
  1318
      if (iface == NULL)
sl@0
  1319
        return FALSE;
sl@0
  1320
sl@0
  1321
      if (strcmp (iface, rule->interface) != 0)
sl@0
  1322
        return FALSE;
sl@0
  1323
    }
sl@0
  1324
sl@0
  1325
  if (rule->flags & BUS_MATCH_MEMBER)
sl@0
  1326
    {
sl@0
  1327
      const char *member;
sl@0
  1328
sl@0
  1329
      _dbus_assert (rule->member != NULL);
sl@0
  1330
sl@0
  1331
      member = dbus_message_get_member (message);
sl@0
  1332
      if (member == NULL)
sl@0
  1333
        return FALSE;
sl@0
  1334
sl@0
  1335
      if (strcmp (member, rule->member) != 0)
sl@0
  1336
        return FALSE;
sl@0
  1337
    }
sl@0
  1338
sl@0
  1339
  if (rule->flags & BUS_MATCH_SENDER)
sl@0
  1340
    {
sl@0
  1341
      _dbus_assert (rule->sender != NULL);
sl@0
  1342
sl@0
  1343
      if (sender == NULL)
sl@0
  1344
        {
sl@0
  1345
          if (strcmp (rule->sender,
sl@0
  1346
                      DBUS_SERVICE_DBUS) != 0)
sl@0
  1347
            return FALSE;
sl@0
  1348
        }
sl@0
  1349
      else
sl@0
  1350
        {
sl@0
  1351
          if (!connection_is_primary_owner (sender, rule->sender))
sl@0
  1352
            return FALSE;
sl@0
  1353
        }
sl@0
  1354
    }
sl@0
  1355
sl@0
  1356
  if (rule->flags & BUS_MATCH_DESTINATION)
sl@0
  1357
    {
sl@0
  1358
      const char *destination;
sl@0
  1359
sl@0
  1360
      _dbus_assert (rule->destination != NULL);
sl@0
  1361
sl@0
  1362
      destination = dbus_message_get_destination (message);
sl@0
  1363
      if (destination == NULL)
sl@0
  1364
        return FALSE;
sl@0
  1365
sl@0
  1366
      if (addressed_recipient == NULL)
sl@0
  1367
        {          
sl@0
  1368
          if (strcmp (rule->destination,
sl@0
  1369
                      DBUS_SERVICE_DBUS) != 0)
sl@0
  1370
            return FALSE;
sl@0
  1371
        }
sl@0
  1372
      else
sl@0
  1373
        {
sl@0
  1374
          if (!connection_is_primary_owner (addressed_recipient, rule->destination))
sl@0
  1375
            return FALSE;
sl@0
  1376
        }
sl@0
  1377
    }
sl@0
  1378
sl@0
  1379
  if (rule->flags & BUS_MATCH_PATH)
sl@0
  1380
    {
sl@0
  1381
      const char *path;
sl@0
  1382
sl@0
  1383
      _dbus_assert (rule->path != NULL);
sl@0
  1384
sl@0
  1385
      path = dbus_message_get_path (message);
sl@0
  1386
      if (path == NULL)
sl@0
  1387
        return FALSE;
sl@0
  1388
sl@0
  1389
      if (strcmp (path, rule->path) != 0)
sl@0
  1390
        return FALSE;
sl@0
  1391
    }
sl@0
  1392
sl@0
  1393
  if (rule->flags & BUS_MATCH_ARGS)
sl@0
  1394
    {
sl@0
  1395
      int i;
sl@0
  1396
      DBusMessageIter iter;
sl@0
  1397
      
sl@0
  1398
      _dbus_assert (rule->args != NULL);
sl@0
  1399
sl@0
  1400
      dbus_message_iter_init (message, &iter);
sl@0
  1401
      
sl@0
  1402
      i = 0;
sl@0
  1403
      while (i < rule->args_len)
sl@0
  1404
        {
sl@0
  1405
          int current_type;
sl@0
  1406
          const char *expected_arg;
sl@0
  1407
sl@0
  1408
          expected_arg = rule->args[i];
sl@0
  1409
          
sl@0
  1410
          current_type = dbus_message_iter_get_arg_type (&iter);
sl@0
  1411
sl@0
  1412
          if (expected_arg != NULL)
sl@0
  1413
            {
sl@0
  1414
              const char *actual_arg;
sl@0
  1415
              
sl@0
  1416
              if (current_type != DBUS_TYPE_STRING)
sl@0
  1417
                return FALSE;
sl@0
  1418
sl@0
  1419
              actual_arg = NULL;
sl@0
  1420
              dbus_message_iter_get_basic (&iter, &actual_arg);
sl@0
  1421
              _dbus_assert (actual_arg != NULL);
sl@0
  1422
sl@0
  1423
              if (strcmp (expected_arg, actual_arg) != 0)
sl@0
  1424
                return FALSE;
sl@0
  1425
            }
sl@0
  1426
          
sl@0
  1427
          if (current_type != DBUS_TYPE_INVALID)
sl@0
  1428
            dbus_message_iter_next (&iter);
sl@0
  1429
sl@0
  1430
          ++i;
sl@0
  1431
        }
sl@0
  1432
    }
sl@0
  1433
  
sl@0
  1434
  return TRUE;
sl@0
  1435
}
sl@0
  1436
sl@0
  1437
dbus_bool_t
sl@0
  1438
bus_matchmaker_get_recipients (BusMatchmaker   *matchmaker,
sl@0
  1439
                               BusConnections  *connections,
sl@0
  1440
                               DBusConnection  *sender,
sl@0
  1441
                               DBusConnection  *addressed_recipient,
sl@0
  1442
                               DBusMessage     *message,
sl@0
  1443
                               DBusList       **recipients_p)
sl@0
  1444
{
sl@0
  1445
  /* FIXME for now this is a wholly unoptimized linear search */
sl@0
  1446
  /* Guessing the important optimization is to skip the signal-related
sl@0
  1447
   * match lists when processing method call and exception messages.
sl@0
  1448
   * So separate match rule lists for signals?
sl@0
  1449
   */
sl@0
  1450
  
sl@0
  1451
  DBusList *link;
sl@0
  1452
sl@0
  1453
  _dbus_assert (*recipients_p == NULL);
sl@0
  1454
sl@0
  1455
  /* This avoids sending same message to the same connection twice.
sl@0
  1456
   * Purpose of the stamp instead of a bool is to avoid iterating over
sl@0
  1457
   * all connections resetting the bool each time.
sl@0
  1458
   */
sl@0
  1459
  bus_connections_increment_stamp (connections);
sl@0
  1460
sl@0
  1461
  /* addressed_recipient is already receiving the message, don't add to list.
sl@0
  1462
   * NULL addressed_recipient means either bus driver, or this is a signal
sl@0
  1463
   * and thus lacks a specific addressed_recipient.
sl@0
  1464
   */
sl@0
  1465
  if (addressed_recipient != NULL)
sl@0
  1466
    bus_connection_mark_stamp (addressed_recipient);
sl@0
  1467
sl@0
  1468
  link = _dbus_list_get_first_link (&matchmaker->all_rules);
sl@0
  1469
  while (link != NULL)
sl@0
  1470
    {
sl@0
  1471
      BusMatchRule *rule;
sl@0
  1472
sl@0
  1473
      rule = link->data;
sl@0
  1474
sl@0
  1475
#ifdef DBUS_ENABLE_VERBOSE_MODE
sl@0
  1476
      {
sl@0
  1477
        char *s = match_rule_to_string (rule);
sl@0
  1478
        
sl@0
  1479
        _dbus_verbose ("Checking whether message matches rule %s for connection %p\n",
sl@0
  1480
                       s, rule->matches_go_to);
sl@0
  1481
        dbus_free (s);
sl@0
  1482
      }
sl@0
  1483
#endif
sl@0
  1484
      
sl@0
  1485
      if (match_rule_matches (rule,
sl@0
  1486
                              sender, addressed_recipient, message))
sl@0
  1487
        {
sl@0
  1488
          _dbus_verbose ("Rule matched\n");
sl@0
  1489
          
sl@0
  1490
          /* Append to the list if we haven't already */
sl@0
  1491
          if (bus_connection_mark_stamp (rule->matches_go_to))
sl@0
  1492
            {
sl@0
  1493
              if (!_dbus_list_append (recipients_p, rule->matches_go_to))
sl@0
  1494
                goto nomem;
sl@0
  1495
            }
sl@0
  1496
#ifdef DBUS_ENABLE_VERBOSE_MODE
sl@0
  1497
          else
sl@0
  1498
            {
sl@0
  1499
              _dbus_verbose ("Connection already receiving this message, so not adding again\n");
sl@0
  1500
            }
sl@0
  1501
#endif /* DBUS_ENABLE_VERBOSE_MODE */
sl@0
  1502
        }
sl@0
  1503
sl@0
  1504
      link = _dbus_list_get_next_link (&matchmaker->all_rules, link);
sl@0
  1505
    }
sl@0
  1506
sl@0
  1507
  return TRUE;
sl@0
  1508
sl@0
  1509
 nomem:
sl@0
  1510
  _dbus_list_clear (recipients_p);
sl@0
  1511
  return FALSE;
sl@0
  1512
}
sl@0
  1513
sl@0
  1514
#ifdef DBUS_BUILD_TESTS
sl@0
  1515
#include "test.h"
sl@0
  1516
#include <stdlib.h>
sl@0
  1517
sl@0
  1518
static BusMatchRule*
sl@0
  1519
check_parse (dbus_bool_t should_succeed,
sl@0
  1520
             const char *text)
sl@0
  1521
{
sl@0
  1522
  BusMatchRule *rule;
sl@0
  1523
  DBusString str;
sl@0
  1524
  DBusError error;
sl@0
  1525
sl@0
  1526
  dbus_error_init (&error);
sl@0
  1527
sl@0
  1528
  _dbus_string_init_const (&str, text);
sl@0
  1529
  
sl@0
  1530
  rule = bus_match_rule_parse (NULL, &str, &error);
sl@0
  1531
  if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
sl@0
  1532
    {
sl@0
  1533
      dbus_error_free (&error);
sl@0
  1534
      return NULL;
sl@0
  1535
    }
sl@0
  1536
sl@0
  1537
  if (should_succeed && rule == NULL)
sl@0
  1538
    {
sl@0
  1539
      _dbus_warn ("Failed to parse: %s: %s: \"%s\"\n",
sl@0
  1540
                  error.name, error.message,
sl@0
  1541
                  _dbus_string_get_const_data (&str));
sl@0
  1542
      exit (1);
sl@0
  1543
    }
sl@0
  1544
sl@0
  1545
  if (!should_succeed && rule != NULL)
sl@0
  1546
    {
sl@0
  1547
      _dbus_warn ("Failed to fail to parse: \"%s\"\n",
sl@0
  1548
                  _dbus_string_get_const_data (&str));
sl@0
  1549
      exit (1);
sl@0
  1550
    }
sl@0
  1551
sl@0
  1552
  dbus_error_free (&error);
sl@0
  1553
sl@0
  1554
  return rule;
sl@0
  1555
}
sl@0
  1556
sl@0
  1557
static void
sl@0
  1558
assert_large_rule (BusMatchRule *rule)
sl@0
  1559
{
sl@0
  1560
  _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
sl@0
  1561
  _dbus_assert (rule->flags & BUS_MATCH_SENDER);
sl@0
  1562
  _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
sl@0
  1563
  _dbus_assert (rule->flags & BUS_MATCH_MEMBER);
sl@0
  1564
  _dbus_assert (rule->flags & BUS_MATCH_DESTINATION);
sl@0
  1565
  _dbus_assert (rule->flags & BUS_MATCH_PATH);
sl@0
  1566
sl@0
  1567
  _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
sl@0
  1568
  _dbus_assert (rule->interface != NULL);
sl@0
  1569
  _dbus_assert (rule->member != NULL);
sl@0
  1570
  _dbus_assert (rule->sender != NULL);
sl@0
  1571
  _dbus_assert (rule->destination != NULL);
sl@0
  1572
  _dbus_assert (rule->path != NULL);
sl@0
  1573
sl@0
  1574
  _dbus_assert (strcmp (rule->interface, "org.freedesktop.DBusInterface") == 0);
sl@0
  1575
  _dbus_assert (strcmp (rule->sender, "org.freedesktop.DBusSender") == 0);
sl@0
  1576
  _dbus_assert (strcmp (rule->member, "Foo") == 0);
sl@0
  1577
  _dbus_assert (strcmp (rule->path, "/bar/foo") == 0);
sl@0
  1578
  _dbus_assert (strcmp (rule->destination, ":452345.34") == 0);
sl@0
  1579
}
sl@0
  1580
sl@0
  1581
static dbus_bool_t
sl@0
  1582
test_parsing (void *data)
sl@0
  1583
{
sl@0
  1584
  BusMatchRule *rule;
sl@0
  1585
sl@0
  1586
  rule = check_parse (TRUE, "type='signal',sender='org.freedesktop.DBusSender',interface='org.freedesktop.DBusInterface',member='Foo',path='/bar/foo',destination=':452345.34'");
sl@0
  1587
  if (rule != NULL)
sl@0
  1588
    {
sl@0
  1589
      assert_large_rule (rule);
sl@0
  1590
      bus_match_rule_unref (rule);
sl@0
  1591
    }
sl@0
  1592
sl@0
  1593
  /* With extra whitespace and useless quotes */
sl@0
  1594
  rule = check_parse (TRUE, "    type='signal',  \tsender='org.freedes''ktop.DBusSender',   interface='org.freedesktop.DBusInterface''''', \tmember='Foo',path='/bar/foo',destination=':452345.34'''''");
sl@0
  1595
  if (rule != NULL)
sl@0
  1596
    {
sl@0
  1597
      assert_large_rule (rule);
sl@0
  1598
      bus_match_rule_unref (rule);
sl@0
  1599
    }
sl@0
  1600
sl@0
  1601
sl@0
  1602
  /* A simple signal connection */
sl@0
  1603
  rule = check_parse (TRUE, "type='signal',path='/foo',interface='org.Bar'");
sl@0
  1604
  if (rule != NULL)
sl@0
  1605
    {
sl@0
  1606
      _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
sl@0
  1607
      _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
sl@0
  1608
      _dbus_assert (rule->flags & BUS_MATCH_PATH);
sl@0
  1609
sl@0
  1610
      _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
sl@0
  1611
      _dbus_assert (rule->interface != NULL);
sl@0
  1612
      _dbus_assert (rule->path != NULL);
sl@0
  1613
sl@0
  1614
      _dbus_assert (strcmp (rule->interface, "org.Bar") == 0);
sl@0
  1615
      _dbus_assert (strcmp (rule->path, "/foo") == 0);
sl@0
  1616
  
sl@0
  1617
      bus_match_rule_unref (rule);
sl@0
  1618
    }
sl@0
  1619
sl@0
  1620
  /* argN */
sl@0
  1621
  rule = check_parse (TRUE, "arg0='foo'");
sl@0
  1622
  if (rule != NULL)
sl@0
  1623
    {
sl@0
  1624
      _dbus_assert (rule->flags == BUS_MATCH_ARGS);
sl@0
  1625
      _dbus_assert (rule->args != NULL);
sl@0
  1626
      _dbus_assert (rule->args_len == 1);
sl@0
  1627
      _dbus_assert (rule->args[0] != NULL);
sl@0
  1628
      _dbus_assert (rule->args[1] == NULL);
sl@0
  1629
      _dbus_assert (strcmp (rule->args[0], "foo") == 0);
sl@0
  1630
sl@0
  1631
      bus_match_rule_unref (rule);
sl@0
  1632
    }
sl@0
  1633
  
sl@0
  1634
  rule = check_parse (TRUE, "arg1='foo'");
sl@0
  1635
  if (rule != NULL)
sl@0
  1636
    {
sl@0
  1637
      _dbus_assert (rule->flags == BUS_MATCH_ARGS);
sl@0
  1638
      _dbus_assert (rule->args != NULL);
sl@0
  1639
      _dbus_assert (rule->args_len == 2);
sl@0
  1640
      _dbus_assert (rule->args[0] == NULL);
sl@0
  1641
      _dbus_assert (rule->args[1] != NULL);
sl@0
  1642
      _dbus_assert (rule->args[2] == NULL);
sl@0
  1643
      _dbus_assert (strcmp (rule->args[1], "foo") == 0);
sl@0
  1644
sl@0
  1645
      bus_match_rule_unref (rule);
sl@0
  1646
    }
sl@0
  1647
sl@0
  1648
  rule = check_parse (TRUE, "arg2='foo'");
sl@0
  1649
  if (rule != NULL)
sl@0
  1650
    {
sl@0
  1651
      _dbus_assert (rule->flags == BUS_MATCH_ARGS);
sl@0
  1652
      _dbus_assert (rule->args != NULL);
sl@0
  1653
      _dbus_assert (rule->args_len == 3);
sl@0
  1654
      _dbus_assert (rule->args[0] == NULL);
sl@0
  1655
      _dbus_assert (rule->args[1] == NULL);
sl@0
  1656
      _dbus_assert (rule->args[2] != NULL);
sl@0
  1657
      _dbus_assert (rule->args[3] == NULL);
sl@0
  1658
      _dbus_assert (strcmp (rule->args[2], "foo") == 0);
sl@0
  1659
sl@0
  1660
      bus_match_rule_unref (rule);
sl@0
  1661
    }
sl@0
  1662
  
sl@0
  1663
  rule = check_parse (TRUE, "arg40='foo'");
sl@0
  1664
  if (rule != NULL)
sl@0
  1665
    {
sl@0
  1666
      _dbus_assert (rule->flags == BUS_MATCH_ARGS);
sl@0
  1667
      _dbus_assert (rule->args != NULL);
sl@0
  1668
      _dbus_assert (rule->args_len == 41);
sl@0
  1669
      _dbus_assert (rule->args[0] == NULL);
sl@0
  1670
      _dbus_assert (rule->args[1] == NULL);
sl@0
  1671
      _dbus_assert (rule->args[40] != NULL);
sl@0
  1672
      _dbus_assert (rule->args[41] == NULL);
sl@0
  1673
      _dbus_assert (strcmp (rule->args[40], "foo") == 0);
sl@0
  1674
sl@0
  1675
      bus_match_rule_unref (rule);
sl@0
  1676
    }
sl@0
  1677
  
sl@0
  1678
  rule = check_parse (TRUE, "arg63='foo'");
sl@0
  1679
  if (rule != NULL)
sl@0
  1680
    {
sl@0
  1681
      _dbus_assert (rule->flags == BUS_MATCH_ARGS);
sl@0
  1682
      _dbus_assert (rule->args != NULL);
sl@0
  1683
      _dbus_assert (rule->args_len == 64);
sl@0
  1684
      _dbus_assert (rule->args[0] == NULL);
sl@0
  1685
      _dbus_assert (rule->args[1] == NULL);
sl@0
  1686
      _dbus_assert (rule->args[63] != NULL);
sl@0
  1687
      _dbus_assert (rule->args[64] == NULL);
sl@0
  1688
      _dbus_assert (strcmp (rule->args[63], "foo") == 0);
sl@0
  1689
sl@0
  1690
      bus_match_rule_unref (rule);
sl@0
  1691
    }
sl@0
  1692
  
sl@0
  1693
  /* Too-large argN */
sl@0
  1694
  rule = check_parse (FALSE, "arg300='foo'");
sl@0
  1695
  _dbus_assert (rule == NULL);
sl@0
  1696
  rule = check_parse (FALSE, "arg64='foo'");
sl@0
  1697
  _dbus_assert (rule == NULL);
sl@0
  1698
sl@0
  1699
  /* No N in argN */
sl@0
  1700
  rule = check_parse (FALSE, "arg='foo'");
sl@0
  1701
  _dbus_assert (rule == NULL);
sl@0
  1702
  rule = check_parse (FALSE, "argv='foo'");
sl@0
  1703
  _dbus_assert (rule == NULL);
sl@0
  1704
  rule = check_parse (FALSE, "arg3junk='foo'");
sl@0
  1705
  _dbus_assert (rule == NULL);
sl@0
  1706
  rule = check_parse (FALSE, "argument='foo'");
sl@0
  1707
  _dbus_assert (rule == NULL);
sl@0
  1708
  
sl@0
  1709
  /* Reject duplicates */
sl@0
  1710
  rule = check_parse (FALSE, "type='signal',type='method_call'");
sl@0
  1711
  _dbus_assert (rule == NULL);
sl@0
  1712
sl@0
  1713
  /* Duplicates with the argN code */
sl@0
  1714
  rule = check_parse (FALSE, "arg0='foo',arg0='bar'");
sl@0
  1715
  _dbus_assert (rule == NULL);
sl@0
  1716
  rule = check_parse (FALSE, "arg3='foo',arg3='bar'");
sl@0
  1717
  _dbus_assert (rule == NULL);
sl@0
  1718
  rule = check_parse (FALSE, "arg30='foo',arg30='bar'");
sl@0
  1719
  _dbus_assert (rule == NULL);
sl@0
  1720
  
sl@0
  1721
  /* Reject broken keys */
sl@0
  1722
  rule = check_parse (FALSE, "blah='signal'");
sl@0
  1723
  _dbus_assert (rule == NULL);
sl@0
  1724
sl@0
  1725
  /* Reject broken values */
sl@0
  1726
  rule = check_parse (FALSE, "type='chouin'");
sl@0
  1727
  _dbus_assert (rule == NULL);
sl@0
  1728
  rule = check_parse (FALSE, "interface='abc@def++'");
sl@0
  1729
  _dbus_assert (rule == NULL);
sl@0
  1730
  rule = check_parse (FALSE, "service='youpi'");
sl@0
  1731
  _dbus_assert (rule == NULL);
sl@0
  1732
sl@0
  1733
  /* Allow empty rule */
sl@0
  1734
  rule = check_parse (TRUE, "");
sl@0
  1735
  if (rule != NULL)
sl@0
  1736
    {
sl@0
  1737
      _dbus_assert (rule->flags == 0);
sl@0
  1738
      
sl@0
  1739
      bus_match_rule_unref (rule);
sl@0
  1740
    }
sl@0
  1741
sl@0
  1742
  /* All-whitespace rule is the same as empty */
sl@0
  1743
  rule = check_parse (TRUE, "    \t");
sl@0
  1744
  if (rule != NULL)
sl@0
  1745
    {
sl@0
  1746
      _dbus_assert (rule->flags == 0);
sl@0
  1747
      
sl@0
  1748
      bus_match_rule_unref (rule);
sl@0
  1749
    }
sl@0
  1750
sl@0
  1751
  /* But with non-whitespace chars and no =value, it's not OK */
sl@0
  1752
  rule = check_parse (FALSE, "type");
sl@0
  1753
  _dbus_assert (rule == NULL);
sl@0
  1754
  
sl@0
  1755
  return TRUE;
sl@0
  1756
}
sl@0
  1757
sl@0
  1758
static struct {
sl@0
  1759
  const char *first;
sl@0
  1760
  const char *second;
sl@0
  1761
} equality_tests[] = {
sl@0
  1762
  { "type='signal'", "type='signal'" },
sl@0
  1763
  { "type='signal',interface='foo.bar'", "interface='foo.bar',type='signal'" },
sl@0
  1764
  { "type='signal',member='bar'", "member='bar',type='signal'" },
sl@0
  1765
  { "type='method_call',sender=':1.0'", "sender=':1.0',type='method_call'" },
sl@0
  1766
  { "type='method_call',destination=':1.0'", "destination=':1.0',type='method_call'" },
sl@0
  1767
  { "type='method_call',path='/foo/bar'", "path='/foo/bar',type='method_call'" },
sl@0
  1768
  { "type='method_call',arg0='blah'", "arg0='blah',type='method_call'" },
sl@0
  1769
  { "type='method_call',arg0='boo'", "arg0='boo',type='method_call'" },
sl@0
  1770
  { "type='method_call',arg0='blah',arg1='baz'", "arg0='blah',arg1='baz',type='method_call'" },
sl@0
  1771
  { "type='method_call',arg3='foosh'", "arg3='foosh',type='method_call'" },
sl@0
  1772
  { "arg3='fool'", "arg3='fool'" },
sl@0
  1773
  { "member='food'", "member='food'" }
sl@0
  1774
};
sl@0
  1775
sl@0
  1776
static void
sl@0
  1777
test_equality (void)
sl@0
  1778
{
sl@0
  1779
  int i;
sl@0
  1780
  
sl@0
  1781
  i = 0;
sl@0
  1782
  while (i < _DBUS_N_ELEMENTS (equality_tests))
sl@0
  1783
    {
sl@0
  1784
      BusMatchRule *first;
sl@0
  1785
      BusMatchRule *second;
sl@0
  1786
      int j;
sl@0
  1787
      
sl@0
  1788
      first = check_parse (TRUE, equality_tests[i].first);
sl@0
  1789
      _dbus_assert (first != NULL);
sl@0
  1790
      second = check_parse (TRUE, equality_tests[i].second);
sl@0
  1791
      _dbus_assert (second != NULL);
sl@0
  1792
sl@0
  1793
      if (!match_rule_equal (first, second))
sl@0
  1794
        {
sl@0
  1795
          _dbus_warn ("rule %s and %s should have been equal\n",
sl@0
  1796
                      equality_tests[i].first,
sl@0
  1797
                      equality_tests[i].second);
sl@0
  1798
          exit (1);
sl@0
  1799
        }
sl@0
  1800
sl@0
  1801
      bus_match_rule_unref (second);
sl@0
  1802
sl@0
  1803
      /* Check that the rule is not equal to any of the
sl@0
  1804
       * others besides its pair match
sl@0
  1805
       */
sl@0
  1806
      j = 0;
sl@0
  1807
      while (j < _DBUS_N_ELEMENTS (equality_tests))
sl@0
  1808
        {
sl@0
  1809
          if (i != j)
sl@0
  1810
            {
sl@0
  1811
              second = check_parse (TRUE, equality_tests[j].second);
sl@0
  1812
sl@0
  1813
              if (match_rule_equal (first, second))
sl@0
  1814
                {
sl@0
  1815
                  _dbus_warn ("rule %s and %s should not have been equal\n",
sl@0
  1816
                              equality_tests[i].first,
sl@0
  1817
                              equality_tests[j].second);
sl@0
  1818
                  exit (1);
sl@0
  1819
                }
sl@0
  1820
              
sl@0
  1821
              bus_match_rule_unref (second);
sl@0
  1822
            }
sl@0
  1823
          
sl@0
  1824
          ++j;
sl@0
  1825
        }
sl@0
  1826
sl@0
  1827
      bus_match_rule_unref (first);
sl@0
  1828
sl@0
  1829
      ++i;
sl@0
  1830
    }
sl@0
  1831
}
sl@0
  1832
sl@0
  1833
static const char*
sl@0
  1834
should_match_message_1[] = {
sl@0
  1835
  "type='signal'",
sl@0
  1836
  "member='Frobated'",
sl@0
  1837
  "arg0='foobar'",
sl@0
  1838
  "type='signal',member='Frobated'",
sl@0
  1839
  "type='signal',member='Frobated',arg0='foobar'",
sl@0
  1840
  "member='Frobated',arg0='foobar'",
sl@0
  1841
  "type='signal',arg0='foobar'",
sl@0
  1842
  NULL
sl@0
  1843
};
sl@0
  1844
sl@0
  1845
static const char*
sl@0
  1846
should_not_match_message_1[] = {
sl@0
  1847
  "type='method_call'",
sl@0
  1848
  "type='error'",
sl@0
  1849
  "type='method_return'",
sl@0
  1850
  "type='signal',member='Oopsed'",
sl@0
  1851
  "arg0='blah'",
sl@0
  1852
  "arg1='foobar'",
sl@0
  1853
  "arg2='foobar'",
sl@0
  1854
  "arg3='foobar'",
sl@0
  1855
  "arg0='3'",
sl@0
  1856
  "arg1='3'",
sl@0
  1857
  "arg0='foobar',arg1='abcdef'",
sl@0
  1858
  "arg0='foobar',arg1='abcdef',arg2='abcdefghi',arg3='abcdefghi',arg4='abcdefghi'",
sl@0
  1859
  "arg0='foobar',arg1='abcdef',arg4='abcdefghi',arg3='abcdefghi',arg2='abcdefghi'",
sl@0
  1860
  NULL
sl@0
  1861
};
sl@0
  1862
sl@0
  1863
static void
sl@0
  1864
check_matches (dbus_bool_t  expected_to_match,
sl@0
  1865
               int          number,
sl@0
  1866
               DBusMessage *message,
sl@0
  1867
               const char  *rule_text)
sl@0
  1868
{
sl@0
  1869
  BusMatchRule *rule;
sl@0
  1870
  dbus_bool_t matched;
sl@0
  1871
sl@0
  1872
  rule = check_parse (TRUE, rule_text);
sl@0
  1873
  _dbus_assert (rule != NULL);
sl@0
  1874
sl@0
  1875
  /* We can't test sender/destination rules since we pass NULL here */
sl@0
  1876
  matched = match_rule_matches (rule, NULL, NULL, message);
sl@0
  1877
sl@0
  1878
  if (matched != expected_to_match)
sl@0
  1879
    {
sl@0
  1880
      _dbus_warn ("Expected rule %s to %s message %d, failed\n",
sl@0
  1881
                  rule_text, expected_to_match ?
sl@0
  1882
                  "match" : "not match", number);
sl@0
  1883
      exit (1);
sl@0
  1884
    }
sl@0
  1885
sl@0
  1886
  bus_match_rule_unref (rule);
sl@0
  1887
}
sl@0
  1888
sl@0
  1889
static void
sl@0
  1890
check_matching (DBusMessage *message,
sl@0
  1891
                int          number,
sl@0
  1892
                const char **should_match,
sl@0
  1893
                const char **should_not_match)
sl@0
  1894
{
sl@0
  1895
  int i;
sl@0
  1896
sl@0
  1897
  i = 0;
sl@0
  1898
  while (should_match[i] != NULL)
sl@0
  1899
    {
sl@0
  1900
      check_matches (TRUE, number, message, should_match[i]);
sl@0
  1901
      ++i;
sl@0
  1902
    }
sl@0
  1903
sl@0
  1904
  i = 0;
sl@0
  1905
  while (should_not_match[i] != NULL)
sl@0
  1906
    {
sl@0
  1907
      check_matches (FALSE, number, message, should_not_match[i]);
sl@0
  1908
      ++i;
sl@0
  1909
    }
sl@0
  1910
}
sl@0
  1911
sl@0
  1912
static void
sl@0
  1913
test_matching (void)
sl@0
  1914
{
sl@0
  1915
  DBusMessage *message1;
sl@0
  1916
  const char *v_STRING;
sl@0
  1917
  dbus_int32_t v_INT32;
sl@0
  1918
sl@0
  1919
  message1 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
sl@0
  1920
  _dbus_assert (message1 != NULL);
sl@0
  1921
  if (!dbus_message_set_member (message1, "Frobated"))
sl@0
  1922
    _dbus_assert_not_reached ("oom");
sl@0
  1923
sl@0
  1924
  v_STRING = "foobar";
sl@0
  1925
  v_INT32 = 3;
sl@0
  1926
  if (!dbus_message_append_args (message1,
sl@0
  1927
                                 DBUS_TYPE_STRING, &v_STRING,
sl@0
  1928
                                 DBUS_TYPE_INT32, &v_INT32,
sl@0
  1929
                                 NULL))
sl@0
  1930
    _dbus_assert_not_reached ("oom");
sl@0
  1931
  
sl@0
  1932
  check_matching (message1, 1,
sl@0
  1933
                  should_match_message_1,
sl@0
  1934
                  should_not_match_message_1);
sl@0
  1935
  
sl@0
  1936
  dbus_message_unref (message1);
sl@0
  1937
}
sl@0
  1938
sl@0
  1939
dbus_bool_t
sl@0
  1940
bus_signals_test (const DBusString *test_data_dir)
sl@0
  1941
{
sl@0
  1942
  BusMatchmaker *matchmaker;
sl@0
  1943
sl@0
  1944
  matchmaker = bus_matchmaker_new ();
sl@0
  1945
  bus_matchmaker_ref (matchmaker);
sl@0
  1946
  bus_matchmaker_unref (matchmaker);
sl@0
  1947
  bus_matchmaker_unref (matchmaker);
sl@0
  1948
sl@0
  1949
  if (!_dbus_test_oom_handling ("parsing match rules", test_parsing, NULL))
sl@0
  1950
    _dbus_assert_not_reached ("Parsing match rules test failed");
sl@0
  1951
sl@0
  1952
  test_equality ();
sl@0
  1953
sl@0
  1954
  test_matching ();
sl@0
  1955
  
sl@0
  1956
  return TRUE;
sl@0
  1957
}
sl@0
  1958
sl@0
  1959
#endif /* DBUS_BUILD_TESTS */
sl@0
  1960