Changeset 5ebff60 for irc_channel.c
- Timestamp:
- 2015-02-20T22:50:54Z (9 years ago)
- Branches:
- master
- Children:
- 0b9daac, 3d45471, 7733b8c
- Parents:
- af359b4
- git-author:
- Indent <please@…> (19-02-15 05:47:20)
- git-committer:
- dequis <dx@…> (20-02-15 22:50:54)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
irc_channel.c
raf359b4 r5ebff60 1 1 /********************************************************************\ 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * … … 26 26 #include "bitlbee.h" 27 27 28 static char *set_eval_channel_type( set_t *set, char *value);29 static gint irc_channel_user_cmp( gconstpointer a_, gconstpointer b_);28 static char *set_eval_channel_type(set_t *set, char *value); 29 static gint irc_channel_user_cmp(gconstpointer a_, gconstpointer b_); 30 30 static const struct irc_channel_funcs control_channel_funcs; 31 31 32 32 extern const struct irc_channel_funcs irc_channel_im_chat_funcs; 33 33 34 irc_channel_t *irc_channel_new( irc_t *irc, const char *name)34 irc_channel_t *irc_channel_new(irc_t *irc, const char *name) 35 35 { 36 36 irc_channel_t *ic; 37 37 set_t *s; 38 39 if ( !irc_channel_name_ok( name ) || irc_channel_by_name( irc, name ) )38 39 if (!irc_channel_name_ok(name) || irc_channel_by_name(irc, name)) { 40 40 return NULL; 41 42 ic = g_new0( irc_channel_t, 1 ); 41 } 42 43 ic = g_new0(irc_channel_t, 1); 43 44 ic->irc = irc; 44 ic->name = g_strdup( name);45 strcpy( ic->mode, CMODE);46 47 irc_channel_add_user( ic, irc->root);48 49 irc->channels = g_slist_append( irc->channels, ic);50 51 set_add( &ic->set, "auto_join", "false", set_eval_bool, ic);52 53 s = set_add( &ic->set, "type", "control", set_eval_channel_type, ic);45 ic->name = g_strdup(name); 46 strcpy(ic->mode, CMODE); 47 48 irc_channel_add_user(ic, irc->root); 49 50 irc->channels = g_slist_append(irc->channels, ic); 51 52 set_add(&ic->set, "auto_join", "false", set_eval_bool, ic); 53 54 s = set_add(&ic->set, "type", "control", set_eval_channel_type, ic); 54 55 s->flags |= SET_NOSAVE; /* Layer violation (XML format detail) */ 55 56 if( name[0] == '&' ) 57 set_setstr( &ic->set, "type", "control" ); 58 else /* if( name[0] == '#' ) */ 59 set_setstr( &ic->set, "type", "chat" ); 60 56 57 if (name[0] == '&') { 58 set_setstr(&ic->set, "type", "control"); 59 } else { /* if( name[0] == '#' ) */ 60 set_setstr(&ic->set, "type", "chat"); 61 } 62 61 63 return ic; 62 64 } 63 65 64 irc_channel_t *irc_channel_by_name( irc_t *irc, const char *name)66 irc_channel_t *irc_channel_by_name(irc_t *irc, const char *name) 65 67 { 66 68 GSList *l; 67 68 for( l = irc->channels; l; l = l->next ) 69 { 69 70 for (l = irc->channels; l; l = l->next) { 70 71 irc_channel_t *ic = l->data; 71 72 if ( irc_channel_name_cmp( name, ic->name ) == 0 )72 73 if (irc_channel_name_cmp(name, ic->name) == 0) { 73 74 return ic; 74 } 75 75 } 76 } 77 76 78 return NULL; 77 79 } 78 80 79 irc_channel_t *irc_channel_get( irc_t *irc, char *id)81 irc_channel_t *irc_channel_get(irc_t *irc, char *id) 80 82 { 81 83 irc_channel_t *ic, *ret = NULL; 82 84 GSList *l; 83 85 int nr; 84 85 if( sscanf( id, "%d", &nr ) == 1 && nr < 1000 ) 86 { 87 for( l = irc->channels; l; l = l->next ) 88 { 86 87 if (sscanf(id, "%d", &nr) == 1 && nr < 1000) { 88 for (l = irc->channels; l; l = l->next) { 89 89 ic = l->data; 90 if ( ( nr-- ) == 0 )90 if ((nr--) == 0) { 91 91 return ic; 92 } 93 92 } 93 } 94 94 95 return NULL; 95 96 } 96 97 97 98 /* Exact match first: Partial match only sucks if there's a channel 98 99 #aa and #aabb */ 99 if ( ( ret = irc_channel_by_name( irc, id ) ) )100 if ((ret = irc_channel_by_name(irc, id))) { 100 101 return ret; 101 102 for( l = irc->channels; l; l = l->next ) 103 {102 } 103 104 for (l = irc->channels; l; l = l->next) { 104 105 ic = l->data; 105 106 if( strstr( ic->name, id ) ) 107 { 106 107 if (strstr(ic->name, id)) { 108 108 /* Make sure it's a unique match. */ 109 if ( !ret )109 if (!ret) { 110 110 ret = ic; 111 else111 } else { 112 112 return NULL; 113 } 114 } 115 113 } 114 } 115 } 116 116 117 return ret; 117 118 } 118 119 119 int irc_channel_free( irc_channel_t *ic)120 int irc_channel_free(irc_channel_t *ic) 120 121 { 121 122 irc_t *irc; 122 123 GSList *l; 123 124 if ( ic == NULL )124 125 if (ic == NULL) { 125 126 return 0; 127 } 126 128 irc = ic->irc; 127 128 if( ic->flags & IRC_CHANNEL_JOINED ) 129 irc_channel_del_user( ic, irc->user, IRC_CDU_KICK, "Cleaning up channel" ); 130 131 if( ic->f->_free ) 132 ic->f->_free( ic ); 133 134 while( ic->set ) 135 set_del( &ic->set, ic->set->key ); 136 137 irc->channels = g_slist_remove( irc->channels, ic ); 138 while( ic->users ) 139 { 140 g_free( ic->users->data ); 141 ic->users = g_slist_remove( ic->users, ic->users->data ); 142 } 143 144 for( l = irc->users; l; l = l->next ) 145 { 129 130 if (ic->flags & IRC_CHANNEL_JOINED) { 131 irc_channel_del_user(ic, irc->user, IRC_CDU_KICK, "Cleaning up channel"); 132 } 133 134 if (ic->f->_free) { 135 ic->f->_free(ic); 136 } 137 138 while (ic->set) { 139 set_del(&ic->set, ic->set->key); 140 } 141 142 irc->channels = g_slist_remove(irc->channels, ic); 143 while (ic->users) { 144 g_free(ic->users->data); 145 ic->users = g_slist_remove(ic->users, ic->users->data); 146 } 147 148 for (l = irc->users; l; l = l->next) { 146 149 irc_user_t *iu = l->data; 147 148 if ( iu->last_channel == ic )150 151 if (iu->last_channel == ic) { 149 152 iu->last_channel = irc->default_channel; 150 } 151 152 if( ic->pastebuf_timer ) b_event_remove( ic->pastebuf_timer ); 153 154 g_free( ic->name ); 155 g_free( ic->topic ); 156 g_free( ic->topic_who ); 157 g_free( ic ); 158 153 } 154 } 155 156 if (ic->pastebuf_timer) { 157 b_event_remove(ic->pastebuf_timer); 158 } 159 160 g_free(ic->name); 161 g_free(ic->topic); 162 g_free(ic->topic_who); 163 g_free(ic); 164 159 165 return 1; 160 166 } 161 167 162 struct irc_channel_free_data 163 { 168 struct irc_channel_free_data { 164 169 irc_t *irc; 165 170 irc_channel_t *ic; … … 167 172 }; 168 173 169 static gboolean irc_channel_free_callback( gpointer data, gint fd, b_input_condition cond)174 static gboolean irc_channel_free_callback(gpointer data, gint fd, b_input_condition cond) 170 175 { 171 176 struct irc_channel_free_data *d = data; 172 173 if( g_slist_find( irc_connection_list, d->irc ) && 174 irc_channel_by_name( d->irc, d->name ) == d->ic && 175 !( d->ic->flags & IRC_CHANNEL_JOINED ) ) 176 irc_channel_free( d->ic ); 177 178 g_free( d->name ); 179 g_free( d ); 177 178 if (g_slist_find(irc_connection_list, d->irc) && 179 irc_channel_by_name(d->irc, d->name) == d->ic && 180 !(d->ic->flags & IRC_CHANNEL_JOINED)) { 181 irc_channel_free(d->ic); 182 } 183 184 g_free(d->name); 185 g_free(d); 180 186 return FALSE; 181 187 } … … 183 189 /* Free the channel, but via the event loop, so after finishing whatever event 184 190 we're currently handling. */ 185 void irc_channel_free_soon( irc_channel_t *ic)186 { 187 struct irc_channel_free_data *d = g_new0( struct irc_channel_free_data, 1);188 191 void irc_channel_free_soon(irc_channel_t *ic) 192 { 193 struct irc_channel_free_data *d = g_new0(struct irc_channel_free_data, 1); 194 189 195 d->irc = ic->irc; 190 196 d->ic = ic; 191 d->name = g_strdup( ic->name);192 193 b_timeout_add( 0, irc_channel_free_callback, d);194 } 195 196 static char *set_eval_channel_type( set_t *set, char *value)197 d->name = g_strdup(ic->name); 198 199 b_timeout_add(0, irc_channel_free_callback, d); 200 } 201 202 static char *set_eval_channel_type(set_t *set, char *value) 197 203 { 198 204 struct irc_channel *ic = set->data; 199 205 const struct irc_channel_funcs *new; 200 201 if ( strcmp( value, "control" ) == 0 )206 207 if (strcmp(value, "control") == 0) { 202 208 new = &control_channel_funcs; 203 else if( ic != ic->irc->default_channel && strcmp( value, "chat" ) == 0 )209 } else if (ic != ic->irc->default_channel && strcmp(value, "chat") == 0) { 204 210 new = &irc_channel_im_chat_funcs; 205 else211 } else { 206 212 return SET_INVALID; 207 213 } 214 208 215 /* TODO: Return values. */ 209 if( ic->f && ic->f->_free ) 210 ic->f->_free( ic ); 211 216 if (ic->f && ic->f->_free) { 217 ic->f->_free(ic); 218 } 219 212 220 ic->f = new; 213 214 if( ic->f && ic->f->_init ) 215 ic->f->_init( ic ); 216 221 222 if (ic->f && ic->f->_init) { 223 ic->f->_init(ic); 224 } 225 217 226 return value; 218 227 } 219 228 220 int irc_channel_add_user( irc_channel_t *ic, irc_user_t *iu)229 int irc_channel_add_user(irc_channel_t *ic, irc_user_t *iu) 221 230 { 222 231 irc_channel_user_t *icu; 223 224 if ( irc_channel_has_user( ic, iu ) )232 233 if (irc_channel_has_user(ic, iu)) { 225 234 return 0; 226 227 icu = g_new0( irc_channel_user_t, 1 ); 235 } 236 237 icu = g_new0(irc_channel_user_t, 1); 228 238 icu->iu = iu; 229 230 ic->users = g_slist_insert_sorted( ic->users, icu, irc_channel_user_cmp ); 231 232 irc_channel_update_ops( ic, set_getstr( &ic->irc->b->set, "ops" ) ); 233 234 if( iu == ic->irc->user || ic->flags & IRC_CHANNEL_JOINED ) 235 { 239 240 ic->users = g_slist_insert_sorted(ic->users, icu, irc_channel_user_cmp); 241 242 irc_channel_update_ops(ic, set_getstr(&ic->irc->b->set, "ops")); 243 244 if (iu == ic->irc->user || ic->flags & IRC_CHANNEL_JOINED) { 236 245 ic->flags |= IRC_CHANNEL_JOINED; 237 irc_send_join( ic, iu);238 } 239 246 irc_send_join(ic, iu); 247 } 248 240 249 return 1; 241 250 } 242 251 243 int irc_channel_del_user( irc_channel_t *ic, irc_user_t *iu, irc_channel_del_user_type_t type, const char *msg)252 int irc_channel_del_user(irc_channel_t *ic, irc_user_t *iu, irc_channel_del_user_type_t type, const char *msg) 244 253 { 245 254 irc_channel_user_t *icu; 246 247 if ( !( icu = irc_channel_has_user( ic, iu ) ) )255 256 if (!(icu = irc_channel_has_user(ic, iu))) { 248 257 return 0; 249 250 ic->users = g_slist_remove( ic->users, icu ); 251 g_free( icu ); 252 253 if( !( ic->flags & IRC_CHANNEL_JOINED ) || type == IRC_CDU_SILENT ) {} 254 /* Do nothing. The caller should promise it won't screw 255 up state of the IRC client. :-) */ 256 else if( type == IRC_CDU_PART ) 257 irc_send_part( ic, iu, msg ); 258 else if( type == IRC_CDU_KICK ) 259 irc_send_kick( ic, iu, ic->irc->root, msg ); 260 261 if( iu == ic->irc->user ) 262 { 258 } 259 260 ic->users = g_slist_remove(ic->users, icu); 261 g_free(icu); 262 263 if (!(ic->flags & IRC_CHANNEL_JOINED) || type == IRC_CDU_SILENT) { 264 } 265 /* Do nothing. The caller should promise it won't screw 266 up state of the IRC client. :-) */ 267 else if (type == IRC_CDU_PART) { 268 irc_send_part(ic, iu, msg); 269 } else if (type == IRC_CDU_KICK) { 270 irc_send_kick(ic, iu, ic->irc->root, msg); 271 } 272 273 if (iu == ic->irc->user) { 263 274 ic->flags &= ~IRC_CHANNEL_JOINED; 264 265 if( ic->irc->status & USTATUS_SHUTDOWN ) 266 { 275 276 if (ic->irc->status & USTATUS_SHUTDOWN) { 267 277 /* Don't do anything fancy when we're shutting down anyway. */ 268 } 269 else if( ic->flags & IRC_CHANNEL_TEMP ) 270 { 271 irc_channel_free_soon( ic ); 272 } 273 else 274 { 278 } else if (ic->flags & IRC_CHANNEL_TEMP) { 279 irc_channel_free_soon(ic); 280 } else { 275 281 /* Flush userlist now. The user won't see it anyway. */ 276 while( ic->users ) 277 { 278 g_free( ic->users->data ); 279 ic->users = g_slist_remove( ic->users, ic->users->data ); 282 while (ic->users) { 283 g_free(ic->users->data); 284 ic->users = g_slist_remove(ic->users, ic->users->data); 280 285 } 281 irc_channel_add_user( ic, ic->irc->root);282 } 283 } 284 286 irc_channel_add_user(ic, ic->irc->root); 287 } 288 } 289 285 290 return 1; 286 291 } 287 292 288 irc_channel_user_t *irc_channel_has_user( irc_channel_t *ic, irc_user_t *iu)293 irc_channel_user_t *irc_channel_has_user(irc_channel_t *ic, irc_user_t *iu) 289 294 { 290 295 GSList *l; 291 292 for( l = ic->users; l; l = l->next ) 293 { 296 297 for (l = ic->users; l; l = l->next) { 294 298 irc_channel_user_t *icu = l->data; 295 296 if ( icu->iu == iu )299 300 if (icu->iu == iu) { 297 301 return icu; 298 } 299 302 } 303 } 304 300 305 return NULL; 301 306 } 302 307 303 308 /* Find a channel we're currently in, that currently has iu in it. */ 304 struct irc_channel *irc_channel_with_user( irc_t *irc, irc_user_t *iu)309 struct irc_channel *irc_channel_with_user(irc_t *irc, irc_user_t *iu) 305 310 { 306 311 GSList *l; 307 308 for( l = irc->channels; l; l = l->next ) 309 { 312 313 for (l = irc->channels; l; l = l->next) { 310 314 irc_channel_t *ic = l->data; 311 312 if ( strcmp( set_getstr( &ic->set, "type" ), "control" ) != 0 )315 316 if (strcmp(set_getstr(&ic->set, "type"), "control") != 0) { 313 317 continue; 314 315 if( ( ic->flags & IRC_CHANNEL_JOINED ) && 316 irc_channel_has_user( ic, iu ) ) 318 } 319 320 if ((ic->flags & IRC_CHANNEL_JOINED) && 321 irc_channel_has_user(ic, iu)) { 317 322 return ic; 318 } 319 323 } 324 } 325 320 326 /* If there was no match, try once more but just see if the user 321 327 *would* be in the channel, i.e. if s/he were online. */ 322 if ( iu->bu == NULL )328 if (iu->bu == NULL) { 323 329 return NULL; 324 325 for( l = irc->channels; l; l = l->next ) 326 {330 } 331 332 for (l = irc->channels; l; l = l->next) { 327 333 irc_channel_t *ic = l->data; 328 329 if ( strcmp( set_getstr( &ic->set, "type" ), "control" ) != 0 )334 335 if (strcmp(set_getstr(&ic->set, "type"), "control") != 0) { 330 336 continue; 331 332 if( ( ic->flags & IRC_CHANNEL_JOINED ) && 333 irc_channel_wants_user( ic, iu ) ) 337 } 338 339 if ((ic->flags & IRC_CHANNEL_JOINED) && 340 irc_channel_wants_user(ic, iu)) { 334 341 return ic; 335 } 336 342 } 343 } 344 337 345 return NULL; 338 346 } 339 347 340 int irc_channel_set_topic( irc_channel_t *ic, const char *topic, const irc_user_t *iu)341 { 342 g_free( ic->topic);343 ic->topic = g_strdup( topic);344 345 g_free( ic->topic_who);346 if ( iu )347 ic->topic_who = g_strdup_printf( "%s!%s@%s", iu->nick, iu->user, iu->host);348 else348 int irc_channel_set_topic(irc_channel_t *ic, const char *topic, const irc_user_t *iu) 349 { 350 g_free(ic->topic); 351 ic->topic = g_strdup(topic); 352 353 g_free(ic->topic_who); 354 if (iu) { 355 ic->topic_who = g_strdup_printf("%s!%s@%s", iu->nick, iu->user, iu->host); 356 } else { 349 357 ic->topic_who = NULL; 350 351 ic->topic_time = time( NULL ); 352 353 if( ic->flags & IRC_CHANNEL_JOINED ) 354 irc_send_topic( ic, TRUE ); 355 358 } 359 360 ic->topic_time = time(NULL); 361 362 if (ic->flags & IRC_CHANNEL_JOINED) { 363 irc_send_topic(ic, TRUE); 364 } 365 356 366 return 1; 357 367 } 358 368 359 void irc_channel_user_set_mode( irc_channel_t *ic, irc_user_t *iu, irc_channel_user_flags_t flags)360 { 361 irc_channel_user_t *icu = irc_channel_has_user( ic, iu);362 363 if ( !icu || icu->flags == flags )369 void irc_channel_user_set_mode(irc_channel_t *ic, irc_user_t *iu, irc_channel_user_flags_t flags) 370 { 371 irc_channel_user_t *icu = irc_channel_has_user(ic, iu); 372 373 if (!icu || icu->flags == flags) { 364 374 return; 365 366 if( ic->flags & IRC_CHANNEL_JOINED ) 367 irc_send_channel_user_mode_diff( ic, iu, icu->flags, flags ); 368 375 } 376 377 if (ic->flags & IRC_CHANNEL_JOINED) { 378 irc_send_channel_user_mode_diff(ic, iu, icu->flags, flags); 379 } 380 369 381 icu->flags = flags; 370 382 } 371 383 372 void irc_channel_set_mode( irc_channel_t *ic, const char *s)384 void irc_channel_set_mode(irc_channel_t *ic, const char *s) 373 385 { 374 386 irc_t *irc = ic->irc; … … 377 389 int i; 378 390 char changes[512], *p, st2 = 2; 379 380 memset( m, 0, sizeof( m ) ); 381 382 for( t = ic->mode; *t; t ++ ) 383 if( *t < sizeof( m ) ) 384 m[(int)*t] = 1; 385 391 392 memset(m, 0, sizeof(m)); 393 394 for (t = ic->mode; *t; t++) { 395 if (*t < sizeof(m)) { 396 m[(int) *t] = 1; 397 } 398 } 399 386 400 p = changes; 387 for( t = s; *t; t ++ ) 388 { 389 if( *t == '+' || *t == '-' ) 401 for (t = s; *t; t++) { 402 if (*t == '+' || *t == '-') { 390 403 st = *t == '+'; 391 else if( strchr( CMODES, *t ) ) 392 { 393 if( m[(int)*t] != st) 394 { 395 if( st != st2 ) 404 } else if (strchr(CMODES, *t)) { 405 if (m[(int) *t] != st) { 406 if (st != st2) { 396 407 st2 = st, *p++ = st ? '+' : '-'; 408 } 397 409 *p++ = *t; 398 410 } 399 m[(int) *t] = st;411 m[(int) *t] = st; 400 412 } 401 413 } 402 414 *p = '\0'; 403 404 memset( ic->mode, 0, sizeof( ic->mode ));405 406 for ( i = 'A'; i <= 'z' && strlen( ic->mode ) < ( sizeof( ic->mode ) - 1 ); i ++ )407 if ( m[i] )415 416 memset(ic->mode, 0, sizeof(ic->mode)); 417 418 for (i = 'A'; i <= 'z' && strlen(ic->mode) < (sizeof(ic->mode) - 1); i++) { 419 if (m[i]) { 408 420 ic->mode[strlen(ic->mode)] = i; 409 410 if( *changes && ( ic->flags & IRC_CHANNEL_JOINED ) ) 411 irc_write( irc, ":%s!%s@%s MODE %s :%s", irc->root->nick, 412 irc->root->user, irc->root->host, ic->name, 413 changes ); 414 } 415 416 void irc_channel_auto_joins( irc_t *irc, account_t *acc ) 421 } 422 } 423 424 if (*changes && (ic->flags & IRC_CHANNEL_JOINED)) { 425 irc_write(irc, ":%s!%s@%s MODE %s :%s", irc->root->nick, 426 irc->root->user, irc->root->host, ic->name, 427 changes); 428 } 429 } 430 431 void irc_channel_auto_joins(irc_t *irc, account_t *acc) 417 432 { 418 433 GSList *l; 419 420 for( l = irc->channels; l; l = l->next ) 421 { 434 435 for (l = irc->channels; l; l = l->next) { 422 436 irc_channel_t *ic = l->data; 423 gboolean aj = set_getbool( &ic->set, "auto_join");437 gboolean aj = set_getbool(&ic->set, "auto_join"); 424 438 char *type; 425 426 if( acc && 427 ( type = set_getstr( &ic->set, "chat_type" ) ) && 428 strcmp( type, "room" ) == 0 ) 429 { 439 440 if (acc && 441 (type = set_getstr(&ic->set, "chat_type")) && 442 strcmp(type, "room") == 0) { 430 443 /* Bit of an ugly special case: Handle chatrooms here, we 431 444 can only auto-join them if their account is online. */ 432 445 char *acc_s; 433 434 if ( !aj || ( ic->flags & IRC_CHANNEL_JOINED ) )446 447 if (!aj || (ic->flags & IRC_CHANNEL_JOINED)) { 435 448 /* Only continue if this one's marked as auto_join 436 449 or if we're in it already. (Possible if the 437 450 client auto-rejoined it before identyfing.) */ 438 451 continue; 439 else if( !( acc_s = set_getstr( &ic->set, "account" ) ) )452 } else if (!(acc_s = set_getstr(&ic->set, "account"))) { 440 453 continue; 441 else if( account_get( irc->b, acc_s ) != acc )454 } else if (account_get(irc->b, acc_s) != acc) { 442 455 continue; 443 else if( acc->ic == NULL || !( acc->ic->flags & OPT_LOGGED_IN ) )456 } else if (acc->ic == NULL || !(acc->ic->flags & OPT_LOGGED_IN)) { 444 457 continue; 445 else 446 ic->f->join( ic ); 447 } 448 else if( aj ) 449 { 450 irc_channel_add_user( ic, irc->user ); 451 } 452 } 453 } 454 455 void irc_channel_printf( irc_channel_t *ic, char *format, ... ) 458 } else { 459 ic->f->join(ic); 460 } 461 } else if (aj) { 462 irc_channel_add_user(ic, irc->user); 463 } 464 } 465 } 466 467 void irc_channel_printf(irc_channel_t *ic, char *format, ...) 456 468 { 457 469 va_list params; 458 470 char *text; 459 460 va_start( params, format);461 text = g_strdup_vprintf( format, params);462 va_end( params);463 464 irc_send_msg( ic->irc->root, "PRIVMSG", ic->name, text, NULL);465 g_free( text);466 } 467 468 gboolean irc_channel_name_ok( const char *name_)469 { 470 const unsigned char *name = (unsigned char *) name_;471 472 va_start(params, format); 473 text = g_strdup_vprintf(format, params); 474 va_end(params); 475 476 irc_send_msg(ic->irc->root, "PRIVMSG", ic->name, text, NULL); 477 g_free(text); 478 } 479 480 gboolean irc_channel_name_ok(const char *name_) 481 { 482 const unsigned char *name = (unsigned char *) name_; 471 483 int i; 472 473 if ( name_[0] == '\0' )484 485 if (name_[0] == '\0') { 474 486 return FALSE; 475 487 } 488 476 489 /* Check if the first character is in CTYPES (#&) */ 477 if ( strchr( CTYPES, name_[0] ) == NULL )490 if (strchr(CTYPES, name_[0]) == NULL) { 478 491 return FALSE; 479 492 } 493 480 494 /* RFC 1459 keeps amazing me: While only a "few" chars are allowed 481 495 in nicknames, channel names can be pretty much anything as long 482 496 as they start with # or &. I'll be a little bit more strict and 483 497 disallow all non-printable characters. */ 484 for ( i = 1; name[i]; i ++ )485 if ( name[i] <= ' ' || name[i] == ',' )498 for (i = 1; name[i]; i++) { 499 if (name[i] <= ' ' || name[i] == ',') { 486 500 return FALSE; 487 501 } 502 } 503 488 504 return TRUE; 489 505 } 490 506 491 void irc_channel_name_strip( char *name)507 void irc_channel_name_strip(char *name) 492 508 { 493 509 int i, j; 494 495 for ( i = j = 0; name[i]; i ++ )496 if ( name[i] > ' ' && name[i] != ',' )510 511 for (i = j = 0; name[i]; i++) { 512 if (name[i] > ' ' && name[i] != ',') { 497 513 name[j++] = name[i]; 498 514 } 515 } 516 499 517 name[j] = '\0'; 500 518 } 501 519 502 int irc_channel_name_cmp( const char *a_, const char *b_)520 int irc_channel_name_cmp(const char *a_, const char *b_) 503 521 { 504 522 static unsigned char case_map[256]; 505 const unsigned char *a = (unsigned char *) a_, *b = (unsigned char*) b_;523 const unsigned char *a = (unsigned char *) a_, *b = (unsigned char *) b_; 506 524 int i; 507 508 if( case_map['A'] == '\0' ) 509 { 510 for( i = 33; i < 256; i ++ ) 511 if( i != ',' ) 525 526 if (case_map['A'] == '\0') { 527 for (i = 33; i < 256; i++) { 528 if (i != ',') { 512 529 case_map[i] = i; 513 514 for( i = 0; i < 26; i ++ ) 515 case_map['A'+i] = 'a' + i; 516 530 } 531 } 532 533 for (i = 0; i < 26; i++) { 534 case_map['A' + i] = 'a' + i; 535 } 536 517 537 case_map['['] = '{'; 518 538 case_map[']'] = '}'; … … 520 540 case_map['\\'] = '|'; 521 541 } 522 523 if ( !irc_channel_name_ok( a_ ) || !irc_channel_name_ok( b_ ) )542 543 if (!irc_channel_name_ok(a_) || !irc_channel_name_ok(b_)) { 524 544 return -1; 525 526 for( i = 0; a[i] && b[i] && case_map[a[i]] && case_map[b[i]]; i ++ ) 527 {528 if ( case_map[a[i]] == case_map[b[i]] )545 } 546 547 for (i = 0; a[i] && b[i] && case_map[a[i]] && case_map[b[i]]; i++) { 548 if (case_map[a[i]] == case_map[b[i]]) { 529 549 continue; 530 else550 } else { 531 551 return case_map[a[i]] - case_map[b[i]]; 532 } 533 552 } 553 } 554 534 555 return case_map[a[i]] - case_map[b[i]]; 535 556 } 536 557 537 static gint irc_channel_user_cmp( gconstpointer a_, gconstpointer b_)558 static gint irc_channel_user_cmp(gconstpointer a_, gconstpointer b_) 538 559 { 539 560 const irc_channel_user_t *a = a_, *b = b_; 540 541 return irc_user_cmp( a->iu, b->iu);542 } 543 544 void irc_channel_update_ops( irc_channel_t *ic, char *value)545 { 546 irc_channel_user_set_mode( 547 ( strcmp( value, "both") == 0 ||548 strcmp( value, "root" ) == 0 ) ? IRC_CHANNEL_USER_OP : 0);549 irc_channel_user_set_mode( 550 ( strcmp( value, "both") == 0 ||551 strcmp( value, "user" ) == 0 ) ? IRC_CHANNEL_USER_OP : 0);552 } 553 554 char *set_eval_irc_channel_ops( set_t *set, char *value)561 562 return irc_user_cmp(a->iu, b->iu); 563 } 564 565 void irc_channel_update_ops(irc_channel_t *ic, char *value) 566 { 567 irc_channel_user_set_mode(ic, ic->irc->root, 568 (strcmp(value, "both") == 0 || 569 strcmp(value, "root") == 0) ? IRC_CHANNEL_USER_OP : 0); 570 irc_channel_user_set_mode(ic, ic->irc->user, 571 (strcmp(value, "both") == 0 || 572 strcmp(value, "user") == 0) ? IRC_CHANNEL_USER_OP : 0); 573 } 574 575 char *set_eval_irc_channel_ops(set_t *set, char *value) 555 576 { 556 577 irc_t *irc = set->data; 557 578 GSList *l; 558 559 if ( strcmp( value, "both" ) != 0 && strcmp( value, "none" ) != 0 &&560 strcmp( value, "user" ) != 0 && strcmp( value, "root" ) != 0 )579 580 if (strcmp(value, "both") != 0 && strcmp(value, "none") != 0 && 581 strcmp(value, "user") != 0 && strcmp(value, "root") != 0) { 561 582 return SET_INVALID; 562 563 for( l = irc->channels; l; l = l->next ) 564 irc_channel_update_ops( l->data, value ); 565 583 } 584 585 for (l = irc->channels; l; l = l->next) { 586 irc_channel_update_ops(l->data, value); 587 } 588 566 589 return value; 567 590 } 568 591 569 592 /* Channel-type dependent functions, for control channels: */ 570 static gboolean control_channel_privmsg( irc_channel_t *ic, const char *msg)593 static gboolean control_channel_privmsg(irc_channel_t *ic, const char *msg) 571 594 { 572 595 irc_t *irc = ic->irc; 573 596 irc_user_t *iu; 574 597 const char *s; 575 598 576 599 /* Scan for non-whitespace chars followed by a colon: */ 577 for( s = msg; *s && !g_ascii_isspace( *s ) && *s != ':' && *s != ','; s ++ ) {} 578 579 if( *s == ':' || *s == ',' ) 580 { 581 char to[s-msg+1]; 582 583 memset( to, 0, sizeof( to ) ); 584 strncpy( to, msg, s - msg ); 585 while( *(++s) && g_ascii_isspace( *s ) ) {} 600 for (s = msg; *s && !g_ascii_isspace(*s) && *s != ':' && *s != ','; s++) { 601 } 602 603 if (*s == ':' || *s == ',') { 604 char to[s - msg + 1]; 605 606 memset(to, 0, sizeof(to)); 607 strncpy(to, msg, s - msg); 608 while (*(++s) && g_ascii_isspace(*s)) { 609 } 586 610 msg = s; 587 588 if ( !( iu = irc_user_by_name( irc, to ) ) )589 irc_channel_printf( ic, "User does not exist: %s", to);590 else611 612 if (!(iu = irc_user_by_name(irc, to))) { 613 irc_channel_printf(ic, "User does not exist: %s", to); 614 } else { 591 615 ic->last_target = iu; 592 }593 else if( g_strcasecmp( set_getstr( &irc->b->set, "default_target" ), "last") == 0 &&594 ic->last_target && g_slist_find( irc->users, ic->last_target ) )616 } 617 } else if (g_strcasecmp(set_getstr(&irc->b->set, "default_target"), "last") == 0 && 618 ic->last_target && g_slist_find(irc->users, ic->last_target)) { 595 619 iu = ic->last_target; 596 else620 } else { 597 621 iu = irc->root; 598 599 if( iu && iu->f->privmsg ) 600 {622 } 623 624 if (iu && iu->f->privmsg) { 601 625 iu->last_channel = ic; 602 iu->f->privmsg( iu, msg);603 } 604 626 iu->f->privmsg(iu, msg); 627 } 628 605 629 return TRUE; 606 630 } 607 631 608 static gboolean control_channel_invite( irc_channel_t *ic, irc_user_t *iu)632 static gboolean control_channel_invite(irc_channel_t *ic, irc_user_t *iu) 609 633 { 610 634 struct irc_control_channel *icc = ic->data; 611 635 bee_user_t *bu = iu->bu; 612 613 if ( bu == NULL )636 637 if (bu == NULL) { 614 638 return FALSE; 615 616 if( icc->type != IRC_CC_TYPE_GROUP ) 617 {618 irc_send_num( ic->irc, 482, "%s :Invitations are only possible to fill_by=group channels", ic->name);639 } 640 641 if (icc->type != IRC_CC_TYPE_GROUP) { 642 irc_send_num(ic->irc, 482, "%s :Invitations are only possible to fill_by=group channels", ic->name); 619 643 return FALSE; 620 644 } 621 622 bu->ic->acc->prpl->add_buddy( 623 icc->group ? icc->group->name : NULL);624 645 646 bu->ic->acc->prpl->add_buddy(bu->ic, bu->handle, 647 icc->group ? icc->group->name : NULL); 648 625 649 return TRUE; 626 650 } 627 651 628 static void control_channel_kick( irc_channel_t *ic, irc_user_t *iu, const char *msg)652 static void control_channel_kick(irc_channel_t *ic, irc_user_t *iu, const char *msg) 629 653 { 630 654 struct irc_control_channel *icc = ic->data; 631 655 bee_user_t *bu = iu->bu; 632 633 if ( bu == NULL )656 657 if (bu == NULL) { 634 658 return; 635 636 if( icc->type != IRC_CC_TYPE_GROUP ) 637 {638 irc_send_num( ic->irc, 482, "%s :Kicks are only possible to fill_by=group channels", ic->name);659 } 660 661 if (icc->type != IRC_CC_TYPE_GROUP) { 662 irc_send_num(ic->irc, 482, "%s :Kicks are only possible to fill_by=group channels", ic->name); 639 663 return; 640 664 } 641 642 bu->ic->acc->prpl->remove_buddy( 643 icc->group ? icc->group->name : NULL);644 } 645 646 static char *set_eval_by_account( set_t *set, char *value);647 static char *set_eval_fill_by( set_t *set, char *value);648 static char *set_eval_by_group( set_t *set, char *value);649 static char *set_eval_by_protocol( set_t *set, char *value);650 static char *set_eval_show_users( set_t *set, char *value);651 652 static gboolean control_channel_init( irc_channel_t *ic)665 666 bu->ic->acc->prpl->remove_buddy(bu->ic, bu->handle, 667 icc->group ? icc->group->name : NULL); 668 } 669 670 static char *set_eval_by_account(set_t *set, char *value); 671 static char *set_eval_fill_by(set_t *set, char *value); 672 static char *set_eval_by_group(set_t *set, char *value); 673 static char *set_eval_by_protocol(set_t *set, char *value); 674 static char *set_eval_show_users(set_t *set, char *value); 675 676 static gboolean control_channel_init(irc_channel_t *ic) 653 677 { 654 678 struct irc_control_channel *icc; 655 656 set_add( &ic->set, "account", NULL, set_eval_by_account, ic);657 set_add( &ic->set, "fill_by", "all", set_eval_fill_by, ic);658 set_add( &ic->set, "group", NULL, set_eval_by_group, ic);659 set_add( &ic->set, "protocol", NULL, set_eval_by_protocol, ic);660 679 680 set_add(&ic->set, "account", NULL, set_eval_by_account, ic); 681 set_add(&ic->set, "fill_by", "all", set_eval_fill_by, ic); 682 set_add(&ic->set, "group", NULL, set_eval_by_group, ic); 683 set_add(&ic->set, "protocol", NULL, set_eval_by_protocol, ic); 684 661 685 /* When changing the default, also change it below. */ 662 set_add( &ic->set, "show_users", "online+,special%,away", set_eval_show_users, ic);663 664 ic->data = icc = g_new0( struct irc_control_channel, 1);686 set_add(&ic->set, "show_users", "online+,special%,away", set_eval_show_users, ic); 687 688 ic->data = icc = g_new0(struct irc_control_channel, 1); 665 689 icc->type = IRC_CC_TYPE_DEFAULT; 666 690 667 691 /* Have to run the evaluator to initialize icc->modes. */ 668 set_setstr( &ic->set, "show_users", "online+,special%,away");669 692 set_setstr(&ic->set, "show_users", "online+,special%,away"); 693 670 694 /* For scripts that care. */ 671 irc_channel_set_mode( ic, "+C");672 695 irc_channel_set_mode(ic, "+C"); 696 673 697 return TRUE; 674 698 } 675 699 676 static gboolean control_channel_join( irc_channel_t *ic)677 { 678 bee_irc_channel_update( ic->irc, ic, NULL);679 700 static gboolean control_channel_join(irc_channel_t *ic) 701 { 702 bee_irc_channel_update(ic->irc, ic, NULL); 703 680 704 return TRUE; 681 705 } 682 706 683 static char *set_eval_by_account( set_t *set, char *value)707 static char *set_eval_by_account(set_t *set, char *value) 684 708 { 685 709 struct irc_channel *ic = set->data; 686 710 struct irc_control_channel *icc = ic->data; 687 711 account_t *acc; 688 689 if ( !( acc = account_get( ic->irc->b, value ) ) )712 713 if (!(acc = account_get(ic->irc->b, value))) { 690 714 return SET_INVALID; 691 715 } 716 692 717 icc->account = acc; 693 if( ( icc->type & IRC_CC_TYPE_MASK ) == IRC_CC_TYPE_ACCOUNT ) 694 bee_irc_channel_update( ic->irc, ic, NULL ); 695 696 return g_strdup( acc->tag ); 697 } 698 699 static char *set_eval_fill_by( set_t *set, char *value ) 718 if ((icc->type & IRC_CC_TYPE_MASK) == IRC_CC_TYPE_ACCOUNT) { 719 bee_irc_channel_update(ic->irc, ic, NULL); 720 } 721 722 return g_strdup(acc->tag); 723 } 724 725 static char *set_eval_fill_by(set_t *set, char *value) 700 726 { 701 727 struct irc_channel *ic = set->data; 702 728 struct irc_control_channel *icc = ic->data; 703 729 char *s; 704 705 icc->type &= ~( IRC_CC_TYPE_MASK | IRC_CC_TYPE_INVERT);706 730 731 icc->type &= ~(IRC_CC_TYPE_MASK | IRC_CC_TYPE_INVERT); 732 707 733 s = value; 708 if( s[0] == '!' ) 709 { 734 if (s[0] == '!') { 710 735 icc->type |= IRC_CC_TYPE_INVERT; 711 s 712 } 713 714 if ( strcmp( s, "all" ) == 0 )736 s++; 737 } 738 739 if (strcmp(s, "all") == 0) { 715 740 icc->type |= IRC_CC_TYPE_DEFAULT; 716 else if( strcmp( s, "rest" ) == 0 )741 } else if (strcmp(s, "rest") == 0) { 717 742 icc->type |= IRC_CC_TYPE_REST; 718 else if( strcmp( s, "group" ) == 0 )743 } else if (strcmp(s, "group") == 0) { 719 744 icc->type |= IRC_CC_TYPE_GROUP; 720 else if( strcmp( s, "account" ) == 0 )745 } else if (strcmp(s, "account") == 0) { 721 746 icc->type |= IRC_CC_TYPE_ACCOUNT; 722 else if( strcmp( s, "protocol" ) == 0 )747 } else if (strcmp(s, "protocol") == 0) { 723 748 icc->type |= IRC_CC_TYPE_PROTOCOL; 724 else749 } else { 725 750 return SET_INVALID; 726 727 bee_irc_channel_update( ic->irc, ic, NULL ); 751 } 752 753 bee_irc_channel_update(ic->irc, ic, NULL); 728 754 return value; 729 755 } 730 756 731 static char *set_eval_by_group( set_t *set, char *value)757 static char *set_eval_by_group(set_t *set, char *value) 732 758 { 733 759 struct irc_channel *ic = set->data; 734 760 struct irc_control_channel *icc = ic->data; 735 736 icc->group = bee_group_by_name( ic->irc->b, value, TRUE ); 737 if( ( icc->type & IRC_CC_TYPE_MASK ) == IRC_CC_TYPE_GROUP ) 738 bee_irc_channel_update( ic->irc, ic, NULL ); 739 740 return g_strdup( icc->group->name ); 741 } 742 743 static char *set_eval_by_protocol( set_t *set, char *value ) 761 762 icc->group = bee_group_by_name(ic->irc->b, value, TRUE); 763 if ((icc->type & IRC_CC_TYPE_MASK) == IRC_CC_TYPE_GROUP) { 764 bee_irc_channel_update(ic->irc, ic, NULL); 765 } 766 767 return g_strdup(icc->group->name); 768 } 769 770 static char *set_eval_by_protocol(set_t *set, char *value) 744 771 { 745 772 struct irc_channel *ic = set->data; 746 773 struct irc_control_channel *icc = ic->data; 747 774 struct prpl *prpl; 748 749 if ( !( prpl = find_protocol( value ) ) )775 776 if (!(prpl = find_protocol(value))) { 750 777 return SET_INVALID; 751 778 } 779 752 780 icc->protocol = prpl; 753 if( ( icc->type & IRC_CC_TYPE_MASK ) == IRC_CC_TYPE_PROTOCOL ) 754 bee_irc_channel_update( ic->irc, ic, NULL ); 755 781 if ((icc->type & IRC_CC_TYPE_MASK) == IRC_CC_TYPE_PROTOCOL) { 782 bee_irc_channel_update(ic->irc, ic, NULL); 783 } 784 756 785 return value; 757 786 } 758 787 759 static char *set_eval_show_users( set_t *set, char *value)788 static char *set_eval_show_users(set_t *set, char *value) 760 789 { 761 790 struct irc_channel *ic = set->data; 762 791 struct irc_control_channel *icc = ic->data; 763 char **parts = g_strsplit( value, ",", 0), **part;792 char **parts = g_strsplit(value, ",", 0), **part; 764 793 char modes[5]; 765 766 memset( modes, 0, 5 ); 767 for( part = parts; *part; part ++ ) 768 { 794 795 memset(modes, 0, 5); 796 for (part = parts; *part; part++) { 769 797 char last, modechar = IRC_CHANNEL_USER_NONE; 770 771 if ( **part == '\0' )798 799 if (**part == '\0') { 772 800 goto fail; 773 774 last = (*part)[strlen(*part+1)]; 775 if( last == '+' ) 801 } 802 803 last = (*part)[strlen(*part + 1)]; 804 if (last == '+') { 776 805 modechar = IRC_CHANNEL_USER_VOICE; 777 else if( last == '%' )806 } else if (last == '%') { 778 807 modechar = IRC_CHANNEL_USER_HALFOP; 779 else if( last == '@' )808 } else if (last == '@') { 780 809 modechar = IRC_CHANNEL_USER_OP; 781 782 if( strncmp( *part, "offline", 7 ) == 0 ) 810 } 811 812 if (strncmp(*part, "offline", 7) == 0) { 783 813 modes[0] = modechar; 784 else if( strncmp( *part, "away", 4 ) == 0 )814 } else if (strncmp(*part, "away", 4) == 0) { 785 815 modes[1] = modechar; 786 else if( strncmp( *part, "special", 7 ) == 0 )816 } else if (strncmp(*part, "special", 7) == 0) { 787 817 modes[2] = modechar; 788 else if( strncmp( *part, "online", 6 ) == 0 )818 } else if (strncmp(*part, "online", 6) == 0) { 789 819 modes[3] = modechar; 790 else820 } else { 791 821 goto fail; 792 } 793 memcpy( icc->modes, modes, 5 ); 794 bee_irc_channel_update( ic->irc, ic, NULL ); 795 796 g_strfreev( parts ); 822 } 823 } 824 memcpy(icc->modes, modes, 5); 825 bee_irc_channel_update(ic->irc, ic, NULL); 826 827 g_strfreev(parts); 797 828 return value; 798 829 799 830 fail: 800 g_strfreev( parts);801 return SET_INVALID; 831 g_strfreev(parts); 832 return SET_INVALID; 802 833 } 803 834 … … 806 837 for control channels, but does *not* check if this channel is of that 807 838 type. Beware! */ 808 gboolean irc_channel_wants_user( irc_channel_t *ic, irc_user_t *iu)839 gboolean irc_channel_wants_user(irc_channel_t *ic, irc_user_t *iu) 809 840 { 810 841 struct irc_control_channel *icc = ic->data; 811 842 gboolean ret = FALSE; 812 813 if ( iu->bu == NULL )843 844 if (iu->bu == NULL) { 814 845 return FALSE; 815 816 switch( icc->type & IRC_CC_TYPE_MASK ) 817 {846 } 847 848 switch (icc->type & IRC_CC_TYPE_MASK) { 818 849 case IRC_CC_TYPE_GROUP: 819 850 ret = iu->bu->group == icc->group; … … 830 861 break; 831 862 } 832 833 if ( icc->type & IRC_CC_TYPE_INVERT )863 864 if (icc->type & IRC_CC_TYPE_INVERT) { 834 865 ret = !ret; 835 866 } 867 836 868 return ret; 837 869 } 838 870 839 static gboolean control_channel_free( irc_channel_t *ic)871 static gboolean control_channel_free(irc_channel_t *ic) 840 872 { 841 873 struct irc_control_channel *icc = ic->data; 842 843 set_del( &ic->set, "account");844 set_del( &ic->set, "fill_by");845 set_del( &ic->set, "group");846 set_del( &ic->set, "protocol");847 set_del( &ic->set, "show_users");848 849 g_free( icc);874 875 set_del(&ic->set, "account"); 876 set_del(&ic->set, "fill_by"); 877 set_del(&ic->set, "group"); 878 set_del(&ic->set, "protocol"); 879 set_del(&ic->set, "show_users"); 880 881 g_free(icc); 850 882 ic->data = NULL; 851 883 852 884 /* For scripts that care. */ 853 irc_channel_set_mode( ic, "-C");854 885 irc_channel_set_mode(ic, "-C"); 886 855 887 return TRUE; 856 888 } … … 863 895 control_channel_invite, 864 896 control_channel_kick, 865 897 866 898 control_channel_init, 867 899 control_channel_free,
Note: See TracChangeset
for help on using the changeset viewer.