Update .bzrignore.
[bitlbee.git] / irc_channel.c
blob7dc9f8854c771fdbf13d831d6f6994f62337b40d
1 /********************************************************************\
2 * BitlBee -- An IRC to other IM-networks gateway *
3 * *
4 * Copyright 2002-2010 Wilmer van der Gaast and others *
5 \********************************************************************/
7 /* The IRC-based UI - Representing (virtual) channels. */
9 /*
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License with
21 the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
22 if not, write to the Free Software Foundation, Inc., 59 Temple Place,
23 Suite 330, Boston, MA 02111-1307 USA
26 #include "bitlbee.h"
28 static char *set_eval_channel_type( set_t *set, char *value );
29 static gint irc_channel_user_cmp( gconstpointer a_, gconstpointer b_ );
30 static const struct irc_channel_funcs control_channel_funcs;
32 extern const struct irc_channel_funcs irc_channel_im_chat_funcs;
34 irc_channel_t *irc_channel_new( irc_t *irc, const char *name )
36 irc_channel_t *ic;
38 if( !irc_channel_name_ok( name ) || irc_channel_by_name( irc, name ) )
39 return NULL;
41 ic = g_new0( irc_channel_t, 1 );
42 ic->irc = irc;
43 ic->name = g_strdup( name );
44 strcpy( ic->mode, CMODE );
46 irc_channel_add_user( ic, irc->root );
48 irc->channels = g_slist_append( irc->channels, ic );
50 set_add( &ic->set, "auto_join", "false", set_eval_bool, ic );
51 set_add( &ic->set, "type", "control", set_eval_channel_type, ic );
53 if( name[0] == '&' )
54 set_setstr( &ic->set, "type", "control" );
55 else /* if( name[0] == '#' ) */
56 set_setstr( &ic->set, "type", "chat" );
58 return ic;
61 irc_channel_t *irc_channel_by_name( irc_t *irc, const char *name )
63 GSList *l;
65 for( l = irc->channels; l; l = l->next )
67 irc_channel_t *ic = l->data;
69 if( irc_channel_name_cmp( name, ic->name ) == 0 )
70 return ic;
73 return NULL;
76 irc_channel_t *irc_channel_get( irc_t *irc, char *id )
78 irc_channel_t *ic, *ret = NULL;
79 GSList *l;
80 int nr;
82 if( sscanf( id, "%d", &nr ) == 1 && nr < 1000 )
84 for( l = irc->channels; l; l = l->next )
86 ic = l->data;
87 if( ( nr-- ) == 0 )
88 return ic;
91 return NULL;
94 /* Exact match first: Partial match only sucks if there's a channel
95 #aa and #aabb */
96 if( ( ret = irc_channel_by_name( irc, id ) ) )
97 return ret;
99 for( l = irc->channels; l; l = l->next )
101 ic = l->data;
103 if( strstr( ic->name, id ) )
105 /* Make sure it's a unique match. */
106 if( !ret )
107 ret = ic;
108 else
109 return NULL;
113 return ret;
116 int irc_channel_free( irc_channel_t *ic )
118 irc_t *irc;
119 GSList *l;
121 if( ic == NULL )
122 return 0;
123 irc = ic->irc;
125 if( ic->flags & IRC_CHANNEL_JOINED )
126 irc_channel_del_user( ic, irc->user, IRC_CDU_KICK, "Cleaning up channel" );
128 if( ic->f->_free )
129 ic->f->_free( ic );
131 while( ic->set )
132 set_del( &ic->set, ic->set->key );
134 irc->channels = g_slist_remove( irc->channels, ic );
135 while( ic->users )
137 g_free( ic->users->data );
138 ic->users = g_slist_remove( ic->users, ic->users->data );
141 for( l = irc->users; l; l = l->next )
143 irc_user_t *iu = l->data;
145 if( iu->last_channel == ic )
146 iu->last_channel = irc->default_channel;
149 if( ic->pastebuf_timer ) b_event_remove( ic->pastebuf_timer );
151 g_free( ic->name );
152 g_free( ic->topic );
153 g_free( ic->topic_who );
154 g_free( ic );
156 return 1;
159 struct irc_channel_free_data
161 irc_t *irc;
162 irc_channel_t *ic;
163 char *name;
166 static gboolean irc_channel_free_callback( gpointer data, gint fd, b_input_condition cond )
168 struct irc_channel_free_data *d = data;
170 if( g_slist_find( irc_connection_list, d->irc ) &&
171 irc_channel_by_name( d->irc, d->name ) == d->ic &&
172 !( d->ic->flags & IRC_CHANNEL_JOINED ) )
173 irc_channel_free( d->ic );
175 g_free( d->name );
176 g_free( d );
177 return FALSE;
180 /* Free the channel, but via the event loop, so after finishing whatever event
181 we're currently handling. */
182 void irc_channel_free_soon( irc_channel_t *ic )
184 struct irc_channel_free_data *d = g_new0( struct irc_channel_free_data, 1 );
186 d->irc = ic->irc;
187 d->ic = ic;
188 d->name = g_strdup( ic->name );
190 b_timeout_add( 0, irc_channel_free_callback, d );
193 static char *set_eval_channel_type( set_t *set, char *value )
195 struct irc_channel *ic = set->data;
196 const struct irc_channel_funcs *new;
198 if( strcmp( value, "control" ) == 0 )
199 new = &control_channel_funcs;
200 else if( ic != ic->irc->default_channel && strcmp( value, "chat" ) == 0 )
201 new = &irc_channel_im_chat_funcs;
202 else
203 return SET_INVALID;
205 /* TODO: Return values. */
206 if( ic->f && ic->f->_free )
207 ic->f->_free( ic );
209 ic->f = new;
211 if( ic->f && ic->f->_init )
212 ic->f->_init( ic );
214 return value;
217 int irc_channel_add_user( irc_channel_t *ic, irc_user_t *iu )
219 irc_channel_user_t *icu;
221 if( irc_channel_has_user( ic, iu ) )
222 return 0;
224 icu = g_new0( irc_channel_user_t, 1 );
225 icu->iu = iu;
227 ic->users = g_slist_insert_sorted( ic->users, icu, irc_channel_user_cmp );
229 irc_channel_update_ops( ic, set_getstr( &ic->irc->b->set, "ops" ) );
231 if( iu == ic->irc->user || ic->flags & IRC_CHANNEL_JOINED )
233 ic->flags |= IRC_CHANNEL_JOINED;
234 irc_send_join( ic, iu );
237 return 1;
240 int irc_channel_del_user( irc_channel_t *ic, irc_user_t *iu, irc_channel_del_user_type_t type, const char *msg )
242 irc_channel_user_t *icu;
244 if( !( icu = irc_channel_has_user( ic, iu ) ) )
245 return 0;
247 ic->users = g_slist_remove( ic->users, icu );
248 g_free( icu );
250 if( !( ic->flags & IRC_CHANNEL_JOINED ) || type == IRC_CDU_SILENT ) {}
251 /* Do nothing. The caller should promise it won't screw
252 up state of the IRC client. :-) */
253 else if( type == IRC_CDU_PART )
254 irc_send_part( ic, iu, msg );
255 else if( type == IRC_CDU_KICK )
256 irc_send_kick( ic, iu, ic->irc->root, msg );
258 if( iu == ic->irc->user )
260 ic->flags &= ~IRC_CHANNEL_JOINED;
262 if( ic->irc->status & USTATUS_SHUTDOWN )
264 /* Don't do anything fancy when we're shutting down anyway. */
266 else if( ic->flags & IRC_CHANNEL_TEMP )
268 irc_channel_free_soon( ic );
270 else
272 /* Flush userlist now. The user won't see it anyway. */
273 while( ic->users )
275 g_free( ic->users->data );
276 ic->users = g_slist_remove( ic->users, ic->users->data );
278 irc_channel_add_user( ic, ic->irc->root );
282 return 1;
285 irc_channel_user_t *irc_channel_has_user( irc_channel_t *ic, irc_user_t *iu )
287 GSList *l;
289 for( l = ic->users; l; l = l->next )
291 irc_channel_user_t *icu = l->data;
293 if( icu->iu == iu )
294 return icu;
297 return NULL;
300 /* Find a channel we're currently in, that currently has iu in it. */
301 struct irc_channel *irc_channel_with_user( irc_t *irc, irc_user_t *iu )
303 GSList *l;
305 for( l = irc->channels; l; l = l->next )
307 irc_channel_t *ic = l->data;
309 if( strcmp( set_getstr( &ic->set, "type" ), "control" ) != 0 )
310 continue;
312 if( ( ic->flags & IRC_CHANNEL_JOINED ) &&
313 irc_channel_has_user( ic, iu ) )
314 return ic;
317 /* If there was no match, try once more but just see if the user
318 *would* be in the channel, i.e. if s/he were online. */
319 if( iu->bu == NULL )
320 return NULL;
322 for( l = irc->channels; l; l = l->next )
324 irc_channel_t *ic = l->data;
326 if( strcmp( set_getstr( &ic->set, "type" ), "control" ) != 0 )
327 continue;
329 if( ( ic->flags & IRC_CHANNEL_JOINED ) &&
330 irc_channel_wants_user( ic, iu ) )
331 return ic;
334 return NULL;
337 int irc_channel_set_topic( irc_channel_t *ic, const char *topic, const irc_user_t *iu )
339 g_free( ic->topic );
340 ic->topic = g_strdup( topic );
342 g_free( ic->topic_who );
343 if( iu )
344 ic->topic_who = g_strdup_printf( "%s!%s@%s", iu->nick, iu->user, iu->host );
345 else
346 ic->topic_who = NULL;
348 ic->topic_time = time( NULL );
350 if( ic->flags & IRC_CHANNEL_JOINED )
351 irc_send_topic( ic, TRUE );
353 return 1;
356 void irc_channel_user_set_mode( irc_channel_t *ic, irc_user_t *iu, irc_channel_user_flags_t flags )
358 irc_channel_user_t *icu = irc_channel_has_user( ic, iu );
360 if( !icu || icu->flags == flags )
361 return;
363 if( ic->flags & IRC_CHANNEL_JOINED )
364 irc_send_channel_user_mode_diff( ic, iu, icu->flags, flags );
366 icu->flags = flags;
369 void irc_channel_set_mode( irc_channel_t *ic, const char *s )
371 irc_t *irc = ic->irc;
372 char m[128], st = 1;
373 const char *t;
374 int i;
375 char changes[512], *p, st2 = 2;
377 memset( m, 0, sizeof( m ) );
379 for( t = ic->mode; *t; t ++ )
380 if( *t < sizeof( m ) )
381 m[(int)*t] = 1;
383 p = changes;
384 for( t = s; *t; t ++ )
386 if( *t == '+' || *t == '-' )
387 st = *t == '+';
388 else if( strchr( CMODES, *t ) )
390 if( m[(int)*t] != st)
392 if( st != st2 )
393 st2 = st, *p++ = st ? '+' : '-';
394 *p++ = *t;
396 m[(int)*t] = st;
399 *p = '\0';
401 memset( ic->mode, 0, sizeof( ic->mode ) );
403 for( i = 'A'; i <= 'z' && strlen( ic->mode ) < ( sizeof( ic->mode ) - 1 ); i ++ )
404 if( m[i] )
405 ic->mode[strlen(ic->mode)] = i;
407 if( *changes && ( ic->flags & IRC_CHANNEL_JOINED ) )
408 irc_write( irc, ":%s!%s@%s MODE %s :%s", irc->root->nick,
409 irc->root->user, irc->root->host, ic->name,
410 changes );
413 void irc_channel_auto_joins( irc_t *irc, account_t *acc )
415 GSList *l;
417 for( l = irc->channels; l; l = l->next )
419 irc_channel_t *ic = l->data;
420 gboolean aj = set_getbool( &ic->set, "auto_join" );
421 char *type;
423 if( acc &&
424 ( type = set_getstr( &ic->set, "chat_type" ) ) &&
425 strcmp( type, "room" ) == 0 )
427 /* Bit of an ugly special case: Handle chatrooms here, we
428 can only auto-join them if their account is online. */
429 char *acc_s;
431 if( !aj && !( ic->flags & IRC_CHANNEL_JOINED ) )
432 /* Only continue if this one's marked as auto_join
433 or if we're in it already. (Possible if the
434 client auto-rejoined it before identyfing.) */
435 continue;
436 else if( !( acc_s = set_getstr( &ic->set, "account" ) ) )
437 continue;
438 else if( account_get( irc->b, acc_s ) != acc )
439 continue;
440 else if( acc->ic == NULL || !( acc->ic->flags & OPT_LOGGED_IN ) )
441 continue;
442 else
443 ic->f->join( ic );
445 else if( aj )
447 irc_channel_add_user( ic, irc->user );
452 void irc_channel_printf( irc_channel_t *ic, char *format, ... )
454 va_list params;
455 char *text;
457 va_start( params, format );
458 text = g_strdup_vprintf( format, params );
459 va_end( params );
461 irc_send_msg( ic->irc->root, "PRIVMSG", ic->name, text, NULL );
462 g_free( text );
465 gboolean irc_channel_name_ok( const char *name_ )
467 const unsigned char *name = (unsigned char*) name_;
468 int i;
470 if( name_[0] == '\0' )
471 return FALSE;
473 /* Check if the first character is in CTYPES (#&) */
474 if( strchr( CTYPES, name_[0] ) == NULL )
475 return FALSE;
477 /* RFC 1459 keeps amazing me: While only a "few" chars are allowed
478 in nicknames, channel names can be pretty much anything as long
479 as they start with # or &. I'll be a little bit more strict and
480 disallow all non-printable characters. */
481 for( i = 1; name[i]; i ++ )
482 if( name[i] <= ' ' || name[i] == ',' )
483 return FALSE;
485 return TRUE;
488 void irc_channel_name_strip( char *name )
490 int i, j;
492 for( i = j = 0; name[i]; i ++ )
493 if( name[i] > ' ' && name[i] != ',' )
494 name[j++] = name[i];
496 name[j] = '\0';
499 int irc_channel_name_cmp( const char *a_, const char *b_ )
501 static unsigned char case_map[256];
502 const unsigned char *a = (unsigned char*) a_, *b = (unsigned char*) b_;
503 int i;
505 if( case_map['A'] == '\0' )
507 for( i = 33; i < 256; i ++ )
508 if( i != ',' )
509 case_map[i] = i;
511 for( i = 0; i < 26; i ++ )
512 case_map['A'+i] = 'a' + i;
514 case_map['['] = '{';
515 case_map[']'] = '}';
516 case_map['~'] = '`';
517 case_map['\\'] = '|';
520 if( !irc_channel_name_ok( a_ ) || !irc_channel_name_ok( b_ ) )
521 return -1;
523 for( i = 0; a[i] && b[i] && case_map[a[i]] && case_map[b[i]]; i ++ )
525 if( case_map[a[i]] == case_map[b[i]] )
526 continue;
527 else
528 return case_map[a[i]] - case_map[b[i]];
531 return case_map[a[i]] - case_map[b[i]];
534 static gint irc_channel_user_cmp( gconstpointer a_, gconstpointer b_ )
536 const irc_channel_user_t *a = a_, *b = b_;
538 return irc_user_cmp( a->iu, b->iu );
541 void irc_channel_update_ops( irc_channel_t *ic, char *value )
543 irc_channel_user_set_mode( ic, ic->irc->root,
544 ( strcmp( value, "both" ) == 0 ||
545 strcmp( value, "root" ) == 0 ) ? IRC_CHANNEL_USER_OP : 0 );
546 irc_channel_user_set_mode( ic, ic->irc->user,
547 ( strcmp( value, "both" ) == 0 ||
548 strcmp( value, "user" ) == 0 ) ? IRC_CHANNEL_USER_OP : 0 );
551 char *set_eval_irc_channel_ops( set_t *set, char *value )
553 irc_t *irc = set->data;
554 GSList *l;
556 if( strcmp( value, "both" ) != 0 && strcmp( value, "none" ) != 0 &&
557 strcmp( value, "user" ) != 0 && strcmp( value, "root" ) != 0 )
558 return SET_INVALID;
560 for( l = irc->channels; l; l = l->next )
561 irc_channel_update_ops( l->data, value );
563 return value;
566 /* Channel-type dependent functions, for control channels: */
567 static gboolean control_channel_privmsg( irc_channel_t *ic, const char *msg )
569 irc_t *irc = ic->irc;
570 irc_user_t *iu;
571 const char *s;
573 /* Scan for non-whitespace chars followed by a colon: */
574 for( s = msg; *s && !isspace( *s ) && *s != ':' && *s != ','; s ++ ) {}
576 if( *s == ':' || *s == ',' )
578 char to[s-msg+1];
580 memset( to, 0, sizeof( to ) );
581 strncpy( to, msg, s - msg );
582 while( *(++s) && isspace( *s ) ) {}
583 msg = s;
585 if( !( iu = irc_user_by_name( irc, to ) ) )
586 irc_channel_printf( ic, "User does not exist: %s", to );
587 else
588 ic->last_target = iu;
590 else if( g_strcasecmp( set_getstr( &irc->b->set, "default_target" ), "last" ) == 0 &&
591 ic->last_target && g_slist_find( irc->users, ic->last_target ) )
592 iu = ic->last_target;
593 else
594 iu = irc->root;
596 if( iu && iu->f->privmsg )
598 iu->last_channel = ic;
599 iu->f->privmsg( iu, msg );
602 return TRUE;
605 static gboolean control_channel_invite( irc_channel_t *ic, irc_user_t *iu )
607 struct irc_control_channel *icc = ic->data;
608 bee_user_t *bu = iu->bu;
610 if( bu == NULL )
611 return FALSE;
613 if( icc->type != IRC_CC_TYPE_GROUP )
615 irc_send_num( ic->irc, 482, "%s :Invitations are only possible to fill_by=group channels", ic->name );
616 return FALSE;
619 bu->ic->acc->prpl->add_buddy( bu->ic, bu->handle,
620 icc->group ? icc->group->name : NULL );
622 return TRUE;
625 static char *set_eval_by_account( set_t *set, char *value );
626 static char *set_eval_fill_by( set_t *set, char *value );
627 static char *set_eval_by_group( set_t *set, char *value );
628 static char *set_eval_by_protocol( set_t *set, char *value );
629 static char *set_eval_show_users( set_t *set, char *value );
631 static gboolean control_channel_init( irc_channel_t *ic )
633 struct irc_control_channel *icc;
635 set_add( &ic->set, "account", NULL, set_eval_by_account, ic );
636 set_add( &ic->set, "fill_by", "all", set_eval_fill_by, ic );
637 set_add( &ic->set, "group", NULL, set_eval_by_group, ic );
638 set_add( &ic->set, "protocol", NULL, set_eval_by_protocol, ic );
640 /* When changing the default, also change it below. */
641 set_add( &ic->set, "show_users", "online+,away", set_eval_show_users, ic );
643 ic->data = icc = g_new0( struct irc_control_channel, 1 );
644 icc->type = IRC_CC_TYPE_DEFAULT;
646 /* Have to run the evaluator to initialize icc->modes. */
647 set_setstr( &ic->set, "show_users", "online+,away" );
649 /* For scripts that care. */
650 irc_channel_set_mode( ic, "+C" );
652 return TRUE;
655 static gboolean control_channel_join( irc_channel_t *ic )
657 bee_irc_channel_update( ic->irc, ic, NULL );
659 return TRUE;
662 static char *set_eval_by_account( set_t *set, char *value )
664 struct irc_channel *ic = set->data;
665 struct irc_control_channel *icc = ic->data;
666 account_t *acc;
668 if( !( acc = account_get( ic->irc->b, value ) ) )
669 return SET_INVALID;
671 icc->account = acc;
672 if( icc->type == IRC_CC_TYPE_ACCOUNT )
673 bee_irc_channel_update( ic->irc, ic, NULL );
675 return g_strdup( acc->tag );
678 static char *set_eval_fill_by( set_t *set, char *value )
680 struct irc_channel *ic = set->data;
681 struct irc_control_channel *icc = ic->data;
683 if( strcmp( value, "all" ) == 0 )
684 icc->type = IRC_CC_TYPE_DEFAULT;
685 else if( strcmp( value, "rest" ) == 0 )
686 icc->type = IRC_CC_TYPE_REST;
687 else if( strcmp( value, "group" ) == 0 )
688 icc->type = IRC_CC_TYPE_GROUP;
689 else if( strcmp( value, "account" ) == 0 )
690 icc->type = IRC_CC_TYPE_ACCOUNT;
691 else if( strcmp( value, "protocol" ) == 0 )
692 icc->type = IRC_CC_TYPE_PROTOCOL;
693 else
694 return SET_INVALID;
696 bee_irc_channel_update( ic->irc, ic, NULL );
697 return value;
700 static char *set_eval_by_group( set_t *set, char *value )
702 struct irc_channel *ic = set->data;
703 struct irc_control_channel *icc = ic->data;
705 icc->group = bee_group_by_name( ic->irc->b, value, TRUE );
706 if( icc->type == IRC_CC_TYPE_GROUP )
707 bee_irc_channel_update( ic->irc, ic, NULL );
709 return g_strdup( icc->group->name );
712 static char *set_eval_by_protocol( set_t *set, char *value )
714 struct irc_channel *ic = set->data;
715 struct irc_control_channel *icc = ic->data;
716 struct prpl *prpl;
718 if( !( prpl = find_protocol( value ) ) )
719 return SET_INVALID;
721 icc->protocol = prpl;
722 if( icc->type == IRC_CC_TYPE_PROTOCOL )
723 bee_irc_channel_update( ic->irc, ic, NULL );
725 return value;
728 static char *set_eval_show_users( set_t *set, char *value )
730 struct irc_channel *ic = set->data;
731 struct irc_control_channel *icc = ic->data;
732 char **parts = g_strsplit( value, ",", 0 ), **part;
733 char modes[4];
735 memset( modes, 0, 4 );
736 for( part = parts; *part; part ++ )
738 char last, modechar = IRC_CHANNEL_USER_NONE;
740 if( **part == '\0' )
741 goto fail;
743 last = (*part)[strlen(*part+1)];
744 if( last == '+' )
745 modechar = IRC_CHANNEL_USER_VOICE;
746 else if( last == '%' )
747 modechar = IRC_CHANNEL_USER_HALFOP;
748 else if( last == '@' )
749 modechar = IRC_CHANNEL_USER_OP;
751 if( strncmp( *part, "offline", 7 ) == 0 )
752 modes[0] = modechar;
753 else if( strncmp( *part, "away", 4 ) == 0 )
754 modes[1] = modechar;
755 else if( strncmp( *part, "online", 6 ) == 0 )
756 modes[2] = modechar;
757 else
758 goto fail;
760 memcpy( icc->modes, modes, 4 );
761 bee_irc_channel_update( ic->irc, ic, NULL );
763 g_strfreev( parts );
764 return value;
766 fail:
767 g_strfreev( parts );
768 return SET_INVALID;
771 /* Figure out if a channel is supposed to have the user, assuming s/he is
772 online or otherwise also selected by the show_users setting. Only works
773 for control channels, but does *not* check if this channel is of that
774 type. Beware! */
775 gboolean irc_channel_wants_user( irc_channel_t *ic, irc_user_t *iu )
777 struct irc_control_channel *icc = ic->data;
779 if( iu->bu == NULL )
780 return FALSE;
782 switch( icc->type )
784 case IRC_CC_TYPE_GROUP:
785 return iu->bu->group == icc->group;
786 case IRC_CC_TYPE_ACCOUNT:
787 return iu->bu->ic->acc == icc->account;
788 case IRC_CC_TYPE_PROTOCOL:
789 return iu->bu->ic->acc->prpl == icc->protocol;
790 case IRC_CC_TYPE_DEFAULT:
791 default:
792 return TRUE;
796 static gboolean control_channel_free( irc_channel_t *ic )
798 struct irc_control_channel *icc = ic->data;
800 set_del( &ic->set, "account" );
801 set_del( &ic->set, "fill_by" );
802 set_del( &ic->set, "group" );
803 set_del( &ic->set, "protocol" );
804 set_del( &ic->set, "show_users" );
806 g_free( icc );
807 ic->data = NULL;
809 /* For scripts that care. */
810 irc_channel_set_mode( ic, "-C" );
812 return TRUE;
815 static const struct irc_channel_funcs control_channel_funcs = {
816 control_channel_privmsg,
817 control_channel_join,
818 NULL,
819 NULL,
820 control_channel_invite,
822 control_channel_init,
823 control_channel_free,