summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bancache.cpp146
-rw-r--r--src/base.cpp42
-rw-r--r--src/channels.cpp839
-rw-r--r--src/cidr.cpp4
-rw-r--r--src/command_parse.cpp326
-rw-r--r--src/commands.cpp99
-rw-r--r--src/commands/cmd_clearcache.cpp52
-rw-r--r--src/commands/cmd_commands.cpp74
-rw-r--r--src/commands/cmd_connect.cpp55
-rw-r--r--src/commands/cmd_join.cpp74
-rw-r--r--src/commands/cmd_kick.cpp85
-rw-r--r--src/commands/cmd_links.cpp52
-rw-r--r--src/commands/cmd_loadmodule.cpp60
-rw-r--r--src/commands/cmd_map.cpp58
-rw-r--r--src/commands/cmd_mode.cpp53
-rw-r--r--src/commands/cmd_notice.cpp229
-rw-r--r--src/commands/cmd_oper.cpp105
-rw-r--r--src/commands/cmd_part.cpp78
-rw-r--r--src/commands/cmd_pass.cpp57
-rw-r--r--src/commands/cmd_ping.cpp49
-rw-r--r--src/commands/cmd_pong.cpp51
-rw-r--r--src/commands/cmd_privmsg.cpp237
-rw-r--r--src/commands/cmd_quit.cpp75
-rw-r--r--src/commands/cmd_rules.cpp76
-rw-r--r--src/commands/cmd_server.cpp56
-rw-r--r--src/commands/cmd_squit.cpp55
-rw-r--r--src/commands/cmd_stats.cpp433
-rw-r--r--src/commands/cmd_time.cpp67
-rw-r--r--src/commands/cmd_topic.cpp88
-rw-r--r--src/commands/cmd_unloadmodule.cpp67
-rw-r--r--src/commands/cmd_version.cpp51
-rw-r--r--src/commands/cmd_whois.cpp98
-rw-r--r--src/commands/cmd_whowas.cpp348
-rw-r--r--src/configparser.cpp136
-rw-r--r--src/configreader.cpp445
-rw-r--r--src/coremods/core_channel/cmd_invite.cpp (renamed from src/commands/cmd_invite.cpp)82
-rw-r--r--src/coremods/core_channel/cmd_join.cpp60
-rw-r--r--src/coremods/core_channel/cmd_kick.cpp128
-rw-r--r--src/coremods/core_channel/cmd_names.cpp (renamed from src/commands/cmd_names.cpp)49
-rw-r--r--src/coremods/core_channel/cmd_topic.cpp86
-rw-r--r--src/coremods/core_channel/core_channel.cpp (renamed from src/modules/account.h)37
-rw-r--r--src/coremods/core_channel/core_channel.h114
-rw-r--r--src/coremods/core_dns.cpp833
-rw-r--r--src/coremods/core_hostname_lookup.cpp233
-rw-r--r--src/coremods/core_info/cmd_admin.cpp (renamed from src/commands/cmd_admin.cpp)50
-rw-r--r--src/coremods/core_info/cmd_commands.cpp53
-rw-r--r--src/coremods/core_info/cmd_info.cpp (renamed from src/commands/cmd_info.cpp)44
-rw-r--r--src/coremods/core_info/cmd_modules.cpp (renamed from src/commands/cmd_modules.cpp)71
-rw-r--r--src/coremods/core_info/cmd_motd.cpp (renamed from src/commands/cmd_motd.cpp)41
-rw-r--r--src/coremods/core_info/cmd_time.cpp46
-rw-r--r--src/coremods/core_info/cmd_version.cpp (renamed from src/modules/spanningtree.h)33
-rw-r--r--src/coremods/core_info/core_info.cpp53
-rw-r--r--src/coremods/core_info/core_info.h161
-rw-r--r--src/coremods/core_ison.cpp (renamed from src/commands/cmd_ison.cpp)78
-rw-r--r--src/coremods/core_list.cpp (renamed from src/commands/cmd_list.cpp)48
-rw-r--r--src/coremods/core_loadmodule.cpp126
-rw-r--r--src/coremods/core_lusers.cpp (renamed from src/commands/cmd_lusers.cpp)68
-rw-r--r--src/coremods/core_oper/cmd_die.cpp (renamed from src/commands/cmd_die.cpp)35
-rw-r--r--src/coremods/core_oper/cmd_kill.cpp (renamed from src/commands/cmd_kill.cpp)102
-rw-r--r--src/coremods/core_oper/cmd_oper.cpp72
-rw-r--r--src/coremods/core_oper/cmd_rehash.cpp (renamed from src/commands/cmd_rehash.cpp)49
-rw-r--r--src/coremods/core_oper/cmd_restart.cpp (renamed from src/commands/cmd_restart.cpp)28
-rw-r--r--src/coremods/core_oper/core_oper.cpp55
-rw-r--r--src/coremods/core_oper/core_oper.h124
-rw-r--r--src/coremods/core_privmsg.cpp296
-rw-r--r--src/coremods/core_reloadmodule.cpp (renamed from src/commands/cmd_reloadmodule.cpp)17
-rw-r--r--src/coremods/core_stats.cpp393
-rw-r--r--src/coremods/core_stub.cpp156
-rw-r--r--src/coremods/core_user/cmd_away.cpp (renamed from src/commands/cmd_away.cpp)32
-rw-r--r--src/coremods/core_user/cmd_nick.cpp (renamed from src/commands/cmd_nick.cpp)74
-rw-r--r--src/coremods/core_user/cmd_part.cpp63
-rw-r--r--src/coremods/core_user/cmd_quit.cpp50
-rw-r--r--src/coremods/core_user/cmd_user.cpp (renamed from src/commands/cmd_user.cpp)45
-rw-r--r--src/coremods/core_user/core_user.cpp191
-rw-r--r--src/coremods/core_user/core_user.h147
-rw-r--r--src/coremods/core_userhost.cpp (renamed from src/commands/cmd_userhost.cpp)41
-rw-r--r--src/coremods/core_wallops.cpp (renamed from src/commands/cmd_wallops.cpp)32
-rw-r--r--src/coremods/core_who.cpp (renamed from src/commands/cmd_who.cpp)128
-rw-r--r--src/coremods/core_whois.cpp244
-rw-r--r--src/coremods/core_whowas.cpp291
-rw-r--r--src/coremods/core_xline/cmd_eline.cpp (renamed from src/commands/cmd_eline.cpp)48
-rw-r--r--src/coremods/core_xline/cmd_gline.cpp (renamed from src/commands/cmd_gline.cpp)43
-rw-r--r--src/coremods/core_xline/cmd_kline.cpp (renamed from src/commands/cmd_kline.cpp)43
-rw-r--r--src/coremods/core_xline/cmd_qline.cpp (renamed from src/commands/cmd_qline.cpp)41
-rw-r--r--src/coremods/core_xline/cmd_zline.cpp (renamed from src/commands/cmd_zline.cpp)45
-rw-r--r--src/coremods/core_xline/core_xline.cpp93
-rw-r--r--src/coremods/core_xline/core_xline.h164
-rw-r--r--src/cull_list.cpp6
-rw-r--r--src/dns.cpp1110
-rw-r--r--src/dynamic.cpp2
-rw-r--r--src/filelogger.cpp20
-rw-r--r--src/fileutils.cpp102
-rw-r--r--src/hashcomp.cpp417
-rw-r--r--src/helperfuncs.cpp235
-rw-r--r--src/inspircd.cpp394
-rw-r--r--src/inspsocket.cpp119
-rw-r--r--src/inspstring.cpp148
-rw-r--r--src/listensocket.cpp102
-rw-r--r--src/listmode.cpp222
-rw-r--r--src/logger.cpp101
-rw-r--r--src/mode.cpp685
-rw-r--r--src/modes/cmode_b.cpp178
-rw-r--r--src/modes/cmode_k.cpp72
-rw-r--r--src/modes/cmode_l.cpp22
-rw-r--r--src/modes/cmode_o.cpp45
-rw-r--r--src/modes/cmode_v.cpp45
-rw-r--r--src/modes/umode_o.cpp10
-rw-r--r--src/modes/umode_s.cpp112
-rw-r--r--src/modmanager_dynamic.cpp172
-rw-r--r--src/modmanager_static.cpp147
-rw-r--r--src/modules.cpp689
-rw-r--r--src/modules/extra/m_geoip.cpp25
-rw-r--r--src/modules/extra/m_ldap.cpp628
-rw-r--r--src/modules/extra/m_ldapauth.cpp436
-rw-r--r--src/modules/extra/m_ldapoper.cpp255
-rw-r--r--src/modules/extra/m_mssql.cpp73
-rw-r--r--src/modules/extra/m_mysql.cpp36
-rw-r--r--src/modules/extra/m_pgsql.cpp68
-rw-r--r--src/modules/extra/m_regex_pcre.cpp41
-rw-r--r--src/modules/extra/m_regex_posix.cpp46
-rw-r--r--src/modules/extra/m_regex_re2.cpp81
-rw-r--r--src/modules/extra/m_regex_stdlib.cpp45
-rw-r--r--src/modules/extra/m_regex_tre.cpp43
-rw-r--r--src/modules/extra/m_sqlite3.cpp55
-rw-r--r--src/modules/extra/m_ssl_gnutls.cpp1377
-rw-r--r--src/modules/extra/m_ssl_openssl.cpp857
-rw-r--r--src/modules/hash.h76
-rw-r--r--src/modules/httpd.h207
-rw-r--r--src/modules/m_abbreviation.cpp35
-rw-r--r--src/modules/m_alias.cpp120
-rw-r--r--src/modules/m_allowinvite.cpp25
-rw-r--r--src/modules/m_alltime.cpp19
-rw-r--r--src/modules/m_auditorium.cpp88
-rw-r--r--src/modules/m_autoop.cpp62
-rw-r--r--src/modules/m_banexception.cpp79
-rw-r--r--src/modules/m_banredirect.cpp106
-rw-r--r--src/modules/m_blockamsg.cpp23
-rw-r--r--src/modules/m_blockcaps.cpp80
-rw-r--r--src/modules/m_blockcolor.cpp30
-rw-r--r--src/modules/m_botmode.cpp23
-rw-r--r--src/modules/m_callerid.cpp251
-rw-r--r--src/modules/m_cap.cpp49
-rw-r--r--src/modules/m_cap.h92
-rw-r--r--src/modules/m_cban.cpp49
-rw-r--r--src/modules/m_censor.cpp39
-rw-r--r--src/modules/m_cgiirc.cpp134
-rw-r--r--src/modules/m_chancreate.cpp12
-rw-r--r--src/modules/m_chanfilter.cpp78
-rw-r--r--src/modules/m_chanhistory.cpp124
-rw-r--r--src/modules/m_chanlog.cpp87
-rw-r--r--src/modules/m_channames.cpp87
-rw-r--r--src/modules/m_channelban.cpp35
-rw-r--r--src/modules/m_chanprotect.cpp308
-rw-r--r--src/modules/m_check.cpp132
-rw-r--r--src/modules/m_chghost.cpp35
-rw-r--r--src/modules/m_chgident.cpp30
-rw-r--r--src/modules/m_chgname.cpp25
-rw-r--r--src/modules/m_clearchan.cpp218
-rw-r--r--src/modules/m_cloaking.cpp215
-rw-r--r--src/modules/m_clones.cpp26
-rw-r--r--src/modules/m_close.cpp28
-rw-r--r--src/modules/m_commonchans.cpp27
-rw-r--r--src/modules/m_conn_join.cpp106
-rw-r--r--src/modules/m_conn_umodes.cpp35
-rw-r--r--src/modules/m_conn_waitpong.cpp27
-rw-r--r--src/modules/m_connectban.cpp56
-rw-r--r--src/modules/m_connflood.cpp22
-rw-r--r--src/modules/m_customprefix.cpp74
-rw-r--r--src/modules/m_customtitle.cpp49
-rw-r--r--src/modules/m_cycle.cpp50
-rw-r--r--src/modules/m_dccallow.cpp154
-rw-r--r--src/modules/m_deaf.cpp106
-rw-r--r--src/modules/m_delayjoin.cpp70
-rw-r--r--src/modules/m_delaymsg.cpp87
-rw-r--r--src/modules/m_denychans.cpp41
-rw-r--r--src/modules/m_devoice.cpp32
-rw-r--r--src/modules/m_dnsbl.cpp342
-rw-r--r--src/modules/m_exemptchanops.cpp60
-rw-r--r--src/modules/m_filter.cpp198
-rw-r--r--src/modules/m_flashpolicyd.cpp158
-rw-r--r--src/modules/m_gecosban.cpp20
-rw-r--r--src/modules/m_globalload.cpp38
-rw-r--r--src/modules/m_globops.cpp9
-rw-r--r--src/modules/m_halfop.cpp104
-rw-r--r--src/modules/m_helpop.cpp69
-rw-r--r--src/modules/m_hidechans.cpp23
-rw-r--r--src/modules/m_hideoper.cpp39
-rw-r--r--src/modules/m_hostchange.cpp22
-rw-r--r--src/modules/m_hostcycle.cpp114
-rw-r--r--src/modules/m_httpd.cpp69
-rw-r--r--src/modules/m_httpd_acl.cpp50
-rw-r--r--src/modules/m_httpd_config.cpp26
-rw-r--r--src/modules/m_httpd_stats.cpp79
-rw-r--r--src/modules/m_ident.cpp120
-rw-r--r--src/modules/m_inviteexception.cpp36
-rw-r--r--src/modules/m_ircv3.cpp49
-rw-r--r--src/modules/m_joinflood.cpp169
-rw-r--r--src/modules/m_jumpserver.cpp84
-rw-r--r--src/modules/m_kicknorejoin.cpp110
-rw-r--r--src/modules/m_knock.cpp53
-rw-r--r--src/modules/m_ldapauth.cpp434
-rw-r--r--src/modules/m_ldapoper.cpp248
-rw-r--r--src/modules/m_lockserv.cpp44
-rw-r--r--src/modules/m_maphide.cpp24
-rw-r--r--src/modules/m_md5.cpp21
-rw-r--r--src/modules/m_messageflood.cpp113
-rw-r--r--src/modules/m_mlock.cpp18
-rw-r--r--src/modules/m_modenotice.cpp (renamed from src/commands/cmd_modenotice.cpp)27
-rw-r--r--src/modules/m_muteban.cpp30
-rw-r--r--src/modules/m_namedmodes.cpp93
-rw-r--r--src/modules/m_namesx.cpp57
-rw-r--r--src/modules/m_nationalchars.cpp48
-rw-r--r--src/modules/m_nickflood.cpp98
-rw-r--r--src/modules/m_nicklock.cpp43
-rw-r--r--src/modules/m_noctcp.cpp32
-rw-r--r--src/modules/m_nokicks.cpp26
-rw-r--r--src/modules/m_nonicks.cpp44
-rw-r--r--src/modules/m_nonotice.cpp27
-rw-r--r--src/modules/m_nopartmsg.cpp26
-rw-r--r--src/modules/m_ojoin.cpp151
-rw-r--r--src/modules/m_operchans.cpp31
-rw-r--r--src/modules/m_operjoin.cpp70
-rw-r--r--src/modules/m_operlevels.cpp18
-rw-r--r--src/modules/m_operlog.cpp33
-rw-r--r--src/modules/m_opermodes.cpp17
-rw-r--r--src/modules/m_opermotd.cpp28
-rw-r--r--src/modules/m_operprefix.cpp107
-rw-r--r--src/modules/m_override.cpp128
-rw-r--r--src/modules/m_passforward.cpp32
-rw-r--r--src/modules/m_password_hash.cpp38
-rw-r--r--src/modules/m_permchannels.cpp308
-rw-r--r--src/modules/m_randquote.cpp73
-rw-r--r--src/modules/m_redirect.cpp132
-rw-r--r--src/modules/m_regex.h58
-rw-r--r--src/modules/m_regex_glob.cpp19
-rw-r--r--src/modules/m_regonlycreate.cpp25
-rw-r--r--src/modules/m_remove.cpp120
-rw-r--r--src/modules/m_repeat.cpp403
-rw-r--r--src/modules/m_restrictchans.cpp39
-rw-r--r--src/modules/m_restrictmsg.cpp29
-rw-r--r--src/modules/m_ripemd160.cpp29
-rw-r--r--src/modules/m_rline.cpp60
-rw-r--r--src/modules/m_rmode.cpp117
-rw-r--r--src/modules/m_sajoin.cpp79
-rw-r--r--src/modules/m_sakick.cpp51
-rw-r--r--src/modules/m_samode.cpp25
-rw-r--r--src/modules/m_sanick.cpp28
-rw-r--r--src/modules/m_sapart.cpp55
-rw-r--r--src/modules/m_saquit.cpp24
-rw-r--r--src/modules/m_sasl.cpp54
-rw-r--r--src/modules/m_satopic.cpp21
-rw-r--r--src/modules/m_securelist.cpp33
-rw-r--r--src/modules/m_seenicks.cpp10
-rw-r--r--src/modules/m_serverban.cpp25
-rw-r--r--src/modules/m_services_account.cpp175
-rw-r--r--src/modules/m_servprotect.cpp49
-rw-r--r--src/modules/m_sethost.cpp31
-rw-r--r--src/modules/m_setident.cpp25
-rw-r--r--src/modules/m_setidle.cpp26
-rw-r--r--src/modules/m_setname.cpp18
-rw-r--r--src/modules/m_sha256.cpp19
-rw-r--r--src/modules/m_showfile.cpp169
-rw-r--r--src/modules/m_showwhois.cpp49
-rw-r--r--src/modules/m_shun.cpp53
-rw-r--r--src/modules/m_silence.cpp79
-rw-r--r--src/modules/m_spanningtree/addline.cpp62
-rw-r--r--src/modules/m_spanningtree/away.cpp34
-rw-r--r--src/modules/m_spanningtree/cachetimer.cpp41
-rw-r--r--src/modules/m_spanningtree/cachetimer.h16
-rw-r--r--src/modules/m_spanningtree/capab.cpp113
-rw-r--r--src/modules/m_spanningtree/commandbuilder.h147
-rw-r--r--src/modules/m_spanningtree/commands.h359
-rw-r--r--src/modules/m_spanningtree/compat.cpp519
-rw-r--r--src/modules/m_spanningtree/delline.cpp30
-rw-r--r--src/modules/m_spanningtree/encap.cpp36
-rw-r--r--src/modules/m_spanningtree/fjoin.cpp307
-rw-r--r--src/modules/m_spanningtree/fmode.cpp83
-rw-r--r--src/modules/m_spanningtree/ftopic.cpp90
-rw-r--r--src/modules/m_spanningtree/hmac.cpp90
-rw-r--r--src/modules/m_spanningtree/idle.cpp100
-rw-r--r--src/modules/m_spanningtree/ijoin.cpp77
-rw-r--r--src/modules/m_spanningtree/link.h7
-rw-r--r--src/modules/m_spanningtree/main.cpp699
-rw-r--r--src/modules/m_spanningtree/main.h120
-rw-r--r--src/modules/m_spanningtree/metadata.cpp71
-rw-r--r--src/modules/m_spanningtree/misccommands.cpp48
-rw-r--r--src/modules/m_spanningtree/netburst.cpp371
-rw-r--r--src/modules/m_spanningtree/nick.cpp63
-rw-r--r--src/modules/m_spanningtree/nickcollide.cpp22
-rw-r--r--src/modules/m_spanningtree/operquit.cpp45
-rw-r--r--src/modules/m_spanningtree/opertype.cpp27
-rw-r--r--src/modules/m_spanningtree/override_map.cpp276
-rw-r--r--src/modules/m_spanningtree/override_squit.cpp17
-rw-r--r--src/modules/m_spanningtree/override_stats.cpp21
-rw-r--r--src/modules/m_spanningtree/override_whois.cpp20
-rw-r--r--src/modules/m_spanningtree/ping.cpp46
-rw-r--r--src/modules/m_spanningtree/pong.cpp65
-rw-r--r--src/modules/m_spanningtree/postcommand.cpp104
-rw-r--r--src/modules/m_spanningtree/precommand.cpp17
-rw-r--r--src/modules/m_spanningtree/protocolinterface.cpp172
-rw-r--r--src/modules/m_spanningtree/protocolinterface.h44
-rw-r--r--src/modules/m_spanningtree/push.cpp24
-rw-r--r--src/modules/m_spanningtree/rconnect.cpp36
-rw-r--r--src/modules/m_spanningtree/resolvers.cpp81
-rw-r--r--src/modules/m_spanningtree/resolvers.h30
-rw-r--r--src/modules/m_spanningtree/rsquit.cpp46
-rw-r--r--src/modules/m_spanningtree/save.cpp30
-rw-r--r--src/modules/m_spanningtree/server.cpp76
-rw-r--r--src/modules/m_spanningtree/servercommand.cpp57
-rw-r--r--src/modules/m_spanningtree/servercommand.h100
-rw-r--r--src/modules/m_spanningtree/sinfo.cpp51
-rw-r--r--src/modules/m_spanningtree/svsjoin.cpp15
-rw-r--r--src/modules/m_spanningtree/svsnick.cpp43
-rw-r--r--src/modules/m_spanningtree/svspart.cpp8
-rw-r--r--src/modules/m_spanningtree/treeserver.cpp189
-rw-r--r--src/modules/m_spanningtree/treeserver.h110
-rw-r--r--src/modules/m_spanningtree/treesocket.h124
-rw-r--r--src/modules/m_spanningtree/treesocket1.cpp129
-rw-r--r--src/modules/m_spanningtree/treesocket2.cpp329
-rw-r--r--src/modules/m_spanningtree/uid.cpp158
-rw-r--r--src/modules/m_spanningtree/utils.cpp198
-rw-r--r--src/modules/m_spanningtree/utils.h50
-rw-r--r--src/modules/m_spanningtree/version.cpp47
-rw-r--r--src/modules/m_sqlauth.cpp32
-rw-r--r--src/modules/m_sqloper.cpp72
-rw-r--r--src/modules/m_sslinfo.cpp111
-rw-r--r--src/modules/m_sslmodes.cpp77
-rw-r--r--src/modules/m_starttls.cpp121
-rw-r--r--src/modules/m_stripcolor.cpp31
-rw-r--r--src/modules/m_svshold.cpp52
-rw-r--r--src/modules/m_swhois.cpp30
-rw-r--r--src/modules/m_testnet.cpp170
-rw-r--r--src/modules/m_timedbans.cpp76
-rw-r--r--src/modules/m_tline.cpp34
-rw-r--r--src/modules/m_topiclock.cpp21
-rw-r--r--src/modules/m_uhnames.cpp35
-rw-r--r--src/modules/m_uninvite.cpp32
-rw-r--r--src/modules/m_userip.cpp27
-rw-r--r--src/modules/m_vhost.cpp25
-rw-r--r--src/modules/m_watch.cpp98
-rw-r--r--src/modules/m_xline_db.cpp121
-rw-r--r--src/modules/sasl.h34
-rw-r--r--src/modules/sql.h187
-rw-r--r--src/modules/ssl.h175
-rw-r--r--src/modules/u_listmode.h423
-rw-r--r--src/server.cpp214
-rw-r--r--src/snomasks.cpp151
-rw-r--r--src/socket.cpp48
-rw-r--r--src/socketengine.cpp108
-rw-r--r--src/socketengines/socketengine_epoll.cpp174
-rw-r--r--src/socketengines/socketengine_kqueue.cpp202
-rw-r--r--src/socketengines/socketengine_poll.cpp244
-rw-r--r--src/socketengines/socketengine_ports.cpp175
-rw-r--r--src/socketengines/socketengine_select.cpp141
-rw-r--r--src/testsuite.cpp55
-rw-r--r--src/threadengine.cpp18
-rw-r--r--src/threadengines/threadengine_pthread.cpp34
-rw-r--r--src/threadengines/threadengine_win32.cpp27
-rw-r--r--src/timer.cpp62
-rw-r--r--src/user_resolver.cpp144
-rw-r--r--src/usermanager.cpp360
-rw-r--r--src/userprocess.cpp121
-rw-r--r--src/users.cpp934
-rwxr-xr-xsrc/version.sh2
-rw-r--r--src/whois.cpp97
-rw-r--r--src/wildcard.cpp46
-rw-r--r--src/xline.cpp122
367 files changed, 18705 insertions, 23345 deletions
diff --git a/src/bancache.cpp b/src/bancache.cpp
index 52449e55e..13e4dc7c7 100644
--- a/src/bancache.cpp
+++ b/src/bancache.cpp
@@ -18,155 +18,89 @@
*/
-/* $Core */
-
#include "inspircd.h"
-#include "bancache.h"
-BanCacheHit *BanCacheManager::AddHit(const std::string &ip, const std::string &type, const std::string &reason)
+BanCacheHit::BanCacheHit(const std::string& type, const std::string& reason, time_t seconds)
+ : Type(type)
+ , Reason(reason)
+ , Expiry(ServerInstance->Time() + seconds)
{
- BanCacheHit *b;
-
- if (this->BanHash->find(ip) != this->BanHash->end()) // can't have two cache entries on the same IP, sorry..
- return NULL;
-
- b = new BanCacheHit(ip, type, reason);
-
- this->BanHash->insert(std::make_pair(ip, b));
- return b;
}
BanCacheHit *BanCacheManager::AddHit(const std::string &ip, const std::string &type, const std::string &reason, time_t seconds)
{
- BanCacheHit *b;
-
- if (this->BanHash->find(ip) != this->BanHash->end()) // can't have two cache entries on the same IP, sorry..
+ BanCacheHit*& b = BanHash[ip];
+ if (b != NULL) // can't have two cache entries on the same IP, sorry..
return NULL;
- b = new BanCacheHit(ip, type, reason, seconds);
-
- this->BanHash->insert(std::make_pair(ip, b));
+ b = new BanCacheHit(type, reason, (seconds ? seconds : 86400));
return b;
}
BanCacheHit *BanCacheManager::GetHit(const std::string &ip)
{
- BanCacheHash::iterator i = this->BanHash->find(ip);
+ BanCacheHash::iterator i = this->BanHash.find(ip);
- if (i == this->BanHash->end())
+ if (i == this->BanHash.end())
return NULL; // free and safe
- else
- {
- if (ServerInstance->Time() > i->second->Expiry)
- {
- ServerInstance->Logs->Log("BANCACHE", DEBUG, "Hit on " + ip + " is out of date, removing!");
- RemoveHit(i->second);
- return NULL; // out of date
- }
- return i->second; // hit.
- }
+ if (RemoveIfExpired(i))
+ return NULL; // expired
+
+ return i->second; // hit.
}
-bool BanCacheManager::RemoveHit(BanCacheHit *b)
+bool BanCacheManager::RemoveIfExpired(BanCacheHash::iterator& it)
{
- BanCacheHash::iterator i;
-
- if (!b)
- return false; // I don't think so.
-
- i = this->BanHash->find(b->IP);
-
- if (i == this->BanHash->end())
- {
- // err..
- ServerInstance->Logs->Log("BANCACHE", DEBUG, "BanCacheManager::RemoveHit(): I got asked to remove a hit that wasn't in the hash(?)");
- }
- else
- {
- this->BanHash->erase(i);
- }
+ if (ServerInstance->Time() < it->second->Expiry)
+ return false;
- delete b;
+ ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "Hit on " + it->first + " is out of date, removing!");
+ delete it->second;
+ it = BanHash.erase(it);
return true;
}
-unsigned int BanCacheManager::RemoveEntries(const std::string &type, bool positive)
+void BanCacheManager::RemoveEntries(const std::string& type, bool positive)
{
- int removed = 0;
-
- BanCacheHash::iterator safei;
-
if (positive)
- ServerInstance->Logs->Log("BANCACHE", DEBUG, "BanCacheManager::RemoveEntries(): Removing positive hits for " + type);
+ ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "BanCacheManager::RemoveEntries(): Removing positive hits for " + type);
else
- ServerInstance->Logs->Log("BANCACHE", DEBUG, "BanCacheManager::RemoveEntries(): Removing negative hits for " + type);
+ ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "BanCacheManager::RemoveEntries(): Removing all negative hits");
- for (BanCacheHash::iterator n = BanHash->begin(); n != BanHash->end(); )
+ for (BanCacheHash::iterator i = BanHash.begin(); i != BanHash.end(); )
{
- safei = n;
- safei++;
+ if (RemoveIfExpired(i))
+ continue; // updates the iterator if expired
- BanCacheHit *b = n->second;
+ BanCacheHit* b = i->second;
+ bool remove = false;
- /* Safe to delete items here through iterator 'n' */
- if (b->Type == type || !positive) // if removing negative hits, ignore type..
+ if (positive)
{
- if ((positive && !b->Reason.empty()) || b->Reason.empty())
- {
- /* we need to remove this one. */
- ServerInstance->Logs->Log("BANCACHE", DEBUG, "BanCacheManager::RemoveEntries(): Removing a hit on " + b->IP);
- delete b;
- BanHash->erase(n); // WORD TO THE WISE: don't use RemoveHit here, because we MUST remove the iterator in a safe way.
- removed++;
- }
+ // when removing positive hits, remove only if the type matches
+ remove = b->IsPositive() && (b->Type == type);
+ }
+ else
+ {
+ // when removing negative hits, remove all of them
+ remove = !b->IsPositive();
}
- /* End of safe section */
- n = safei;
- }
-
-
- return removed;
-}
-
-void BanCacheManager::RehashCache()
-{
- BanCacheHash* NewHash = new BanCacheHash();
-
- BanCacheHash::iterator safei;
- for (BanCacheHash::iterator n = BanHash->begin(); n != BanHash->end(); )
- {
- safei = n;
- safei++;
-
- /* Safe to delete items here through iterator 'n' */
- BanCacheHit *b = n->second;
-
- if (ServerInstance->Time() > b->Expiry)
+ if (remove)
{
/* we need to remove this one. */
+ ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "BanCacheManager::RemoveEntries(): Removing a hit on " + i->first);
delete b;
- BanHash->erase(n); // WORD TO THE WISE: don't use RemoveHit here, because we MUST remove the iterator in a safe way.
+ i = BanHash.erase(i);
}
else
- {
- /* Actually inserts a std::pair */
- NewHash->insert(*n);
- }
-
- /* End of safe section */
-
- n = safei;
+ ++i;
}
-
- delete BanHash;
- BanHash = NewHash;
}
BanCacheManager::~BanCacheManager()
{
- for (BanCacheHash::iterator n = BanHash->begin(); n != BanHash->end(); ++n)
+ for (BanCacheHash::iterator n = BanHash.begin(); n != BanHash.end(); ++n)
delete n->second;
- delete BanHash;
}
diff --git a/src/base.cpp b/src/base.cpp
index 66a3cb140..c131f4dae 100644
--- a/src/base.cpp
+++ b/src/base.cpp
@@ -27,22 +27,22 @@
classbase::classbase()
{
- if (ServerInstance && ServerInstance->Logs)
- ServerInstance->Logs->Log("CULLLIST", DEBUG, "classbase::+ @%p", (void*)this);
+ if (ServerInstance)
+ ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "classbase::+ @%p", (void*)this);
}
CullResult classbase::cull()
{
- if (ServerInstance && ServerInstance->Logs)
- ServerInstance->Logs->Log("CULLLIST", DEBUG, "classbase::-%s @%p",
+ if (ServerInstance)
+ ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "classbase::-%s @%p",
typeid(*this).name(), (void*)this);
return CullResult();
}
classbase::~classbase()
{
- if (ServerInstance && ServerInstance->Logs)
- ServerInstance->Logs->Log("CULLLIST", DEBUG, "classbase::~ @%p", (void*)this);
+ if (ServerInstance)
+ ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "classbase::~ @%p", (void*)this);
}
CullResult::CullResult()
@@ -73,15 +73,15 @@ refcountbase::refcountbase() : refcount(0)
refcountbase::~refcountbase()
{
- if (refcount && ServerInstance && ServerInstance->Logs)
- ServerInstance->Logs->Log("CULLLIST", DEBUG, "refcountbase::~ @%p with refcount %d",
+ if (refcount && ServerInstance)
+ ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "refcountbase::~ @%p with refcount %d",
(void*)this, refcount);
}
usecountbase::~usecountbase()
{
- if (usecount && ServerInstance && ServerInstance->Logs)
- ServerInstance->Logs->Log("CULLLIST", DEBUG, "usecountbase::~ @%p with refcount %d",
+ if (usecount && ServerInstance)
+ ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "usecountbase::~ @%p with refcount %d",
(void*)this, usecount);
}
@@ -174,32 +174,31 @@ void Extensible::doUnhookExtensions(const std::vector<reference<ExtensionItem> >
}
}
-static struct DummyExtensionItem : LocalExtItem
-{
- DummyExtensionItem() : LocalExtItem("", NULL) {}
- void free(void*) {}
-} dummy;
-
Extensible::Extensible()
+ : culled(false)
{
- extensions[&dummy] = NULL;
}
CullResult Extensible::cull()
{
+ FreeAllExtItems();
+ culled = true;
+ return classbase::cull();
+}
+
+void Extensible::FreeAllExtItems()
+{
for(ExtensibleStore::iterator i = extensions.begin(); i != extensions.end(); ++i)
{
i->first->free(i->second);
}
extensions.clear();
- return classbase::cull();
}
Extensible::~Extensible()
{
- if (!extensions.empty() && ServerInstance && ServerInstance->Logs)
- ServerInstance->Logs->Log("CULLLIST", DEBUG,
- "Extensible destructor called without cull @%p", (void*)this);
+ if ((!extensions.empty() || !culled) && ServerInstance)
+ ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "Extensible destructor called without cull @%p", (void*)this);
}
LocalExtItem::LocalExtItem(const std::string& Key, Module* mod) : ExtensionItem(Key, mod)
@@ -312,4 +311,3 @@ ModuleException::ModuleException(const std::string &message, Module* who)
: CoreException(message, who ? who->ModuleSourceFile : "A Module")
{
}
-
diff --git a/src/channels.cpp b/src/channels.cpp
index 6c9bd7c85..13595c4c3 100644
--- a/src/channels.cpp
+++ b/src/channels.cpp
@@ -23,172 +23,103 @@
*/
-/* $Core */
-
#include "inspircd.h"
-#include <cstdarg>
-#include "mode.h"
+#include "listmode.h"
-Channel::Channel(const std::string &cname, time_t ts)
+namespace
{
- if (!ServerInstance->chanlist->insert(std::make_pair(cname, this)).second)
- throw CoreException("Cannot create duplicate channel " + cname);
-
- this->name = cname;
- this->age = ts ? ts : ServerInstance->Time();
-
- maxbans = topicset = 0;
- modes.reset();
+ ChanModeReference ban(NULL, "ban");
+ ChanModeReference inviteonlymode(NULL, "inviteonly");
+ ChanModeReference keymode(NULL, "key");
+ ChanModeReference limitmode(NULL, "limit");
+ ChanModeReference secretmode(NULL, "secret");
+ ChanModeReference privatemode(NULL, "private");
+ UserModeReference invisiblemode(NULL, "invisible");
}
-void Channel::SetMode(char mode,bool mode_on)
+Channel::Channel(const std::string &cname, time_t ts)
+ : name(cname), age(ts), topicset(0)
{
- modes[mode-65] = mode_on;
+ if (!ServerInstance->chanlist.insert(std::make_pair(cname, this)).second)
+ throw CoreException("Cannot create duplicate channel " + cname);
}
void Channel::SetMode(ModeHandler* mh, bool on)
{
- modes[mh->GetModeChar() - 65] = on;
-}
-
-void Channel::SetModeParam(char mode, const std::string& parameter)
-{
- CustomModeList::iterator n = custom_mode_params.find(mode);
- // always erase, even if changing, so that the map gets the new value
- if (n != custom_mode_params.end())
- custom_mode_params.erase(n);
- if (parameter.empty())
- {
- modes[mode-65] = false;
- }
- else
- {
- custom_mode_params[mode] = parameter;
- modes[mode-65] = true;
- }
+ modes[mh->GetId()] = on;
}
-void Channel::SetModeParam(ModeHandler* mode, const std::string& parameter)
+void Channel::SetTopic(User* u, const std::string& ntopic)
{
- SetModeParam(mode->GetModeChar(), parameter);
-}
-
-std::string Channel::GetModeParameter(char mode)
-{
- CustomModeList::iterator n = custom_mode_params.find(mode);
- if (n != custom_mode_params.end())
- return n->second;
- return "";
-}
-
-std::string Channel::GetModeParameter(ModeHandler* mode)
-{
- CustomModeList::iterator n = custom_mode_params.find(mode->GetModeChar());
- if (n != custom_mode_params.end())
- return n->second;
- return "";
-}
-
-int Channel::SetTopic(User *u, std::string &ntopic, bool forceset)
-{
- if (!u)
- u = ServerInstance->FakeClient;
- if (IS_LOCAL(u) && !forceset)
- {
- ModResult res;
- FIRST_MOD_RESULT(OnPreTopicChange, res, (u,this,ntopic));
-
- if (res == MOD_RES_DENY)
- return CMD_FAILURE;
- if (res != MOD_RES_ALLOW)
- {
- if (!this->HasUser(u))
- {
- u->WriteNumeric(442, "%s %s :You're not on that channel!",u->nick.c_str(), this->name.c_str());
- return CMD_FAILURE;
- }
- if (IsModeSet('t') && !ServerInstance->OnCheckExemption(u,this,"topiclock").check(GetPrefixValue(u) >= HALFOP_VALUE))
- {
- u->WriteNumeric(482, "%s %s :You do not have access to change the topic on this channel", u->nick.c_str(), this->name.c_str());
- return CMD_FAILURE;
- }
- }
- }
-
this->topic.assign(ntopic, 0, ServerInstance->Config->Limits.MaxTopic);
this->setby.assign(ServerInstance->Config->FullHostInTopic ? u->GetFullHost() : u->nick, 0, 128);
this->WriteChannel(u, "TOPIC %s :%s", this->name.c_str(), this->topic.c_str());
-
this->topicset = ServerInstance->Time();
- FOREACH_MOD(I_OnPostTopicChange,OnPostTopicChange(u, this, this->topic));
-
- return CMD_SUCCESS;
-}
-
-long Channel::GetUserCounter()
-{
- return userlist.size();
+ FOREACH_MOD(OnPostTopicChange, (u, this, this->topic));
}
Membership* Channel::AddUser(User* user)
{
- Membership* memb = new Membership(user, this);
- userlist[user] = memb;
+ Membership*& memb = userlist[user];
+ if (memb)
+ return NULL;
+
+ memb = new Membership(user, this);
return memb;
}
void Channel::DelUser(User* user)
{
- UserMembIter a = userlist.find(user);
+ MemberMap::iterator it = userlist.find(user);
+ if (it != userlist.end())
+ DelUser(it);
+}
- if (a != userlist.end())
- {
- a->second->cull();
- delete a->second;
- userlist.erase(a);
- }
+void Channel::CheckDestroy()
+{
+ if (!userlist.empty())
+ return;
- if (userlist.empty())
- {
- ModResult res;
- FIRST_MOD_RESULT(OnChannelPreDelete, res, (this));
- if (res == MOD_RES_DENY)
- return;
- chan_hash::iterator iter = ServerInstance->chanlist->find(this->name);
- /* kill the record */
- if (iter != ServerInstance->chanlist->end())
- {
- FOREACH_MOD(I_OnChannelDelete, OnChannelDelete(this));
- ServerInstance->chanlist->erase(iter);
- }
+ ModResult res;
+ FIRST_MOD_RESULT(OnChannelPreDelete, res, (this));
+ if (res == MOD_RES_DENY)
+ return;
- ClearInvites();
- ServerInstance->GlobalCulls.AddItem(this);
+ chan_hash::iterator iter = ServerInstance->chanlist.find(this->name);
+ /* kill the record */
+ if (iter != ServerInstance->chanlist.end())
+ {
+ FOREACH_MOD(OnChannelDelete, (this));
+ ServerInstance->chanlist.erase(iter);
}
+
+ ClearInvites();
+ ServerInstance->GlobalCulls.AddItem(this);
}
-bool Channel::HasUser(User* user)
+void Channel::DelUser(const MemberMap::iterator& membiter)
{
- return (userlist.find(user) != userlist.end());
+ Membership* memb = membiter->second;
+ memb->cull();
+ delete memb;
+ userlist.erase(membiter);
+
+ // If this channel became empty then it should be removed
+ CheckDestroy();
}
Membership* Channel::GetUser(User* user)
{
- UserMembIter i = userlist.find(user);
+ MemberMap::iterator i = userlist.find(user);
if (i == userlist.end())
return NULL;
return i->second;
}
-const UserMembList* Channel::GetUsers()
-{
- return &userlist;
-}
-
void Channel::SetDefaultModes()
{
- ServerInstance->Logs->Log("CHANNELS", DEBUG, "SetDefaultModes %s",
+ ServerInstance->Logs->Log("CHANNELS", LOG_DEBUG, "SetDefaultModes %s",
ServerInstance->Config->DefaultModes.c_str());
irc::spacesepstream list(ServerInstance->Config->DefaultModes);
std::string modeseq;
@@ -201,6 +132,9 @@ void Channel::SetDefaultModes()
ModeHandler* mode = ServerInstance->Modes->FindMode(*n, MODETYPE_CHANNEL);
if (mode)
{
+ if (mode->IsPrefixMode())
+ continue;
+
if (mode->GetNumParams(true))
list.GetToken(parameter);
else
@@ -215,134 +149,126 @@ void Channel::SetDefaultModes()
* add a channel to a user, creating the record for it if needed and linking
* it to the user record
*/
-Channel* Channel::JoinUser(User *user, const char* cn, bool override, const char* key, bool bursting, time_t TS)
+Channel* Channel::JoinUser(LocalUser* user, std::string cname, bool override, const std::string& key)
{
- // Fix: unregistered users could be joined using /SAJOIN
- if (!user || !cn || user->registered != REG_ALL)
+ if (user->registered != REG_ALL)
+ {
+ ServerInstance->Logs->Log("CHANNELS", LOG_DEBUG, "Attempted to join unregistered user " + user->uuid + " to channel " + cname);
return NULL;
-
- std::string privs;
- Channel *Ptr;
+ }
/*
* We don't restrict the number of channels that remote users or users that are override-joining may be in.
- * We restrict local users to MaxChans channels.
- * We restrict local operators to OperMaxChans channels.
+ * We restrict local users to <connect:maxchans> channels.
+ * We restrict local operators to <oper:maxchans> channels.
* This is a lot more logical than how it was formerly. -- w00t
*/
- if (IS_LOCAL(user) && !override)
+ if (!override)
{
- if (user->HasPrivPermission("channels/high-join-limit"))
+ unsigned int maxchans = user->GetClass()->maxchans;
+ if (user->IsOper())
{
- if (user->chans.size() >= ServerInstance->Config->OperMaxChans)
- {
- user->WriteNumeric(ERR_TOOMANYCHANNELS, "%s %s :You are on too many channels",user->nick.c_str(), cn);
- return NULL;
- }
+ unsigned int opermaxchans = ConvToInt(user->oper->getConfig("maxchans"));
+ // If not set, use 2.0's <channels:opers>, if that's not set either, use limit from CC
+ if (!opermaxchans)
+ opermaxchans = ServerInstance->Config->OperMaxChans;
+ if (opermaxchans)
+ maxchans = opermaxchans;
}
- else
+ if (user->chans.size() >= maxchans)
{
- unsigned int maxchans = user->GetClass()->maxchans;
- if (!maxchans)
- maxchans = ServerInstance->Config->MaxChans;
- if (user->chans.size() >= maxchans)
- {
- user->WriteNumeric(ERR_TOOMANYCHANNELS, "%s %s :You are on too many channels",user->nick.c_str(), cn);
- return NULL;
- }
+ user->WriteNumeric(ERR_TOOMANYCHANNELS, "%s :You are on too many channels", cname.c_str());
+ return NULL;
}
}
- std::string cname;
- cname.assign(std::string(cn), 0, ServerInstance->Config->Limits.ChanMax);
- Ptr = ServerInstance->FindChan(cname);
- bool created_by_local = false;
+ // Crop channel name if it's too long
+ if (cname.length() > ServerInstance->Config->Limits.ChanMax)
+ cname.resize(ServerInstance->Config->Limits.ChanMax);
- if (!Ptr)
+ Channel* chan = ServerInstance->FindChan(cname);
+ bool created_by_local = (chan == NULL); // Flag that will be passed to modules in the OnUserJoin() hook later
+ std::string privs; // Prefix mode(letter)s to give to the joining user
+
+ if (!chan)
{
- /*
- * Fix: desync bug was here, don't set @ on remote users - spanningtree handles their permissions. bug #358. -- w00t
- */
- if (!IS_LOCAL(user))
- {
- if (!TS)
- ServerInstance->Logs->Log("CHANNELS",DEBUG,"*** BUG *** Channel::JoinUser called for REMOTE user '%s' on channel '%s' but no TS given!", user->nick.c_str(), cn);
- }
- else
- {
- privs = "o";
- created_by_local = true;
- }
+ privs = ServerInstance->Config->DefaultModes.substr(0, ServerInstance->Config->DefaultModes.find(' '));
- if (IS_LOCAL(user) && override == false)
+ if (override == false)
{
+ // Ask the modules whether they're ok with the join, pass NULL as Channel* as the channel is yet to be created
ModResult MOD_RESULT;
- FIRST_MOD_RESULT(OnUserPreJoin, MOD_RESULT, (user, NULL, cname.c_str(), privs, key ? key : ""));
+ FIRST_MOD_RESULT(OnUserPreJoin, MOD_RESULT, (user, NULL, cname, privs, key));
if (MOD_RESULT == MOD_RES_DENY)
- return NULL;
+ return NULL; // A module wasn't happy with the join, abort
}
- Ptr = new Channel(cname, TS);
+ chan = new Channel(cname, ServerInstance->Time());
+ // Set the default modes on the channel (<options:defaultmodes>)
+ chan->SetDefaultModes();
}
else
{
/* Already on the channel */
- if (Ptr->HasUser(user))
+ if (chan->HasUser(user))
return NULL;
- /*
- * remote users are allowed us to bypass channel modes
- * and bans (used by servers)
- */
- if (IS_LOCAL(user) && override == false)
+ if (override == false)
{
ModResult MOD_RESULT;
- FIRST_MOD_RESULT(OnUserPreJoin, MOD_RESULT, (user, Ptr, cname.c_str(), privs, key ? key : ""));
+ FIRST_MOD_RESULT(OnUserPreJoin, MOD_RESULT, (user, chan, cname, privs, key));
+
+ // A module explicitly denied the join and (hopefully) generated a message
+ // describing the situation, so we may stop here without sending anything
if (MOD_RESULT == MOD_RES_DENY)
- {
return NULL;
- }
- else if (MOD_RESULT == MOD_RES_PASSTHRU)
+
+ // If no module returned MOD_RES_DENY or MOD_RES_ALLOW (which is the case
+ // most of the time) then proceed to check channel modes +k, +i, +l and bans,
+ // in this order.
+ // If a module explicitly allowed the join (by returning MOD_RES_ALLOW),
+ // then this entire section is skipped
+ if (MOD_RESULT == MOD_RES_PASSTHRU)
{
- std::string ckey = Ptr->GetModeParameter('k');
- bool invited = IS_LOCAL(user)->IsInvited(Ptr->name.c_str());
+ std::string ckey = chan->GetModeParameter(keymode);
+ bool invited = user->IsInvited(chan);
bool can_bypass = ServerInstance->Config->InvBypassModes && invited;
if (!ckey.empty())
{
- FIRST_MOD_RESULT(OnCheckKey, MOD_RESULT, (user, Ptr, key ? key : ""));
- if (!MOD_RESULT.check((key && ckey == key) || can_bypass))
+ FIRST_MOD_RESULT(OnCheckKey, MOD_RESULT, (user, chan, key));
+ if (!MOD_RESULT.check((ckey == key) || can_bypass))
{
// If no key provided, or key is not the right one, and can't bypass +k (not invited or option not enabled)
- user->WriteNumeric(ERR_BADCHANNELKEY, "%s %s :Cannot join channel (Incorrect channel key)",user->nick.c_str(), Ptr->name.c_str());
+ user->WriteNumeric(ERR_BADCHANNELKEY, "%s :Cannot join channel (Incorrect channel key)", chan->name.c_str());
return NULL;
}
}
- if (Ptr->IsModeSet('i'))
+ if (chan->IsModeSet(inviteonlymode))
{
- FIRST_MOD_RESULT(OnCheckInvite, MOD_RESULT, (user, Ptr));
+ FIRST_MOD_RESULT(OnCheckInvite, MOD_RESULT, (user, chan));
if (!MOD_RESULT.check(invited))
{
- user->WriteNumeric(ERR_INVITEONLYCHAN, "%s %s :Cannot join channel (Invite only)",user->nick.c_str(), Ptr->name.c_str());
+ user->WriteNumeric(ERR_INVITEONLYCHAN, "%s :Cannot join channel (Invite only)", chan->name.c_str());
return NULL;
}
}
- std::string limit = Ptr->GetModeParameter('l');
+ std::string limit = chan->GetModeParameter(limitmode);
if (!limit.empty())
{
- FIRST_MOD_RESULT(OnCheckLimit, MOD_RESULT, (user, Ptr));
- if (!MOD_RESULT.check((Ptr->GetUserCounter() < atol(limit.c_str()) || can_bypass)))
+ FIRST_MOD_RESULT(OnCheckLimit, MOD_RESULT, (user, chan));
+ if (!MOD_RESULT.check((chan->GetUserCounter() < atol(limit.c_str()) || can_bypass)))
{
- user->WriteNumeric(ERR_CHANNELISFULL, "%s %s :Cannot join channel (Channel is full)",user->nick.c_str(), Ptr->name.c_str());
+ user->WriteNumeric(ERR_CHANNELISFULL, "%s :Cannot join channel (Channel is full)", chan->name.c_str());
return NULL;
}
}
- if (Ptr->IsBanned(user) && !can_bypass)
+ if (chan->IsBanned(user) && !can_bypass)
{
- user->WriteNumeric(ERR_BANNEDFROMCHAN, "%s %s :Cannot join channel (You're banned)",user->nick.c_str(), Ptr->name.c_str());
+ user->WriteNumeric(ERR_BANNEDFROMCHAN, "%s :Cannot join channel (You're banned)", chan->name.c_str());
return NULL;
}
@@ -352,67 +278,77 @@ Channel* Channel::JoinUser(User *user, const char* cn, bool override, const char
*/
if (invited)
{
- IS_LOCAL(user)->RemoveInvite(Ptr->name.c_str());
+ user->RemoveInvite(chan);
}
}
}
}
- if (created_by_local)
- {
- /* As spotted by jilles, dont bother to set this on remote users */
- Ptr->SetDefaultModes();
- }
-
- return Channel::ForceChan(Ptr, user, privs, bursting, created_by_local);
+ // We figured that this join is allowed and also created the
+ // channel if it didn't exist before, now do the actual join
+ chan->ForceJoin(user, &privs, false, created_by_local);
+ return chan;
}
-Channel* Channel::ForceChan(Channel* Ptr, User* user, const std::string &privs, bool bursting, bool created)
+Membership* Channel::ForceJoin(User* user, const std::string* privs, bool bursting, bool created_by_local)
{
- std::string nick = user->nick;
+ if (IS_SERVER(user))
+ {
+ ServerInstance->Logs->Log("CHANNELS", LOG_DEBUG, "Attempted to join server user " + user->uuid + " to channel " + this->name);
+ return NULL;
+ }
- Membership* memb = Ptr->AddUser(user);
- user->chans.insert(Ptr);
+ Membership* memb = this->AddUser(user);
+ if (!memb)
+ return NULL; // Already on the channel
- for (std::string::const_iterator x = privs.begin(); x != privs.end(); x++)
+ user->chans.push_front(memb);
+
+ if (privs)
{
- const char status = *x;
- ModeHandler* mh = ServerInstance->Modes->FindMode(status, MODETYPE_CHANNEL);
- if (mh)
+ // If the user was granted prefix modes (in the OnUserPreJoin hook, or he's a
+ // remote user and his own server set the modes), then set them internally now
+ for (std::string::const_iterator i = privs->begin(); i != privs->end(); ++i)
{
- /* Set, and make sure that the mode handler knows this mode was now set */
- Ptr->SetPrefix(user, mh->GetModeChar(), true);
- mh->OnModeChange(ServerInstance->FakeClient, ServerInstance->FakeClient, Ptr, nick, true);
+ PrefixMode* mh = ServerInstance->Modes->FindPrefixMode(*i);
+ if (mh)
+ {
+ std::string nick = user->nick;
+ // Set the mode on the user
+ mh->OnModeChange(ServerInstance->FakeClient, NULL, this, nick, true);
+ }
}
}
+ // Tell modules about this join, they have the chance now to populate except_list with users we won't send the JOIN (and possibly MODE) to
CUList except_list;
- FOREACH_MOD(I_OnUserJoin,OnUserJoin(memb, bursting, created, except_list));
+ FOREACH_MOD(OnUserJoin, (memb, bursting, created_by_local, except_list));
- Ptr->WriteAllExcept(user, false, 0, except_list, "JOIN :%s", Ptr->name.c_str());
+ this->WriteAllExcept(user, false, 0, except_list, "JOIN :%s", this->name.c_str());
/* Theyre not the first ones in here, make sure everyone else sees the modes we gave the user */
- if ((Ptr->GetUserCounter() > 1) && (!memb->modes.empty()))
+ if ((GetUserCounter() > 1) && (!memb->modes.empty()))
{
std::string ms = memb->modes;
for(unsigned int i=0; i < memb->modes.length(); i++)
ms.append(" ").append(user->nick);
except_list.insert(user);
- Ptr->WriteAllExcept(user, !ServerInstance->Config->CycleHostsFromUser, 0, except_list, "MODE %s +%s", Ptr->name.c_str(), ms.c_str());
+ this->WriteAllExcept(user, !ServerInstance->Config->CycleHostsFromUser, 0, except_list, "MODE %s +%s", this->name.c_str(), ms.c_str());
}
if (IS_LOCAL(user))
{
- if (Ptr->topicset)
+ if (this->topicset)
{
- user->WriteNumeric(RPL_TOPIC, "%s %s :%s", user->nick.c_str(), Ptr->name.c_str(), Ptr->topic.c_str());
- user->WriteNumeric(RPL_TOPICTIME, "%s %s %s %lu", user->nick.c_str(), Ptr->name.c_str(), Ptr->setby.c_str(), (unsigned long)Ptr->topicset);
+ user->WriteNumeric(RPL_TOPIC, "%s :%s", this->name.c_str(), this->topic.c_str());
+ user->WriteNumeric(RPL_TOPICTIME, "%s %s %lu", this->name.c_str(), this->setby.c_str(), (unsigned long)this->topicset);
}
- Ptr->UserList(user);
+ this->UserList(user);
}
- FOREACH_MOD(I_OnPostJoin,OnPostJoin(memb));
- return Ptr;
+
+ FOREACH_MOD(OnPostJoin, (memb));
+ return memb;
}
bool Channel::IsBanned(User* user)
@@ -423,10 +359,15 @@ bool Channel::IsBanned(User* user)
if (result != MOD_RES_PASSTHRU)
return (result == MOD_RES_DENY);
- for (BanList::iterator i = this->bans.begin(); i != this->bans.end(); i++)
+ ListModeBase* banlm = static_cast<ListModeBase*>(*ban);
+ const ListModeBase::ModeList* bans = banlm->GetList(this);
+ if (bans)
{
- if (CheckBan(user, i->data))
- return true;
+ for (ListModeBase::ModeList::const_iterator it = bans->begin(); it != bans->end(); it++)
+ {
+ if (CheckBan(user, it->mask))
+ return true;
+ }
}
return false;
}
@@ -446,10 +387,9 @@ bool Channel::CheckBan(User* user, const std::string& mask)
if (at == std::string::npos)
return false;
- char tomatch[MAXBUF];
- snprintf(tomatch, MAXBUF, "%s!%s", user->nick.c_str(), user->ident.c_str());
+ const std::string nickIdent = user->nick + "!" + user->ident;
std::string prefix = mask.substr(0, at);
- if (InspIRCd::Match(tomatch, prefix, NULL))
+ if (InspIRCd::Match(nickIdent, prefix, NULL))
{
std::string suffix = mask.substr(at + 1);
if (InspIRCd::Match(user->host, suffix, NULL) ||
@@ -466,12 +406,14 @@ ModResult Channel::GetExtBanStatus(User *user, char type)
FIRST_MOD_RESULT(OnExtBanCheck, rv, (user, this, type));
if (rv != MOD_RES_PASSTHRU)
return rv;
- for (BanList::iterator i = this->bans.begin(); i != this->bans.end(); i++)
+
+ ListModeBase* banlm = static_cast<ListModeBase*>(*ban);
+ const ListModeBase::ModeList* bans = banlm->GetList(this);
+ if (bans)
{
- if (i->data[0] == type && i->data[1] == ':')
+ for (ListModeBase::ModeList::const_iterator it = bans->begin(); it != bans->end(); ++it)
{
- std::string val = i->data.substr(2);
- if (CheckBan(user, val))
+ if (CheckBan(user, it->mask))
return MOD_RES_DENY;
}
}
@@ -479,150 +421,74 @@ ModResult Channel::GetExtBanStatus(User *user, char type)
}
/* Channel::PartUser
- * remove a channel from a users record, and return the number of users left.
- * Therefore, if this function returns 0 the caller should delete the Channel.
+ * Remove a channel from a users record, remove the reference to the Membership object
+ * from the channel and destroy it.
*/
void Channel::PartUser(User *user, std::string &reason)
{
- if (!user)
- return;
+ MemberMap::iterator membiter = userlist.find(user);
- Membership* memb = GetUser(user);
-
- if (memb)
+ if (membiter != userlist.end())
{
+ Membership* memb = membiter->second;
CUList except_list;
- FOREACH_MOD(I_OnUserPart,OnUserPart(memb, reason, except_list));
+ FOREACH_MOD(OnUserPart, (memb, reason, except_list));
WriteAllExcept(user, false, 0, except_list, "PART %s%s%s", this->name.c_str(), reason.empty() ? "" : " :", reason.c_str());
- user->chans.erase(this);
- this->RemoveAllPrefixes(user);
+ // Remove this channel from the user's chanlist
+ user->chans.erase(memb);
+ // Remove the Membership from this channel's userlist and destroy it
+ this->DelUser(membiter);
}
-
- this->DelUser(user);
}
-void Channel::KickUser(User *src, User *user, const char* reason)
+void Channel::KickUser(User* src, const MemberMap::iterator& victimiter, const std::string& reason)
{
- if (!src || !user || !reason)
- return;
-
- Membership* memb = GetUser(user);
- if (IS_LOCAL(src))
- {
- if (!memb)
- {
- src->WriteNumeric(ERR_USERNOTINCHANNEL, "%s %s %s :They are not on that channel",src->nick.c_str(), user->nick.c_str(), this->name.c_str());
- return;
- }
- if ((ServerInstance->ULine(user->server)) && (!ServerInstance->ULine(src->server)))
- {
- src->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only a u-line may kick a u-line from a channel.",src->nick.c_str(), this->name.c_str());
- return;
- }
-
- ModResult res;
- if (ServerInstance->ULine(src->server))
- res = MOD_RES_ALLOW;
- else
- FIRST_MOD_RESULT(OnUserPreKick, res, (src,memb,reason));
-
- if (res == MOD_RES_DENY)
- return;
-
- if (res == MOD_RES_PASSTHRU)
- {
- unsigned int them = this->GetPrefixValue(src);
- unsigned int req = HALFOP_VALUE;
- for (std::string::size_type i = 0; i < memb->modes.length(); i++)
- {
- ModeHandler* mh = ServerInstance->Modes->FindMode(memb->modes[i], MODETYPE_CHANNEL);
- if (mh && mh->GetLevelRequired() > req)
- req = mh->GetLevelRequired();
- }
-
- if (them < req)
- {
- src->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must be a channel %soperator",
- src->nick.c_str(), this->name.c_str(), req > HALFOP_VALUE ? "" : "half-");
- return;
- }
- }
- }
-
- if (memb)
- {
- CUList except_list;
- FOREACH_MOD(I_OnUserKick,OnUserKick(src, memb, reason, except_list));
-
- WriteAllExcept(src, false, 0, except_list, "KICK %s %s :%s", name.c_str(), user->nick.c_str(), reason);
+ Membership* memb = victimiter->second;
+ CUList except_list;
+ FOREACH_MOD(OnUserKick, (src, memb, reason, except_list));
- user->chans.erase(this);
- this->RemoveAllPrefixes(user);
- }
+ User* victim = memb->user;
+ WriteAllExcept(src, false, 0, except_list, "KICK %s %s :%s", name.c_str(), victim->nick.c_str(), reason.c_str());
- this->DelUser(user);
+ victim->chans.erase(memb);
+ this->DelUser(victimiter);
}
void Channel::WriteChannel(User* user, const char* text, ...)
{
- char textbuffer[MAXBUF];
- va_list argsPtr;
-
- if (!user || !text)
- return;
-
- va_start(argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
-
- this->WriteChannel(user, std::string(textbuffer));
+ std::string textbuffer;
+ VAFORMAT(textbuffer, text, text);
+ this->WriteChannel(user, textbuffer);
}
void Channel::WriteChannel(User* user, const std::string &text)
{
- char tb[MAXBUF];
+ const std::string message = ":" + user->GetFullHost() + " " + text;
- if (!user)
- return;
-
- snprintf(tb,MAXBUF,":%s %s", user->GetFullHost().c_str(), text.c_str());
- std::string out = tb;
-
- for (UserMembIter i = userlist.begin(); i != userlist.end(); i++)
+ for (MemberMap::iterator i = userlist.begin(); i != userlist.end(); i++)
{
if (IS_LOCAL(i->first))
- i->first->Write(out);
+ i->first->Write(message);
}
}
void Channel::WriteChannelWithServ(const std::string& ServName, const char* text, ...)
{
- char textbuffer[MAXBUF];
- va_list argsPtr;
-
- if (!text)
- return;
-
- va_start(argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
-
- this->WriteChannelWithServ(ServName, std::string(textbuffer));
+ std::string textbuffer;
+ VAFORMAT(textbuffer, text, text);
+ this->WriteChannelWithServ(ServName, textbuffer);
}
void Channel::WriteChannelWithServ(const std::string& ServName, const std::string &text)
{
- char tb[MAXBUF];
-
- snprintf(tb,MAXBUF,":%s %s", ServName.empty() ? ServerInstance->Config->ServerName.c_str() : ServName.c_str(), text.c_str());
- std::string out = tb;
+ const std::string message = ":" + (ServName.empty() ? ServerInstance->Config->ServerName : ServName) + " " + text;
- for (UserMembIter i = userlist.begin(); i != userlist.end(); i++)
+ for (MemberMap::iterator i = userlist.begin(); i != userlist.end(); i++)
{
if (IS_LOCAL(i->first))
- i->first->Write(out);
+ i->first->Write(message);
}
}
@@ -630,43 +496,23 @@ void Channel::WriteChannelWithServ(const std::string& ServName, const std::strin
* for the sender (for privmsg etc) */
void Channel::WriteAllExceptSender(User* user, bool serversource, char status, const char* text, ...)
{
- char textbuffer[MAXBUF];
- va_list argsPtr;
-
- if (!text)
- return;
-
- va_start(argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
-
- this->WriteAllExceptSender(user, serversource, status, std::string(textbuffer));
+ std::string textbuffer;
+ VAFORMAT(textbuffer, text, text);
+ this->WriteAllExceptSender(user, serversource, status, textbuffer);
}
void Channel::WriteAllExcept(User* user, bool serversource, char status, CUList &except_list, const char* text, ...)
{
- char textbuffer[MAXBUF];
- va_list argsPtr;
-
- if (!text)
- return;
-
- int offset = snprintf(textbuffer,MAXBUF,":%s ", serversource ? ServerInstance->Config->ServerName.c_str() : user->GetFullHost().c_str());
-
- va_start(argsPtr, text);
- vsnprintf(textbuffer + offset, MAXBUF - offset, text, argsPtr);
- va_end(argsPtr);
-
- this->RawWriteAllExcept(user, serversource, status, except_list, std::string(textbuffer));
+ std::string textbuffer;
+ VAFORMAT(textbuffer, text, text);
+ textbuffer = ":" + (serversource ? ServerInstance->Config->ServerName : user->GetFullHost()) + " " + textbuffer;
+ this->RawWriteAllExcept(user, serversource, status, except_list, textbuffer);
}
void Channel::WriteAllExcept(User* user, bool serversource, char status, CUList &except_list, const std::string &text)
{
- char tb[MAXBUF];
-
- snprintf(tb,MAXBUF,":%s %s", serversource ? ServerInstance->Config->ServerName.c_str() : user->GetFullHost().c_str(), text.c_str());
-
- this->RawWriteAllExcept(user, serversource, status, except_list, std::string(tb));
+ const std::string message = ":" + (serversource ? ServerInstance->Config->ServerName : user->GetFullHost()) + " " + text;
+ this->RawWriteAllExcept(user, serversource, status, except_list, message);
}
void Channel::RawWriteAllExcept(User* user, bool serversource, char status, CUList &except_list, const std::string &out)
@@ -674,11 +520,11 @@ void Channel::RawWriteAllExcept(User* user, bool serversource, char status, CULi
unsigned int minrank = 0;
if (status)
{
- ModeHandler* mh = ServerInstance->Modes->FindPrefix(status);
+ PrefixMode* mh = ServerInstance->Modes->FindPrefix(status);
if (mh)
minrank = mh->GetPrefixRank();
}
- for (UserMembIter i = userlist.begin(); i != userlist.end(); i++)
+ for (MemberMap::iterator i = userlist.begin(); i != userlist.end(); i++)
{
if (IS_LOCAL(i->first) && (except_list.find(i->first) == except_list.end()))
{
@@ -698,99 +544,59 @@ void Channel::WriteAllExceptSender(User* user, bool serversource, char status, c
this->WriteAllExcept(user, serversource, status, except_list, std::string(text));
}
-/*
- * return a count of the users on a specific channel accounting for
- * invisible users who won't increase the count. e.g. for /LIST
- */
-int Channel::CountInvisible()
-{
- int count = 0;
- for (UserMembIter i = userlist.begin(); i != userlist.end(); i++)
- {
- if (!i->first->quitting && !i->first->IsModeSet('i'))
- count++;
- }
-
- return count;
-}
-
-char* Channel::ChanModes(bool showkey)
+const char* Channel::ChanModes(bool showkey)
{
- static char scratch[MAXBUF];
- static char sparam[MAXBUF];
- char* offset = scratch;
- std::string extparam;
+ static std::string scratch;
+ std::string sparam;
- *scratch = '\0';
- *sparam = '\0';
+ scratch.clear();
/* This was still iterating up to 190, Channel::modes is only 64 elements -- Om */
for(int n = 0; n < 64; n++)
{
- if(this->modes[n])
+ ModeHandler* mh = ServerInstance->Modes->FindMode(n + 65, MODETYPE_CHANNEL);
+ if (mh && IsModeSet(mh))
{
- *offset++ = n + 65;
- extparam.clear();
+ scratch.push_back(n + 65);
+
+ ParamModeBase* pm = mh->IsParameterMode();
+ if (!pm)
+ continue;
+
if (n == 'k' - 65 && !showkey)
{
- extparam = "<key>";
+ sparam += " <key>";
}
else
{
- extparam = this->GetModeParameter(n + 65);
- }
- if (!extparam.empty())
- {
- charlcat(sparam,' ',MAXBUF);
- strlcat(sparam,extparam.c_str(),MAXBUF);
+ sparam += ' ';
+ pm->GetParameter(this, sparam);
}
}
}
- /* Null terminate scratch */
- *offset = '\0';
- strlcat(scratch,sparam,MAXBUF);
- return scratch;
+ scratch += sparam;
+ return scratch.c_str();
}
/* compile a userlist of a channel into a string, each nick seperated by
* spaces and op, voice etc status shown as @ and +, and send it to 'user'
*/
-void Channel::UserList(User *user)
+void Channel::UserList(User* user, bool has_user)
{
- if (!IS_LOCAL(user))
- return;
-
bool has_privs = user->HasPrivPermission("channels/auspex");
-
- if (this->IsModeSet('s') && !this->HasUser(user) && !has_privs)
- {
- user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), this->name.c_str());
- return;
- }
-
- std::string list = user->nick;
- list.push_back(' ');
- list.push_back(this->IsModeSet('s') ? '@' : this->IsModeSet('p') ? '*' : '=');
+ std::string list;
+ list.push_back(this->IsModeSet(secretmode) ? '@' : this->IsModeSet(privatemode) ? '*' : '=');
list.push_back(' ');
list.append(this->name).append(" :");
std::string::size_type pos = list.size();
- bool has_one = false;
-
- /* Improvement by Brain - this doesnt change in value, so why was it inside
- * the loop?
- */
- bool has_user = this->HasUser(user);
-
- const size_t maxlen = MAXBUF - 10 - ServerInstance->Config->ServerName.size();
+ const size_t maxlen = ServerInstance->Config->Limits.MaxLine - 10 - ServerInstance->Config->ServerName.size();
std::string prefixlist;
std::string nick;
- for (UserMembIter i = userlist.begin(); i != userlist.end(); ++i)
+ for (MemberMap::iterator i = userlist.begin(); i != userlist.end(); ++i)
{
- if (i->first->quitting)
- continue;
- if ((!has_user) && (i->first->IsModeSet('i')) && (!has_privs))
+ if ((!has_user) && (i->first->IsModeSet(invisiblemode)) && (!has_privs))
{
/*
* user is +i, and source not on the channel, does not show
@@ -799,13 +605,19 @@ void Channel::UserList(User *user)
continue;
}
- prefixlist = this->GetPrefixChar(i->first);
+ Membership* memb = i->second;
+
+ prefixlist.clear();
+ char prefix = memb->GetPrefixChar();
+ if (prefix)
+ prefixlist.push_back(prefix);
nick = i->first->nick;
- FOREACH_MOD(I_OnNamesListItem, OnNamesListItem(user, i->second, prefixlist, nick));
+ ModResult res;
+ FIRST_MOD_RESULT(OnNamesListItem, res, (user, memb, prefixlist, nick));
- /* Nick was nuked, a module wants us to skip it */
- if (nick.empty())
+ // See if a module wants us to exclude this user from NAMES
+ if (res == MOD_RES_DENY)
continue;
if (list.size() + prefixlist.length() + nick.length() + 1 > maxlen)
@@ -815,71 +627,34 @@ void Channel::UserList(User *user)
// Erase all nicks, keep the constant part
list.erase(pos);
- has_one = false;
}
list.append(prefixlist).append(nick).push_back(' ');
-
- has_one = true;
}
- /* if whats left in the list isnt empty, send it */
- if (has_one)
- {
+ // Only send the user list numeric if there is at least one user in it
+ if (list.size() != pos)
user->WriteNumeric(RPL_NAMREPLY, list);
- }
-
- user->WriteNumeric(RPL_ENDOFNAMES, "%s %s :End of /NAMES list.", user->nick.c_str(), this->name.c_str());
-}
-
-long Channel::GetMaxBans()
-{
- /* Return the cached value if there is one */
- if (this->maxbans)
- return this->maxbans;
- /* If there isnt one, we have to do some O(n) hax to find it the first time. (ick) */
- for (std::map<std::string,int>::iterator n = ServerInstance->Config->maxbans.begin(); n != ServerInstance->Config->maxbans.end(); n++)
- {
- if (InspIRCd::Match(this->name, n->first, NULL))
- {
- this->maxbans = n->second;
- return n->second;
- }
- }
-
- /* Screw it, just return the default of 64 */
- this->maxbans = 64;
- return this->maxbans;
-}
-
-void Channel::ResetMaxBans()
-{
- this->maxbans = 0;
+ user->WriteNumeric(RPL_ENDOFNAMES, "%s :End of /NAMES list.", this->name.c_str());
}
/* returns the status character for a given user on a channel, e.g. @ for op,
* % for halfop etc. If the user has several modes set, the highest mode
* the user has must be returned.
*/
-const char* Channel::GetPrefixChar(User *user)
+char Membership::GetPrefixChar() const
{
- static char pf[2] = {0, 0};
- *pf = 0;
+ char pf = 0;
unsigned int bestrank = 0;
- UserMembIter m = userlist.find(user);
- if (m != userlist.end())
+ for (std::string::const_iterator i = modes.begin(); i != modes.end(); ++i)
{
- for(unsigned int i=0; i < m->second->modes.length(); i++)
+ PrefixMode* mh = ServerInstance->Modes->FindPrefixMode(*i);
+ if (mh && mh->GetPrefixRank() > bestrank && mh->GetPrefix())
{
- char mchar = m->second->modes[i];
- ModeHandler* mh = ServerInstance->Modes->FindMode(mchar, MODETYPE_CHANNEL);
- if (mh && mh->GetPrefixRank() > bestrank && mh->GetPrefix())
- {
- bestrank = mh->GetPrefixRank();
- pf[0] = mh->GetPrefix();
- }
+ bestrank = mh->GetPrefixRank();
+ pf = mh->GetPrefix();
}
}
return pf;
@@ -891,28 +666,23 @@ unsigned int Membership::getRank()
unsigned int rv = 0;
if (mchar)
{
- ModeHandler* mh = ServerInstance->Modes->FindMode(mchar, MODETYPE_CHANNEL);
+ PrefixMode* mh = ServerInstance->Modes->FindPrefixMode(mchar);
if (mh)
rv = mh->GetPrefixRank();
}
return rv;
}
-const char* Channel::GetAllPrefixChars(User* user)
+const char* Membership::GetAllPrefixChars() const
{
static char prefix[64];
int ctr = 0;
- UserMembIter m = userlist.find(user);
- if (m != userlist.end())
+ for (std::string::const_iterator i = modes.begin(); i != modes.end(); ++i)
{
- for(unsigned int i=0; i < m->second->modes.length(); i++)
- {
- char mchar = m->second->modes[i];
- ModeHandler* mh = ServerInstance->Modes->FindMode(mchar, MODETYPE_CHANNEL);
- if (mh && mh->GetPrefix())
- prefix[ctr++] = mh->GetPrefix();
- }
+ PrefixMode* mh = ServerInstance->Modes->FindPrefixMode(*i);
+ if (mh && mh->GetPrefix())
+ prefix[ctr++] = mh->GetPrefix();
}
prefix[ctr] = 0;
@@ -921,54 +691,39 @@ const char* Channel::GetAllPrefixChars(User* user)
unsigned int Channel::GetPrefixValue(User* user)
{
- UserMembIter m = userlist.find(user);
+ MemberMap::iterator m = userlist.find(user);
if (m == userlist.end())
return 0;
return m->second->getRank();
}
-bool Channel::SetPrefix(User* user, char prefix, bool adding)
+bool Membership::SetPrefix(PrefixMode* delta_mh, bool adding)
{
- ModeHandler* delta_mh = ServerInstance->Modes->FindMode(prefix, MODETYPE_CHANNEL);
- if (!delta_mh)
- return false;
- UserMembIter m = userlist.find(user);
- if (m == userlist.end())
- return false;
- for(unsigned int i=0; i < m->second->modes.length(); i++)
+ char prefix = delta_mh->GetModeChar();
+ for (unsigned int i = 0; i < modes.length(); i++)
{
- char mchar = m->second->modes[i];
- ModeHandler* mh = ServerInstance->Modes->FindMode(mchar, MODETYPE_CHANNEL);
+ char mchar = modes[i];
+ PrefixMode* mh = ServerInstance->Modes->FindPrefixMode(mchar);
if (mh && mh->GetPrefixRank() <= delta_mh->GetPrefixRank())
{
- m->second->modes =
- m->second->modes.substr(0,i) +
+ modes = modes.substr(0,i) +
(adding ? std::string(1, prefix) : "") +
- m->second->modes.substr(mchar == prefix ? i+1 : i);
+ modes.substr(mchar == prefix ? i+1 : i);
return adding != (mchar == prefix);
}
}
if (adding)
- m->second->modes += std::string(1, prefix);
+ modes.push_back(prefix);
return adding;
}
-void Channel::RemoveAllPrefixes(User* user)
-{
- UserMembIter m = userlist.find(user);
- if (m != userlist.end())
- {
- m->second->modes.clear();
- }
-}
-
void Invitation::Create(Channel* c, LocalUser* u, time_t timeout)
{
if ((timeout != 0) && (ServerInstance->Time() >= timeout))
// Expired, don't bother
return;
- ServerInstance->Logs->Log("INVITATION", DEBUG, "Invitation::Create chan=%s user=%s", c->name.c_str(), u->uuid.c_str());
+ ServerInstance->Logs->Log("INVITATION", LOG_DEBUG, "Invitation::Create chan=%s user=%s", c->name.c_str(), u->uuid.c_str());
Invitation* inv = Invitation::Find(c, u, false);
if (inv)
@@ -976,37 +731,32 @@ void Invitation::Create(Channel* c, LocalUser* u, time_t timeout)
if ((inv->expiry == 0) || (inv->expiry > timeout))
return;
inv->expiry = timeout;
- ServerInstance->Logs->Log("INVITATION", DEBUG, "Invitation::Create changed expiry in existing invitation %p", (void*) inv);
+ ServerInstance->Logs->Log("INVITATION", LOG_DEBUG, "Invitation::Create changed expiry in existing invitation %p", (void*) inv);
}
else
{
inv = new Invitation(c, u, timeout);
- c->invites.push_back(inv);
- u->invites.push_back(inv);
- ServerInstance->Logs->Log("INVITATION", DEBUG, "Invitation::Create created new invitation %p", (void*) inv);
+ c->invites.push_front(inv);
+ u->invites.push_front(inv);
+ ServerInstance->Logs->Log("INVITATION", LOG_DEBUG, "Invitation::Create created new invitation %p", (void*) inv);
}
}
Invitation* Invitation::Find(Channel* c, LocalUser* u, bool check_expired)
{
- ServerInstance->Logs->Log("INVITATION", DEBUG, "Invitation::Find chan=%s user=%s check_expired=%d", c ? c->name.c_str() : "NULL", u ? u->uuid.c_str() : "NULL", check_expired);
- if (!u || u->invites.empty())
- return NULL;
-
- InviteList locallist;
- locallist.swap(u->invites);
+ ServerInstance->Logs->Log("INVITATION", LOG_DEBUG, "Invitation::Find chan=%s user=%s check_expired=%d", c ? c->name.c_str() : "NULL", u ? u->uuid.c_str() : "NULL", check_expired);
Invitation* result = NULL;
- for (InviteList::iterator i = locallist.begin(); i != locallist.end(); )
+ for (InviteList::iterator i = u->invites.begin(); i != u->invites.end(); )
{
Invitation* inv = *i;
+ ++i;
+
if ((check_expired) && (inv->expiry != 0) && (inv->expiry <= ServerInstance->Time()))
{
/* Expired invite, remove it. */
- std::string expiration = ServerInstance->TimeString(inv->expiry);
- ServerInstance->Logs->Log("INVITATION", DEBUG, "Invitation::Find ecountered expired entry: %p expired %s", (void*) inv, expiration.c_str());
- i = locallist.erase(i);
- inv->cull();
+ std::string expiration = InspIRCd::TimeString(inv->expiry);
+ ServerInstance->Logs->Log("INVITATION", LOG_DEBUG, "Invitation::Find ecountered expired entry: %p expired %s", (void*) inv, expiration.c_str());
delete inv;
}
else
@@ -1017,34 +767,17 @@ Invitation* Invitation::Find(Channel* c, LocalUser* u, bool check_expired)
result = inv;
break;
}
- ++i;
}
}
- locallist.swap(u->invites);
- ServerInstance->Logs->Log("INVITATION", DEBUG, "Invitation::Find result=%p", (void*) result);
+ ServerInstance->Logs->Log("INVITATION", LOG_DEBUG, "Invitation::Find result=%p", (void*) result);
return result;
}
Invitation::~Invitation()
{
// Remove this entry from both lists
- InviteList::iterator it = std::find(chan->invites.begin(), chan->invites.end(), this);
- if (it != chan->invites.end())
- chan->invites.erase(it);
- it = std::find(user->invites.begin(), user->invites.end(), this);
- if (it != user->invites.end())
- user->invites.erase(it);
-}
-
-void InviteBase::ClearInvites()
-{
- ServerInstance->Logs->Log("INVITEBASE", DEBUG, "InviteBase::ClearInvites %p", (void*) this);
- InviteList locallist;
- locallist.swap(invites);
- for (InviteList::const_iterator i = locallist.begin(); i != locallist.end(); ++i)
- {
- (*i)->cull();
- delete *i;
- }
+ chan->invites.erase(this);
+ user->invites.erase(this);
+ ServerInstance->Logs->Log("INVITEBASE", LOG_DEBUG, "Invitation::~ %p", (void*) this);
}
diff --git a/src/cidr.cpp b/src/cidr.cpp
index b245a1552..8d199353d 100644
--- a/src/cidr.cpp
+++ b/src/cidr.cpp
@@ -19,8 +19,6 @@
*/
-/* $Core */
-
#include "inspircd.h"
/* Match CIDR strings, e.g. 127.0.0.1 to 127.0.0.0/8 or 3ffe:1:5:6::8 to 3ffe:1::0/32
@@ -82,5 +80,3 @@ bool irc::sockets::MatchCIDR(const std::string &address, const std::string &cidr
return mask == mask2;
}
-
-
diff --git a/src/command_parse.cpp b/src/command_parse.cpp
index 1c72c7de4..ed996e83c 100644
--- a/src/command_parse.cpp
+++ b/src/command_parse.cpp
@@ -23,117 +23,93 @@
#include "inspircd.h"
-int InspIRCd::PassCompare(Extensible* ex, const std::string &data, const std::string &input, const std::string &hashtype)
+bool InspIRCd::PassCompare(Extensible* ex, const std::string& data, const std::string& input, const std::string& hashtype)
{
ModResult res;
FIRST_MOD_RESULT(OnPassCompare, res, (ex, data, input, hashtype));
/* Module matched */
if (res == MOD_RES_ALLOW)
- return 0;
+ return true;
/* Module explicitly didnt match */
if (res == MOD_RES_DENY)
- return 1;
+ return false;
/* We dont handle any hash types except for plaintext - Thanks tra26 */
if (!hashtype.empty() && hashtype != "plaintext")
- /* See below. 1 because they dont match */
- return 1;
+ return false;
- return (data != input); // this seems back to front, but returns 0 if they *match*, 1 else
+ return TimingSafeCompare(data, input);
}
-/* LoopCall is used to call a command classes handler repeatedly based on the contents of a comma seperated list.
- * There are two overriden versions of this method, one of which takes two potential lists and the other takes one.
- * We need a version which takes two potential lists for JOIN, because a JOIN may contain two lists of items at once,
- * the channel names and their keys as follows:
- * JOIN #chan1,#chan2,#chan3 key1,,key3
- * Therefore, we need to deal with both lists concurrently. The first instance of this method does that by creating
- * two instances of irc::commasepstream and reading them both together until the first runs out of tokens.
- * The second version is much simpler and just has the one stream to read, and is used in NAMES, WHOIS, PRIVMSG etc.
- * Both will only parse until they reach ServerInstance->Config->MaxTargets number of targets, to stop abuse via spam.
- */
-int CommandParser::LoopCall(User* user, Command* CommandObj, const std::vector<std::string>& parameters, unsigned int splithere, int extra, bool usemax)
+bool CommandParser::LoopCall(User* user, Command* handler, const std::vector<std::string>& parameters, unsigned int splithere, int extra, bool usemax)
{
if (splithere >= parameters.size())
- return 0;
+ return false;
- if (extra >= (signed)parameters.size())
- extra = -1;
-
- /* First check if we have more than one item in the list, if we don't we return zero here and the handler
+ /* First check if we have more than one item in the list, if we don't we return false here and the handler
* which called us just carries on as it was.
*/
if (parameters[splithere].find(',') == std::string::npos)
- return 0;
+ return false;
/** Some lame ircds will weed out dupes using some shitty O(n^2) algorithm.
* By using std::set (thanks for the idea w00t) we can cut this down a ton.
* ...VOOODOOOO!
+ *
+ * Only check for duplicates if there is one list (allow them in JOIN).
*/
std::set<irc::string> dupes;
+ bool check_dupes = (extra < 0);
- /* Create two lists, one for channel names, one for keys
+ /* Create two sepstreams, if we have only one list, then initialize the second sepstream with
+ * an empty string. The second parameter of the constructor of the sepstream tells whether
+ * or not to allow empty tokens.
+ * We allow empty keys, so "JOIN #a,#b ,bkey" will be interpreted as "JOIN #a", "JOIN #b bkey"
*/
irc::commasepstream items1(parameters[splithere]);
- irc::commasepstream items2(extra >= 0 ? parameters[extra] : "");
- std::string extrastuff;
+ irc::commasepstream items2(extra >= 0 ? parameters[extra] : "", true);
std::string item;
unsigned int max = 0;
+ LocalUser* localuser = IS_LOCAL(user);
- /* Attempt to iterate these lists and call the command objech
- * which called us, for every parameter pair until there are
- * no more left to parse.
+ /* Attempt to iterate these lists and call the command handler
+ * for every parameter or parameter pair until there are no more
+ * left to parse.
*/
while (items1.GetToken(item) && (!usemax || max++ < ServerInstance->Config->MaxTargets))
{
- if (dupes.find(item.c_str()) == dupes.end())
+ if ((!check_dupes) || (dupes.insert(item.c_str()).second))
{
std::vector<std::string> new_parameters(parameters);
-
- if (!items2.GetToken(extrastuff))
- extrastuff.clear();
-
new_parameters[splithere] = item;
- if (extra >= 0)
- new_parameters[extra] = extrastuff;
-
- CommandObj->Handle(new_parameters, user);
-
- dupes.insert(item.c_str());
- }
- }
- return 1;
-}
-
-bool CommandParser::IsValidCommand(const std::string &commandname, unsigned int pcnt, User * user)
-{
- Commandtable::iterator n = cmdlist.find(commandname);
- if (n != cmdlist.end())
- {
- if ((pcnt >= n->second->min_params))
- {
- if (IS_LOCAL(user) && n->second->flags_needed)
+ if (extra >= 0)
{
- if (user->IsModeSet(n->second->flags_needed))
- {
- return (user->HasPermission(commandname));
- }
+ // If we have two lists then get the next item from the second list.
+ // In case it runs out of elements then 'item' will be an empty string.
+ items2.GetToken(item);
+ new_parameters[extra] = item;
}
- else
+
+ CmdResult result = handler->Handle(new_parameters, user);
+ if (localuser)
{
- return true;
+ // Run the OnPostCommand hook with the last parameter (original line) being empty
+ // to indicate that the command had more targets in its original form.
+ item.clear();
+ FOREACH_MOD(OnPostCommand, (handler, new_parameters, localuser, result, item));
}
}
}
- return false;
+
+ return true;
}
Command* CommandParser::GetHandler(const std::string &commandname)
{
- Commandtable::iterator n = cmdlist.find(commandname);
+ CommandMap::iterator n = cmdlist.find(commandname);
if (n != cmdlist.end())
return n->second;
@@ -142,9 +118,9 @@ Command* CommandParser::GetHandler(const std::string &commandname)
// calls a handler function for a command
-CmdResult CommandParser::CallHandler(const std::string &commandname, const std::vector<std::string>& parameters, User *user)
+CmdResult CommandParser::CallHandler(const std::string& commandname, const std::vector<std::string>& parameters, User* user, Command** cmd)
{
- Commandtable::iterator n = cmdlist.find(commandname);
+ CommandMap::iterator n = cmdlist.find(commandname);
if (n != cmdlist.end())
{
@@ -174,6 +150,8 @@ CmdResult CommandParser::CallHandler(const std::string &commandname, const std::
if (bOkay)
{
+ if (cmd)
+ *cmd = n->second;
return n->second->Handle(parameters,user);
}
}
@@ -181,7 +159,7 @@ CmdResult CommandParser::CallHandler(const std::string &commandname, const std::
return CMD_INVALID;
}
-bool CommandParser::ProcessCommand(LocalUser *user, std::string &cmd)
+void CommandParser::ProcessCommand(LocalUser *user, std::string &cmd)
{
std::vector<std::string> command_p;
irc::tokenstream tokens(cmd);
@@ -196,29 +174,27 @@ bool CommandParser::ProcessCommand(LocalUser *user, std::string &cmd)
if (command[0] == ':')
tokens.GetToken(command);
- while (tokens.GetToken(token) && (command_p.size() <= MAXPARAMETERS))
+ while (tokens.GetToken(token))
command_p.push_back(token);
std::transform(command.begin(), command.end(), command.begin(), ::toupper);
/* find the command, check it exists */
- Commandtable::iterator cm = cmdlist.find(command);
+ Command* handler = GetHandler(command);
/* Modify the user's penalty regardless of whether or not the command exists */
- bool do_more = true;
if (!user->HasPrivPermission("users/flood/no-throttle"))
{
// If it *doesn't* exist, give it a slightly heftier penalty than normal to deter flooding us crap
- user->CommandFloodPenalty += cm != cmdlist.end() ? cm->second->Penalty * 1000 : 2000;
+ user->CommandFloodPenalty += handler ? handler->Penalty * 1000 : 2000;
}
-
- if (cm == cmdlist.end())
+ if (!handler)
{
ModResult MOD_RESULT;
FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, command_p, user, false, cmd));
if (MOD_RESULT == MOD_RES_DENY)
- return true;
+ return;
/*
* This double lookup is in case a module (abbreviation) wishes to change a command.
@@ -227,17 +203,19 @@ bool CommandParser::ProcessCommand(LocalUser *user, std::string &cmd)
* Thanks dz for making me actually understand why this is necessary!
* -- w00t
*/
- cm = cmdlist.find(command);
- if (cm == cmdlist.end())
+ handler = GetHandler(command);
+ if (!handler)
{
if (user->registered == REG_ALL)
- user->WriteNumeric(ERR_UNKNOWNCOMMAND, "%s %s :Unknown command",user->nick.c_str(),command.c_str());
- ServerInstance->stats->statsUnknown++;
- return true;
+ user->WriteNumeric(ERR_UNKNOWNCOMMAND, "%s :Unknown command",command.c_str());
+ ServerInstance->stats.Unknown++;
+ return;
}
}
- if (cm->second->max_params && command_p.size() > cm->second->max_params)
+ // If we were given more parameters than max_params then append the excess parameter(s)
+ // to command_p[maxparams-1], i.e. to the last param that is still allowed
+ if (handler->max_params && command_p.size() > handler->max_params)
{
/*
* command_p input (assuming max_params 1):
@@ -246,32 +224,21 @@ bool CommandParser::ProcessCommand(LocalUser *user, std::string &cmd)
* a
* test
*/
- std::string lparam;
- /*
- * The '-1' here is a clever trick, we'll go backwards throwing everything into a temporary param
- * and then just toss that into the array.
- * -- w00t
- */
- while (command_p.size() > (cm->second->max_params - 1))
- {
- // BE CAREFUL: .end() returns past the end of the vector, hence decrement.
- std::vector<std::string>::iterator it = command_p.end() - 1;
+ // Iterator to the last parameter that will be kept
+ const std::vector<std::string>::iterator lastkeep = command_p.begin() + (handler->max_params - 1);
+ // Iterator to the first excess parameter
+ const std::vector<std::string>::iterator firstexcess = lastkeep + 1;
- lparam.insert(0, " " + *(it));
- command_p.erase(it); // remove last element
+ // Append all excess parameter(s) to the last parameter, seperated by spaces
+ for (std::vector<std::string>::const_iterator i = firstexcess; i != command_p.end(); ++i)
+ {
+ lastkeep->push_back(' ');
+ lastkeep->append(*i);
}
- /* we now have (each iteration):
- * ' test'
- * ' a test'
- * ' is a test' <-- final string
- * ...now remove the ' ' at the start...
- */
- lparam.erase(lparam.begin());
-
- /* param is now 'is a test', which is exactly what we wanted! */
- command_p.push_back(lparam);
+ // Erase the excess parameter(s)
+ command_p.erase(firstexcess, command_p.end());
}
/*
@@ -281,99 +248,102 @@ bool CommandParser::ProcessCommand(LocalUser *user, std::string &cmd)
ModResult MOD_RESULT;
FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, command_p, user, false, cmd));
if (MOD_RESULT == MOD_RES_DENY)
- return true;
+ return;
/* activity resets the ping pending timer */
user->nping = ServerInstance->Time() + user->MyClass->GetPingTime();
- if (cm->second->flags_needed)
+ if (handler->flags_needed)
{
- if (!user->IsModeSet(cm->second->flags_needed))
+ if (!user->IsModeSet(handler->flags_needed))
{
- user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - You do not have the required operator privileges",user->nick.c_str());
- return do_more;
+ user->WriteNumeric(ERR_NOPRIVILEGES, ":Permission Denied - You do not have the required operator privileges");
+ return;
}
+
if (!user->HasPermission(command))
{
- user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to command %s",
- user->nick.c_str(), user->oper->NameStr(), command.c_str());
- return do_more;
+ user->WriteNumeric(ERR_NOPRIVILEGES, ":Permission Denied - Oper type %s does not have access to command %s",
+ user->oper->name.c_str(), command.c_str());
+ return;
}
}
- if ((user->registered == REG_ALL) && (!IS_OPER(user)) && (cm->second->IsDisabled()))
+
+ if ((user->registered == REG_ALL) && (!user->IsOper()) && (handler->IsDisabled()))
{
/* command is disabled! */
if (ServerInstance->Config->DisabledDontExist)
{
- user->WriteNumeric(ERR_UNKNOWNCOMMAND, "%s %s :Unknown command",user->nick.c_str(),command.c_str());
+ user->WriteNumeric(ERR_UNKNOWNCOMMAND, "%s :Unknown command", command.c_str());
}
else
{
- user->WriteNumeric(ERR_UNKNOWNCOMMAND, "%s %s :This command has been disabled.",
- user->nick.c_str(), command.c_str());
+ user->WriteNumeric(ERR_UNKNOWNCOMMAND, "%s :This command has been disabled.", command.c_str());
}
ServerInstance->SNO->WriteToSnoMask('a', "%s denied for %s (%s@%s)",
command.c_str(), user->nick.c_str(), user->ident.c_str(), user->host.c_str());
- return do_more;
+ return;
}
- if ((!command_p.empty()) && (command_p.back().empty()) && (!cm->second->allow_empty_last_param))
+ if ((!command_p.empty()) && (command_p.back().empty()) && (!handler->allow_empty_last_param))
command_p.pop_back();
- if (command_p.size() < cm->second->min_params)
+ if (command_p.size() < handler->min_params)
{
- user->WriteNumeric(ERR_NEEDMOREPARAMS, "%s %s :Not enough parameters.", user->nick.c_str(), command.c_str());
- if ((ServerInstance->Config->SyntaxHints) && (user->registered == REG_ALL) && (cm->second->syntax.length()))
- user->WriteNumeric(RPL_SYNTAX, "%s :SYNTAX %s %s", user->nick.c_str(), cm->second->name.c_str(), cm->second->syntax.c_str());
- return do_more;
+ user->WriteNumeric(ERR_NEEDMOREPARAMS, "%s :Not enough parameters.", command.c_str());
+ if ((ServerInstance->Config->SyntaxHints) && (user->registered == REG_ALL) && (handler->syntax.length()))
+ user->WriteNumeric(RPL_SYNTAX, ":SYNTAX %s %s", handler->name.c_str(), handler->syntax.c_str());
+ return;
}
- if ((user->registered != REG_ALL) && (!cm->second->WorksBeforeReg()))
+
+ if ((user->registered != REG_ALL) && (!handler->WorksBeforeReg()))
{
user->WriteNumeric(ERR_NOTREGISTERED, "%s :You have not registered",command.c_str());
- return do_more;
}
else
{
/* passed all checks.. first, do the (ugly) stats counters. */
- cm->second->use_count++;
- cm->second->total_bytes += cmd.length();
+ handler->use_count++;
/* module calls too */
FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, command_p, user, true, cmd));
if (MOD_RESULT == MOD_RES_DENY)
- return do_more;
+ return;
/*
* WARNING: be careful, the user may be deleted soon
*/
- CmdResult result = cm->second->Handle(command_p, user);
+ CmdResult result = handler->Handle(command_p, user);
- FOREACH_MOD(I_OnPostCommand,OnPostCommand(command, command_p, user, result,cmd));
- return do_more;
+ FOREACH_MOD(OnPostCommand, (handler, command_p, user, result, cmd));
}
}
void CommandParser::RemoveCommand(Command* x)
{
- Commandtable::iterator n = cmdlist.find(x->name);
+ CommandMap::iterator n = cmdlist.find(x->name);
if (n != cmdlist.end() && n->second == x)
cmdlist.erase(n);
}
+CommandBase::~CommandBase()
+{
+}
+
Command::~Command()
{
- ServerInstance->Parser->RemoveCommand(this);
+ ServerInstance->Parser.RemoveCommand(this);
}
-bool CommandParser::ProcessBuffer(std::string &buffer,LocalUser *user)
+void CommandParser::ProcessBuffer(std::string &buffer,LocalUser *user)
{
- if (!user || buffer.empty())
- return true;
+ if (buffer.empty())
+ return;
- ServerInstance->Logs->Log("USERINPUT", RAWIO, "C[%s] I :%s %s",
+ ServerInstance->Logs->Log("USERINPUT", LOG_RAWIO, "C[%s] I :%s %s",
user->uuid.c_str(), user->nick.c_str(), buffer.c_str());
- return ProcessCommand(user,buffer);
+ ProcessCommand(user,buffer);
}
bool CommandParser::AddCommand(Command *f)
@@ -391,88 +361,64 @@ CommandParser::CommandParser()
{
}
-int CommandParser::TranslateUIDs(const std::vector<TranslateType> to, const std::vector<std::string> &source, std::string &dest, bool prefix_final, Command* custom_translator)
+std::string CommandParser::TranslateUIDs(const std::vector<TranslateType>& to, const std::vector<std::string>& source, bool prefix_final, CommandBase* custom_translator)
{
std::vector<TranslateType>::const_iterator types = to.begin();
- User* user = NULL;
- unsigned int i;
- int translations = 0;
- dest.clear();
+ std::string dest;
- for(i=0; i < source.size(); i++)
+ for (unsigned int i = 0; i < source.size(); i++)
{
- TranslateType t;
- std::string item = source[i];
-
- if (types == to.end())
- t = TR_TEXT;
- else
+ TranslateType t = TR_TEXT;
+ // They might supply less translation types than parameters,
+ // in that case pretend that all remaining types are TR_TEXT
+ if (types != to.end())
{
t = *types;
types++;
}
- if (prefix_final && i == source.size() - 1)
- dest.append(":");
+ bool last = (i == (source.size() - 1));
+ if (prefix_final && last)
+ dest.push_back(':');
- switch (t)
- {
- case TR_NICK:
- /* Translate single nickname */
- user = ServerInstance->FindNick(item);
- if (user)
- {
- dest.append(user->uuid);
- translations++;
- }
- else
- dest.append(item);
- break;
- case TR_CUSTOM:
- if (custom_translator)
- custom_translator->EncodeParameter(item, i);
- dest.append(item);
- break;
- case TR_END:
- case TR_TEXT:
- default:
- /* Do nothing */
- dest.append(item);
- break;
- }
- if (i != source.size() - 1)
- dest.append(" ");
+ TranslateSingleParam(t, source[i], dest, custom_translator, i);
+
+ if (!last)
+ dest.push_back(' ');
}
- return translations;
+ return dest;
}
-int CommandParser::TranslateUIDs(TranslateType to, const std::string &source, std::string &dest)
+void CommandParser::TranslateSingleParam(TranslateType to, const std::string& item, std::string& dest, CommandBase* custom_translator, unsigned int paramnumber)
{
- User* user = NULL;
- int translations = 0;
- dest.clear();
-
switch (to)
{
case TR_NICK:
+ {
/* Translate single nickname */
- user = ServerInstance->FindNick(source);
+ User* user = ServerInstance->FindNick(item);
if (user)
+ dest.append(user->uuid);
+ else
+ dest.append(item);
+ break;
+ }
+ case TR_CUSTOM:
+ {
+ if (custom_translator)
{
- dest = user->uuid;
- translations++;
+ std::string translated = item;
+ custom_translator->EncodeParameter(translated, paramnumber);
+ dest.append(translated);
+ break;
}
- else
- dest = source;
- break;
- case TR_END:
+ // If no custom translator was given, fall through
+ }
case TR_TEXT:
default:
/* Do nothing */
- dest = source;
+ dest.append(item);
break;
}
-
- return translations;
}
diff --git a/src/commands.cpp b/src/commands.cpp
index d805a1f65..c72a5dc73 100644
--- a/src/commands.cpp
+++ b/src/commands.cpp
@@ -21,103 +21,7 @@
*/
-/* $Core */
-
#include "inspircd.h"
-#include "xline.h"
-#include "command_parse.h"
-
-/* All other ircds when doing this check usually just look for a string of *@* or *. We're smarter than that, though. */
-
-bool InspIRCd::HostMatchesEveryone(const std::string &mask, User* user)
-{
- long matches = 0;
-
- ConfigTag* insane = Config->ConfValue("insane");
-
- if (insane->getBool("hostmasks"))
- return false;
-
- float itrigger = insane->getFloat("trigger", 95.5);
-
- for (user_hash::iterator u = this->Users->clientlist->begin(); u != this->Users->clientlist->end(); u++)
- {
- if ((InspIRCd::Match(u->second->MakeHost(), mask, ascii_case_insensitive_map)) ||
- (InspIRCd::Match(u->second->MakeHostIP(), mask, ascii_case_insensitive_map)))
- {
- matches++;
- }
- }
-
- if (!matches)
- return false;
-
- float percent = ((float)matches / (float)this->Users->clientlist->size()) * 100;
- if (percent > itrigger)
- {
- SNO->WriteToSnoMask('a', "\2WARNING\2: %s tried to set a G/K/E line mask of %s, which covers %.2f%% of the network!",user->nick.c_str(),mask.c_str(),percent);
- return true;
- }
- return false;
-}
-
-bool InspIRCd::IPMatchesEveryone(const std::string &ip, User* user)
-{
- long matches = 0;
-
- ConfigTag* insane = Config->ConfValue("insane");
-
- if (insane->getBool("ipmasks"))
- return false;
-
- float itrigger = insane->getFloat("trigger", 95.5);
-
- for (user_hash::iterator u = this->Users->clientlist->begin(); u != this->Users->clientlist->end(); u++)
- {
- if (InspIRCd::Match(u->second->GetIPString(), ip, ascii_case_insensitive_map))
- matches++;
- }
-
- if (!matches)
- return false;
-
- float percent = ((float)matches / (float)this->Users->clientlist->size()) * 100;
- if (percent > itrigger)
- {
- SNO->WriteToSnoMask('a', "\2WARNING\2: %s tried to set a Z line mask of %s, which covers %.2f%% of the network!",user->nick.c_str(),ip.c_str(),percent);
- return true;
- }
- return false;
-}
-
-bool InspIRCd::NickMatchesEveryone(const std::string &nick, User* user)
-{
- long matches = 0;
-
- ConfigTag* insane = Config->ConfValue("insane");
-
- if (insane->getBool("nickmasks"))
- return false;
-
- float itrigger = insane->getFloat("trigger", 95.5);
-
- for (user_hash::iterator u = this->Users->clientlist->begin(); u != this->Users->clientlist->end(); u++)
- {
- if (InspIRCd::Match(u->second->nick, nick))
- matches++;
- }
-
- if (!matches)
- return false;
-
- float percent = ((float)matches / (float)this->Users->clientlist->size()) * 100;
- if (percent > itrigger)
- {
- SNO->WriteToSnoMask('a', "\2WARNING\2: %s tried to set a Q line mask of %s, which covers %.2f%% of the network!",user->nick.c_str(),nick.c_str(),percent);
- return true;
- }
- return false;
-}
CmdResult SplitCommand::Handle(const std::vector<std::string>& parms, User* u)
{
@@ -127,7 +31,7 @@ CmdResult SplitCommand::Handle(const std::vector<std::string>& parms, User* u)
return HandleRemote(parms, IS_REMOTE(u));
if (IS_SERVER(u))
return HandleServer(parms, IS_SERVER(u));
- ServerInstance->Logs->Log("COMMAND", DEFAULT, "Unknown user type in command (uuid=%s)!", u->uuid.c_str());
+ ServerInstance->Logs->Log("COMMAND", LOG_DEFAULT, "Unknown user type in command (uuid=%s)!", u->uuid.c_str());
return CMD_INVALID;
}
@@ -145,4 +49,3 @@ CmdResult SplitCommand::HandleServer(const std::vector<std::string>&, FakeUser*)
{
return CMD_INVALID;
}
-
diff --git a/src/commands/cmd_clearcache.cpp b/src/commands/cmd_clearcache.cpp
deleted file mode 100644
index 5914f9a8f..000000000
--- a/src/commands/cmd_clearcache.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-
-/** Handle /CLEARCACHE. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandClearcache : public Command
-{
- public:
- /** Constructor for clearcache.
- */
- CommandClearcache ( Module* parent) : Command(parent,"CLEARCACHE",0) { flags_needed = 'o'; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
-
-/** Handle /CLEARCACHE
- */
-CmdResult CommandClearcache::Handle (const std::vector<std::string>& parameters, User *user)
-{
- int n = ServerInstance->Res->ClearCache();
- user->WriteServ("NOTICE %s :*** Cleared DNS cache of %d items.", user->nick.c_str(), n);
- return CMD_SUCCESS;
-}
-
-COMMAND_INIT(CommandClearcache)
diff --git a/src/commands/cmd_commands.cpp b/src/commands/cmd_commands.cpp
deleted file mode 100644
index 1555b4d04..000000000
--- a/src/commands/cmd_commands.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-
-/** Handle /COMMANDS. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandCommands : public Command
-{
- public:
- /** Constructor for commands.
- */
- CommandCommands(Module* parent) : Command(parent,"COMMANDS",0,0)
- {
- Penalty = 3;
- }
-
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
-
-/** Handle /COMMANDS
- */
-CmdResult CommandCommands::Handle (const std::vector<std::string>&, User *user)
-{
- std::vector<std::string> list;
- list.reserve(ServerInstance->Parser->cmdlist.size());
- for (Commandtable::iterator i = ServerInstance->Parser->cmdlist.begin(); i != ServerInstance->Parser->cmdlist.end(); i++)
- {
- // Don't show S2S commands to users
- if (i->second->flags_needed == FLAG_SERVERONLY)
- continue;
-
- Module* src = i->second->creator;
- char buffer[MAXBUF];
- snprintf(buffer, MAXBUF, ":%s %03d %s :%s %s %d %d",
- ServerInstance->Config->ServerName.c_str(), RPL_COMMANDS, user->nick.c_str(),
- i->second->name.c_str(), src->ModuleSourceFile.c_str(),
- i->second->min_params, i->second->Penalty);
- list.push_back(buffer);
- }
- sort(list.begin(), list.end());
- for(unsigned int i=0; i < list.size(); i++)
- user->Write(list[i]);
- user->WriteNumeric(RPL_COMMANDSEND, "%s :End of COMMANDS list",user->nick.c_str());
- return CMD_SUCCESS;
-}
-
-COMMAND_INIT(CommandCommands)
diff --git a/src/commands/cmd_connect.cpp b/src/commands/cmd_connect.cpp
deleted file mode 100644
index 8fb82fab4..000000000
--- a/src/commands/cmd_connect.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-
-/** Handle /CONNECT. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandConnect : public Command
-{
- public:
- /** Constructor for connect.
- */
- CommandConnect ( Module* parent) : Command(parent,"CONNECT",1) { flags_needed = 'o'; syntax = "<servername>"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
-
-/*
- * This is handled by the server linking module, if necessary. Do not remove this stub.
- */
-
-/** Handle /CONNECT
- */
-CmdResult CommandConnect::Handle (const std::vector<std::string>&, User *user)
-{
- user->WriteServ( "NOTICE %s :Look into loading a linking module (like m_spanningtree) if you want this to do anything useful.", user->nick.c_str());
- return CMD_SUCCESS;
-}
-
-COMMAND_INIT(CommandConnect)
diff --git a/src/commands/cmd_join.cpp b/src/commands/cmd_join.cpp
deleted file mode 100644
index 6124fcc1c..000000000
--- a/src/commands/cmd_join.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-
-/** Handle /JOIN. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandJoin : public Command
-{
- public:
- /** Constructor for join.
- */
- CommandJoin ( Module* parent) : Command(parent,"JOIN", 1, 2) { syntax = "<channel>{,<channel>} {<key>{,<key>}}"; Penalty = 2; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
-
-/** Handle /JOIN
- */
-CmdResult CommandJoin::Handle (const std::vector<std::string>& parameters, User *user)
-{
- if (parameters.size() > 1)
- {
- if (ServerInstance->Parser->LoopCall(user, this, parameters, 0, 1, false))
- return CMD_SUCCESS;
-
- if (ServerInstance->IsChannel(parameters[0].c_str(), ServerInstance->Config->Limits.ChanMax))
- {
- Channel::JoinUser(user, parameters[0].c_str(), false, parameters[1].c_str(), false);
- return CMD_SUCCESS;
- }
- }
- else
- {
- if (ServerInstance->Parser->LoopCall(user, this, parameters, 0, -1, false))
- return CMD_SUCCESS;
-
- if (ServerInstance->IsChannel(parameters[0].c_str(), ServerInstance->Config->Limits.ChanMax))
- {
- Channel::JoinUser(user, parameters[0].c_str(), false, "", false);
- return CMD_SUCCESS;
- }
- }
-
- user->WriteNumeric(ERR_NOSUCHCHANNEL, "%s %s :Invalid channel name",user->nick.c_str(), parameters[0].c_str());
- return CMD_FAILURE;
-}
-
-COMMAND_INIT(CommandJoin)
diff --git a/src/commands/cmd_kick.cpp b/src/commands/cmd_kick.cpp
deleted file mode 100644
index c497dd459..000000000
--- a/src/commands/cmd_kick.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-
-/** Handle /KICK. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandKick : public Command
-{
- public:
- /** Constructor for kick.
- */
- CommandKick ( Module* parent) : Command(parent,"KICK",2,3) { syntax = "<channel> <nick>{,<nick>} [<reason>]"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
-
-/** Handle /KICK
- */
-CmdResult CommandKick::Handle (const std::vector<std::string>& parameters, User *user)
-{
- std::string reason;
- Channel* c = ServerInstance->FindChan(parameters[0]);
- User* u;
-
- if (ServerInstance->Parser->LoopCall(user, this, parameters, 1))
- return CMD_SUCCESS;
-
- if (IS_LOCAL(user))
- u = ServerInstance->FindNickOnly(parameters[1]);
- else
- u = ServerInstance->FindNick(parameters[1]);
-
- if ((!u) || (!c) || (u->registered != REG_ALL))
- {
- user->WriteServ( "401 %s %s :No such nick/channel", user->nick.c_str(), c ? parameters[1].c_str() : parameters[0].c_str());
- return CMD_FAILURE;
- }
-
- if ((IS_LOCAL(user)) && (!c->HasUser(user)) && (!ServerInstance->ULine(user->server)))
- {
- user->WriteServ( "442 %s %s :You're not on that channel!", user->nick.c_str(), parameters[0].c_str());
- return CMD_FAILURE;
- }
-
- if (parameters.size() > 2)
- {
- reason.assign(parameters[2], 0, ServerInstance->Config->Limits.MaxKick);
- }
- else
- {
- reason.assign(user->nick, 0, ServerInstance->Config->Limits.MaxKick);
- }
-
- c->KickUser(user, u, reason.c_str());
-
- return CMD_SUCCESS;
-}
-
-COMMAND_INIT(CommandKick)
diff --git a/src/commands/cmd_links.cpp b/src/commands/cmd_links.cpp
deleted file mode 100644
index f4152ebc5..000000000
--- a/src/commands/cmd_links.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-
-/** Handle /LINKS. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandLinks : public Command
-{
- public:
- /** Constructor for links.
- */
- CommandLinks ( Module* parent) : Command(parent,"LINKS",0,0) { }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
-
-/** Handle /LINKS
- */
-CmdResult CommandLinks::Handle (const std::vector<std::string>&, User *user)
-{
- user->WriteNumeric(364, "%s %s %s :0 %s",user->nick.c_str(),ServerInstance->Config->ServerName.c_str(),ServerInstance->Config->ServerName.c_str(),ServerInstance->Config->ServerDesc.c_str());
- user->WriteNumeric(365, "%s * :End of /LINKS list.",user->nick.c_str());
- return CMD_SUCCESS;
-}
-
-COMMAND_INIT(CommandLinks)
diff --git a/src/commands/cmd_loadmodule.cpp b/src/commands/cmd_loadmodule.cpp
deleted file mode 100644
index 379e597e4..000000000
--- a/src/commands/cmd_loadmodule.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-
-/** Handle /LOADMODULE. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandLoadmodule : public Command
-{
- public:
- /** Constructor for loadmodule.
- */
- CommandLoadmodule ( Module* parent) : Command(parent,"LOADMODULE",1,1) { flags_needed='o'; syntax = "<modulename>"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
-
-/** Handle /LOADMODULE
- */
-CmdResult CommandLoadmodule::Handle (const std::vector<std::string>& parameters, User *user)
-{
- if (ServerInstance->Modules->Load(parameters[0]))
- {
- ServerInstance->SNO->WriteGlobalSno('a', "NEW MODULE: %s loaded %s",user->nick.c_str(), parameters[0].c_str());
- user->WriteNumeric(975, "%s %s :Module successfully loaded.",user->nick.c_str(), parameters[0].c_str());
- return CMD_SUCCESS;
- }
- else
- {
- user->WriteNumeric(974, "%s %s :%s",user->nick.c_str(), parameters[0].c_str(), ServerInstance->Modules->LastError().c_str());
- return CMD_FAILURE;
- }
-}
-
-COMMAND_INIT(CommandLoadmodule)
diff --git a/src/commands/cmd_map.cpp b/src/commands/cmd_map.cpp
deleted file mode 100644
index 385a2c752..000000000
--- a/src/commands/cmd_map.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-
-class CommandMap : public Command
-{
- public:
- /** Constructor for map.
- */
- CommandMap ( Module* parent) : Command(parent,"MAP",0,0) { Penalty=2; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
-
-/** Handle /MAP
- */
-CmdResult CommandMap::Handle (const std::vector<std::string>&, User *user)
-{
- // as with /LUSERS this does nothing without a linking
- // module to override its behaviour and display something
- // better.
-
- if (IS_OPER(user))
- {
- user->WriteNumeric(006, "%s :%s [%s]", user->nick.c_str(), ServerInstance->Config->ServerName.c_str(), ServerInstance->Config->GetSID().c_str());
- user->WriteNumeric(007, "%s :End of /MAP", user->nick.c_str());
- return CMD_SUCCESS;
- }
- user->WriteNumeric(006, "%s :%s",user->nick.c_str(),ServerInstance->Config->ServerName.c_str());
- user->WriteNumeric(007, "%s :End of /MAP",user->nick.c_str());
-
- return CMD_SUCCESS;
-}
-
-COMMAND_INIT(CommandMap)
diff --git a/src/commands/cmd_mode.cpp b/src/commands/cmd_mode.cpp
deleted file mode 100644
index 17e21b182..000000000
--- a/src/commands/cmd_mode.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-
-/** Handle /MODE. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandMode : public Command
-{
- public:
- /** Constructor for mode.
- */
- CommandMode ( Module* parent) : Command(parent,"MODE",1) { syntax = "<target> <modes> {<mode-parameters>}"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
-
-
-/** Handle /MODE
- */
-CmdResult CommandMode::Handle (const std::vector<std::string>& parameters, User *user)
-{
- ServerInstance->Modes->Process(parameters, user, false);
- return CMD_SUCCESS;
-}
-
-
-COMMAND_INIT(CommandMode)
diff --git a/src/commands/cmd_notice.cpp b/src/commands/cmd_notice.cpp
deleted file mode 100644
index d5ef7ba1d..000000000
--- a/src/commands/cmd_notice.cpp
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc>
- * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-/** Handle /NOTICE. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandNotice : public Command
-{
- public:
- /** Constructor for notice.
- */
- CommandNotice ( Module* parent) : Command(parent,"NOTICE",2,2) { syntax = "<target>{,<target>} <message>"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-
- RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
- {
- if (IS_LOCAL(user))
- // This is handled by the OnUserNotice hook to split the LoopCall pieces
- return ROUTE_LOCALONLY;
- else
- return ROUTE_MESSAGE(parameters[0]);
- }
-};
-
-
-CmdResult CommandNotice::Handle (const std::vector<std::string>& parameters, User *user)
-{
- User *dest;
- Channel *chan;
-
- CUList exempt_list;
-
- user->idle_lastmsg = ServerInstance->Time();
-
- if (ServerInstance->Parser->LoopCall(user, this, parameters, 0))
- return CMD_SUCCESS;
- if (parameters[0][0] == '$')
- {
- if (!user->HasPrivPermission("users/mass-message"))
- return CMD_SUCCESS;
-
- ModResult MOD_RESULT;
- std::string temp = parameters[1];
- FIRST_MOD_RESULT(OnUserPreNotice, MOD_RESULT, (user, (void*)parameters[0].c_str(), TYPE_SERVER, temp, 0, exempt_list));
- if (MOD_RESULT == MOD_RES_DENY)
- return CMD_FAILURE;
- const char* text = temp.c_str();
- const char* servermask = (parameters[0].c_str()) + 1;
-
- FOREACH_MOD(I_OnText,OnText(user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, exempt_list));
- if (InspIRCd::Match(ServerInstance->Config->ServerName,servermask, NULL))
- {
- user->SendAll("NOTICE", "%s", text);
- }
- FOREACH_MOD(I_OnUserNotice,OnUserNotice(user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, exempt_list));
- return CMD_SUCCESS;
- }
- char status = 0;
- const char* target = parameters[0].c_str();
-
- if (ServerInstance->Modes->FindPrefix(*target))
- {
- status = *target;
- target++;
- }
- if (*target == '#')
- {
- chan = ServerInstance->FindChan(target);
-
- exempt_list.insert(user);
-
- if (chan)
- {
- if (IS_LOCAL(user))
- {
- if ((chan->IsModeSet('n')) && (!chan->HasUser(user)))
- {
- user->WriteNumeric(404, "%s %s :Cannot send to channel (no external messages)", user->nick.c_str(), chan->name.c_str());
- return CMD_FAILURE;
- }
- if ((chan->IsModeSet('m')) && (chan->GetPrefixValue(user) < VOICE_VALUE))
- {
- user->WriteNumeric(404, "%s %s :Cannot send to channel (+m)", user->nick.c_str(), chan->name.c_str());
- return CMD_FAILURE;
- }
-
- if (ServerInstance->Config->RestrictBannedUsers)
- {
- if (chan->IsBanned(user))
- {
- user->WriteNumeric(404, "%s %s :Cannot send to channel (you're banned)", user->nick.c_str(), chan->name.c_str());
- return CMD_FAILURE;
- }
- }
- }
- ModResult MOD_RESULT;
-
- std::string temp = parameters[1];
- FIRST_MOD_RESULT(OnUserPreNotice, MOD_RESULT, (user,chan,TYPE_CHANNEL,temp,status, exempt_list));
- if (MOD_RESULT == MOD_RES_DENY)
- return CMD_FAILURE;
-
- const char* text = temp.c_str();
-
- if (temp.empty())
- {
- user->WriteNumeric(412, "%s :No text to send", user->nick.c_str());
- return CMD_FAILURE;
- }
-
- FOREACH_MOD(I_OnText,OnText(user,chan,TYPE_CHANNEL,text,status,exempt_list));
-
- if (status)
- {
- if (ServerInstance->Config->UndernetMsgPrefix)
- {
- chan->WriteAllExcept(user, false, status, exempt_list, "NOTICE %c%s :%c %s", status, chan->name.c_str(), status, text);
- }
- else
- {
- chan->WriteAllExcept(user, false, status, exempt_list, "NOTICE %c%s :%s", status, chan->name.c_str(), text);
- }
- }
- else
- {
- chan->WriteAllExcept(user, false, status, exempt_list, "NOTICE %s :%s", chan->name.c_str(), text);
- }
-
- FOREACH_MOD(I_OnUserNotice,OnUserNotice(user,chan,TYPE_CHANNEL,text,status,exempt_list));
- }
- else
- {
- /* no such nick/channel */
- user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), target);
- return CMD_FAILURE;
- }
- return CMD_SUCCESS;
- }
-
- const char* destnick = parameters[0].c_str();
-
- if (IS_LOCAL(user))
- {
- const char* targetserver = strchr(destnick, '@');
-
- if (targetserver)
- {
- std::string nickonly;
-
- nickonly.assign(destnick, 0, targetserver - destnick);
- dest = ServerInstance->FindNickOnly(nickonly);
- if (dest && strcasecmp(dest->server.c_str(), targetserver + 1))
- {
- /* Incorrect server for user */
- user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
- return CMD_FAILURE;
- }
- }
- else
- dest = ServerInstance->FindNickOnly(destnick);
- }
- else
- dest = ServerInstance->FindNick(destnick);
-
- if ((dest) && (dest->registered == REG_ALL))
- {
- if (parameters[1].empty())
- {
- user->WriteNumeric(412, "%s :No text to send", user->nick.c_str());
- return CMD_FAILURE;
- }
-
- ModResult MOD_RESULT;
- std::string temp = parameters[1];
- FIRST_MOD_RESULT(OnUserPreNotice, MOD_RESULT, (user,dest,TYPE_USER,temp,0,exempt_list));
- if (MOD_RESULT == MOD_RES_DENY) {
- return CMD_FAILURE;
- }
- const char* text = temp.c_str();
-
- FOREACH_MOD(I_OnText,OnText(user,dest,TYPE_USER,text,0,exempt_list));
-
- if (IS_LOCAL(dest))
- {
- // direct write, same server
- user->WriteTo(dest, "NOTICE %s :%s", dest->nick.c_str(), text);
- }
-
- FOREACH_MOD(I_OnUserNotice,OnUserNotice(user,dest,TYPE_USER,text,0,exempt_list));
- }
- else
- {
- /* no such nick/channel */
- user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
- return CMD_FAILURE;
- }
-
- return CMD_SUCCESS;
-
-}
-
-COMMAND_INIT(CommandNotice)
diff --git a/src/commands/cmd_oper.cpp b/src/commands/cmd_oper.cpp
deleted file mode 100644
index 1a5e7e178..000000000
--- a/src/commands/cmd_oper.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
- * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-
-bool OneOfMatches(const char* host, const char* ip, const char* hostlist);
-
-/** Handle /OPER. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandOper : public SplitCommand
-{
- public:
- /** Constructor for oper.
- */
- CommandOper ( Module* parent) : SplitCommand(parent,"OPER",2,2) { syntax = "<username> <password>"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult HandleLocal(const std::vector<std::string>& parameters, LocalUser *user);
-};
-
-bool OneOfMatches(const char* host, const char* ip, const std::string& hostlist)
-{
- std::stringstream hl(hostlist);
- std::string xhost;
- while (hl >> xhost)
- {
- if (InspIRCd::Match(host, xhost, ascii_case_insensitive_map) || InspIRCd::MatchCIDR(ip, xhost, ascii_case_insensitive_map))
- {
- return true;
- }
- }
- return false;
-}
-
-CmdResult CommandOper::HandleLocal(const std::vector<std::string>& parameters, LocalUser *user)
-{
- char TheHost[MAXBUF];
- char TheIP[MAXBUF];
- bool match_login = false;
- bool match_pass = false;
- bool match_hosts = false;
-
- snprintf(TheHost,MAXBUF,"%s@%s",user->ident.c_str(),user->host.c_str());
- snprintf(TheIP, MAXBUF,"%s@%s",user->ident.c_str(),user->GetIPString());
-
- OperIndex::iterator i = ServerInstance->Config->oper_blocks.find(parameters[0]);
- if (i != ServerInstance->Config->oper_blocks.end())
- {
- OperInfo* ifo = i->second;
- ConfigTag* tag = ifo->oper_block;
- match_login = true;
- match_pass = !ServerInstance->PassCompare(user, tag->getString("password"), parameters[1], tag->getString("hash"));
- match_hosts = OneOfMatches(TheHost,TheIP,tag->getString("host"));
-
- if (match_pass && match_hosts)
- {
- /* found this oper's opertype */
- user->Oper(ifo);
- return CMD_SUCCESS;
- }
- }
-
- std::string fields;
- if (!match_login)
- fields.append("login ");
- if (!match_pass)
- fields.append("password ");
- if (!match_hosts)
- fields.append("hosts");
-
- // tell them they suck, and lag them up to help prevent brute-force attacks
- user->WriteNumeric(491, "%s :Invalid oper credentials",user->nick.c_str());
- user->CommandFloodPenalty += 10000;
-
- ServerInstance->SNO->WriteGlobalSno('o', "WARNING! Failed oper attempt by %s using login '%s': The following fields do not match: %s", user->GetFullRealHost().c_str(), parameters[0].c_str(), fields.c_str());
- ServerInstance->Logs->Log("OPER",DEFAULT,"OPER: Failed oper attempt by %s using login '%s': The following fields did not match: %s", user->GetFullRealHost().c_str(), parameters[0].c_str(), fields.c_str());
- return CMD_FAILURE;
-}
-
-COMMAND_INIT(CommandOper)
diff --git a/src/commands/cmd_part.cpp b/src/commands/cmd_part.cpp
deleted file mode 100644
index aadb42d90..000000000
--- a/src/commands/cmd_part.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-
-/** Handle /PART. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandPart : public Command
-{
- public:
- /** Constructor for part.
- */
- CommandPart (Module* parent) : Command(parent,"PART", 1, 2) { Penalty = 5; syntax = "<channel>{,<channel>} [<reason>]"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
-
-CmdResult CommandPart::Handle (const std::vector<std::string>& parameters, User *user)
-{
- std::string reason;
-
- if (IS_LOCAL(user))
- {
- if (!ServerInstance->Config->FixedPart.empty())
- reason = ServerInstance->Config->FixedPart;
- else if (parameters.size() > 1)
- reason = ServerInstance->Config->PrefixPart + parameters[1] + ServerInstance->Config->SuffixPart;
- }
- else
- {
- if (parameters.size() > 1)
- reason = parameters[1];
- }
-
- if (ServerInstance->Parser->LoopCall(user, this, parameters, 0))
- return CMD_SUCCESS;
-
- Channel* c = ServerInstance->FindChan(parameters[0]);
-
- if (c)
- {
- c->PartUser(user, reason);
- }
- else
- {
- user->WriteServ( "401 %s %s :No such channel", user->nick.c_str(), parameters[0].c_str());
- return CMD_FAILURE;
- }
-
- return CMD_SUCCESS;
-}
-
-COMMAND_INIT(CommandPart)
diff --git a/src/commands/cmd_pass.cpp b/src/commands/cmd_pass.cpp
deleted file mode 100644
index f082a4ce8..000000000
--- a/src/commands/cmd_pass.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-
-/** Handle /PASS. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandPass : public SplitCommand
-{
- public:
- /** Constructor for pass.
- */
- CommandPass (Module* parent) : SplitCommand(parent,"PASS",1,1) { works_before_reg = true; Penalty = 0; syntax = "<password>"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult HandleLocal(const std::vector<std::string>& parameters, LocalUser *user);
-};
-
-
-CmdResult CommandPass::HandleLocal(const std::vector<std::string>& parameters, LocalUser *user)
-{
- // Check to make sure they haven't registered -- Fix by FCS
- if (user->registered == REG_ALL)
- {
- user->WriteNumeric(ERR_ALREADYREGISTERED, "%s :You may not reregister",user->nick.c_str());
- return CMD_FAILURE;
- }
- user->password = parameters[0];
-
- return CMD_SUCCESS;
-}
-
-COMMAND_INIT(CommandPass)
diff --git a/src/commands/cmd_ping.cpp b/src/commands/cmd_ping.cpp
deleted file mode 100644
index 3ccadd929..000000000
--- a/src/commands/cmd_ping.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-
-/** Handle /PING. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandPing : public Command
-{
- public:
- /** Constructor for ping.
- */
- CommandPing ( Module* parent) : Command(parent,"PING", 1, 2) { Penalty = 0; syntax = "<servername> [:<servername>]"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
-
-CmdResult CommandPing::Handle (const std::vector<std::string>& parameters, User *user)
-{
- user->WriteServ("PONG %s :%s", ServerInstance->Config->ServerName.c_str(), parameters[0].c_str());
- return CMD_SUCCESS;
-}
-
-COMMAND_INIT(CommandPing)
diff --git a/src/commands/cmd_pong.cpp b/src/commands/cmd_pong.cpp
deleted file mode 100644
index 825168de7..000000000
--- a/src/commands/cmd_pong.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-
-/** Handle /PONG. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandPong : public Command
-{
- public:
- /** Constructor for pong.
- */
- CommandPong ( Module* parent) : Command(parent,"PONG", 0, 1) { Penalty = 0; syntax = "<ping-text>"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
-
-CmdResult CommandPong::Handle (const std::vector<std::string>&, User *user)
-{
- // set the user as alive so they survive to next ping
- if (IS_LOCAL(user))
- IS_LOCAL(user)->lastping = 1;
- return CMD_SUCCESS;
-}
-
-COMMAND_INIT(CommandPong)
diff --git a/src/commands/cmd_privmsg.cpp b/src/commands/cmd_privmsg.cpp
deleted file mode 100644
index cefdd4800..000000000
--- a/src/commands/cmd_privmsg.cpp
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc>
- * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-
-/** Handle /PRIVMSG. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandPrivmsg : public Command
-{
- public:
- /** Constructor for privmsg.
- */
- CommandPrivmsg ( Module* parent) : Command(parent,"PRIVMSG",2,2) { syntax = "<target>{,<target>} <message>"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-
- RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
- {
- if (IS_LOCAL(user))
- // This is handled by the OnUserMessage hook to split the LoopCall pieces
- return ROUTE_LOCALONLY;
- else
- return ROUTE_MESSAGE(parameters[0]);
- }
-};
-
-CmdResult CommandPrivmsg::Handle (const std::vector<std::string>& parameters, User *user)
-{
- User *dest;
- Channel *chan;
- CUList except_list;
-
- user->idle_lastmsg = ServerInstance->Time();
-
- if (ServerInstance->Parser->LoopCall(user, this, parameters, 0))
- return CMD_SUCCESS;
-
- if (parameters[0][0] == '$')
- {
- if (!user->HasPrivPermission("users/mass-message"))
- return CMD_SUCCESS;
-
- ModResult MOD_RESULT;
- std::string temp = parameters[1];
- FIRST_MOD_RESULT(OnUserPreMessage, MOD_RESULT, (user, (void*)parameters[0].c_str(), TYPE_SERVER, temp, 0, except_list));
- if (MOD_RESULT == MOD_RES_DENY)
- return CMD_FAILURE;
-
- const char* text = temp.c_str();
- const char* servermask = (parameters[0].c_str()) + 1;
-
- FOREACH_MOD(I_OnText,OnText(user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, except_list));
- if (InspIRCd::Match(ServerInstance->Config->ServerName, servermask, NULL))
- {
- user->SendAll("PRIVMSG", "%s", text);
- }
- FOREACH_MOD(I_OnUserMessage,OnUserMessage(user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, except_list));
- return CMD_SUCCESS;
- }
- char status = 0;
- const char* target = parameters[0].c_str();
-
- if (ServerInstance->Modes->FindPrefix(*target))
- {
- status = *target;
- target++;
- }
- if (*target == '#')
- {
- chan = ServerInstance->FindChan(target);
-
- except_list.insert(user);
-
- if (chan)
- {
- if (IS_LOCAL(user) && chan->GetPrefixValue(user) < VOICE_VALUE)
- {
- if (chan->IsModeSet('n') && !chan->HasUser(user))
- {
- user->WriteNumeric(404, "%s %s :Cannot send to channel (no external messages)", user->nick.c_str(), chan->name.c_str());
- return CMD_FAILURE;
- }
-
- if (chan->IsModeSet('m'))
- {
- user->WriteNumeric(404, "%s %s :Cannot send to channel (+m)", user->nick.c_str(), chan->name.c_str());
- return CMD_FAILURE;
- }
-
- if (ServerInstance->Config->RestrictBannedUsers)
- {
- if (chan->IsBanned(user))
- {
- user->WriteNumeric(404, "%s %s :Cannot send to channel (you're banned)", user->nick.c_str(), chan->name.c_str());
- return CMD_FAILURE;
- }
- }
- }
- ModResult MOD_RESULT;
-
- std::string temp = parameters[1];
- FIRST_MOD_RESULT(OnUserPreMessage, MOD_RESULT, (user,chan,TYPE_CHANNEL,temp,status,except_list));
- if (MOD_RESULT == MOD_RES_DENY)
- return CMD_FAILURE;
-
- const char* text = temp.c_str();
-
- /* Check again, a module may have zapped the input string */
- if (temp.empty())
- {
- user->WriteNumeric(412, "%s :No text to send", user->nick.c_str());
- return CMD_FAILURE;
- }
-
- FOREACH_MOD(I_OnText,OnText(user,chan,TYPE_CHANNEL,text,status,except_list));
-
- if (status)
- {
- if (ServerInstance->Config->UndernetMsgPrefix)
- {
- chan->WriteAllExcept(user, false, status, except_list, "PRIVMSG %c%s :%c %s", status, chan->name.c_str(), status, text);
- }
- else
- {
- chan->WriteAllExcept(user, false, status, except_list, "PRIVMSG %c%s :%s", status, chan->name.c_str(), text);
- }
- }
- else
- {
- chan->WriteAllExcept(user, false, status, except_list, "PRIVMSG %s :%s", chan->name.c_str(), text);
- }
-
- FOREACH_MOD(I_OnUserMessage,OnUserMessage(user,chan,TYPE_CHANNEL,text,status,except_list));
- }
- else
- {
- /* no such nick/channel */
- user->WriteNumeric(401, "%s %s :No such nick/channel", user->nick.c_str(), target);
- return CMD_FAILURE;
- }
- return CMD_SUCCESS;
- }
-
- const char* destnick = parameters[0].c_str();
-
- if (IS_LOCAL(user))
- {
- const char* targetserver = strchr(destnick, '@');
-
- if (targetserver)
- {
- std::string nickonly;
-
- nickonly.assign(destnick, 0, targetserver - destnick);
- dest = ServerInstance->FindNickOnly(nickonly);
- if (dest && strcasecmp(dest->server.c_str(), targetserver + 1))
- {
- /* Incorrect server for user */
- user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
- return CMD_FAILURE;
- }
- }
- else
- dest = ServerInstance->FindNickOnly(destnick);
- }
- else
- dest = ServerInstance->FindNick(destnick);
-
- if ((dest) && (dest->registered == REG_ALL))
- {
- if (parameters[1].empty())
- {
- user->WriteNumeric(412, "%s :No text to send", user->nick.c_str());
- return CMD_FAILURE;
- }
-
- if (IS_AWAY(dest))
- {
- /* auto respond with aweh msg */
- user->WriteNumeric(301, "%s %s :%s", user->nick.c_str(), dest->nick.c_str(), dest->awaymsg.c_str());
- }
-
- ModResult MOD_RESULT;
-
- std::string temp = parameters[1];
- FIRST_MOD_RESULT(OnUserPreMessage, MOD_RESULT, (user, dest, TYPE_USER, temp, 0, except_list));
- if (MOD_RESULT == MOD_RES_DENY)
- return CMD_FAILURE;
-
- const char* text = temp.c_str();
-
- FOREACH_MOD(I_OnText,OnText(user, dest, TYPE_USER, text, 0, except_list));
-
- if (IS_LOCAL(dest))
- {
- // direct write, same server
- user->WriteTo(dest, "PRIVMSG %s :%s", dest->nick.c_str(), text);
- }
-
- FOREACH_MOD(I_OnUserMessage,OnUserMessage(user, dest, TYPE_USER, text, 0, except_list));
- }
- else
- {
- /* no such nick/channel */
- user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
- return CMD_FAILURE;
- }
- return CMD_SUCCESS;
-}
-
-COMMAND_INIT(CommandPrivmsg)
diff --git a/src/commands/cmd_quit.cpp b/src/commands/cmd_quit.cpp
deleted file mode 100644
index 6a6b447e5..000000000
--- a/src/commands/cmd_quit.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-
-/** Handle /QUIT. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandQuit : public Command
-{
- public:
- /** Constructor for quit.
- */
- CommandQuit ( Module* parent) : Command(parent,"QUIT",0,1) { works_before_reg = true; syntax = "[<message>]"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
-
-
-CmdResult CommandQuit::Handle (const std::vector<std::string>& parameters, User *user)
-{
-
- std::string quitmsg;
-
- if (IS_LOCAL(user))
- {
- if (!ServerInstance->Config->FixedQuit.empty())
- quitmsg = ServerInstance->Config->FixedQuit;
- else
- quitmsg = parameters.size() ?
- ServerInstance->Config->PrefixQuit + std::string(parameters[0]) + ServerInstance->Config->SuffixQuit
- : "Client exited";
- }
- else
- quitmsg = parameters.size() ? parameters[0] : "Client exited";
-
- std::string* operquit = ServerInstance->OperQuit.get(user);
- if (operquit)
- {
- ServerInstance->Users->QuitUser(user, quitmsg, operquit->c_str());
- }
- else
- {
- ServerInstance->Users->QuitUser(user, quitmsg);
- }
-
- return CMD_SUCCESS;
-}
-
-
-COMMAND_INIT(CommandQuit)
diff --git a/src/commands/cmd_rules.cpp b/src/commands/cmd_rules.cpp
deleted file mode 100644
index 5d41aa4b8..000000000
--- a/src/commands/cmd_rules.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-
-/** Handle /RULES. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandRules : public Command
-{
- public:
- /** Constructor for rules.
- */
- CommandRules ( Module* parent) : Command(parent,"RULES",0,0) { syntax = "[<servername>]"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
- RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
- {
- if (parameters.size() > 0)
- return ROUTE_UNICAST(parameters[0]);
- return ROUTE_LOCALONLY;
- }
-};
-
-CmdResult CommandRules::Handle (const std::vector<std::string>& parameters, User *user)
-{
- if (parameters.size() > 0 && parameters[0] != ServerInstance->Config->ServerName)
- return CMD_SUCCESS;
-
- ConfigTag* tag = NULL;
- if (IS_LOCAL(user))
- tag = user->GetClass()->config;
- std::string rules_name = tag->getString("rules", "rules");
- ConfigFileCache::iterator rules = ServerInstance->Config->Files.find(rules_name);
- if (rules == ServerInstance->Config->Files.end())
- {
- user->SendText(":%s %03d %s :RULES file is missing.",
- ServerInstance->Config->ServerName.c_str(), ERR_NORULES, user->nick.c_str());
- return CMD_SUCCESS;
- }
- user->SendText(":%s %03d %s :%s server rules:", ServerInstance->Config->ServerName.c_str(),
- RPL_RULESTART, user->nick.c_str(), ServerInstance->Config->ServerName.c_str());
-
- for (file_cache::iterator i = rules->second.begin(); i != rules->second.end(); i++)
- user->SendText(":%s %03d %s :- %s", ServerInstance->Config->ServerName.c_str(), RPL_RULES, user->nick.c_str(),i->c_str());
-
- user->SendText(":%s %03d %s :End of RULES command.", ServerInstance->Config->ServerName.c_str(), RPL_RULESEND, user->nick.c_str());
-
- return CMD_SUCCESS;
-}
-
-COMMAND_INIT(CommandRules)
diff --git a/src/commands/cmd_server.cpp b/src/commands/cmd_server.cpp
deleted file mode 100644
index d54eca392..000000000
--- a/src/commands/cmd_server.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-
-/** Handle /SERVER. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandServer : public Command
-{
- public:
- /** Constructor for server.
- */
- CommandServer ( Module* parent) : Command(parent,"SERVER") { works_before_reg = true;}
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
-
-CmdResult CommandServer::Handle (const std::vector<std::string>&, User *user)
-{
- if (user->registered == REG_ALL)
- {
- user->WriteNumeric(ERR_ALREADYREGISTERED, "%s :You are already registered. (Perhaps your IRC client does not have a /SERVER command).",user->nick.c_str());
- }
- else
- {
- user->WriteNumeric(ERR_NOTREGISTERED, "%s :You may not register as a server (servers have separate ports from clients, change your config)",name.c_str());
- }
- return CMD_FAILURE;
-}
-
-COMMAND_INIT(CommandServer)
diff --git a/src/commands/cmd_squit.cpp b/src/commands/cmd_squit.cpp
deleted file mode 100644
index ce73ee05b..000000000
--- a/src/commands/cmd_squit.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-
-/** Handle /SQUIT. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandSquit : public Command
-{
- public:
- /** Constructor for squit.
- */
- CommandSquit ( Module* parent) : Command(parent,"SQUIT",1,2) { flags_needed = 'o'; syntax = "<servername>"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
-
-
-/*
- * This is handled by the server linking module, if necessary. Do not remove this stub.
- */
-
-
-CmdResult CommandSquit::Handle (const std::vector<std::string>&, User *user)
-{
- user->WriteServ( "NOTICE %s :Look into loading a linking module (like m_spanningtree) if you want this to do anything useful.", user->nick.c_str());
- return CMD_FAILURE;
-}
-
-COMMAND_INIT(CommandSquit)
diff --git a/src/commands/cmd_stats.cpp b/src/commands/cmd_stats.cpp
deleted file mode 100644
index 9399b7bea..000000000
--- a/src/commands/cmd_stats.cpp
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc>
- * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-#include "xline.h"
-#include "commands/cmd_whowas.h"
-
-#ifdef _WIN32
-#include <psapi.h>
-#pragma comment(lib, "psapi.lib") // For GetProcessMemoryInfo()
-#endif
-
-/** Handle /STATS. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandStats : public Command
-{
- void DoStats(char statschar, User* user, string_list &results);
- public:
- /** Constructor for stats.
- */
- CommandStats ( Module* parent) : Command(parent,"STATS",1,2) { syntax = "<stats-symbol> [<servername>]"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
- RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
- {
- if (parameters.size() > 1)
- return ROUTE_UNICAST(parameters[1]);
- return ROUTE_LOCALONLY;
- }
-};
-
-void CommandStats::DoStats(char statschar, User* user, string_list &results)
-{
- std::string sn(ServerInstance->Config->ServerName);
-
- bool isPublic = ServerInstance->Config->UserStats.find(statschar) != std::string::npos;
- bool isRemoteOper = IS_REMOTE(user) && IS_OPER(user);
- bool isLocalOperWithPrivs = IS_LOCAL(user) && user->HasPrivPermission("servers/auspex");
-
- if (!isPublic && !isRemoteOper && !isLocalOperWithPrivs)
- {
- ServerInstance->SNO->WriteToSnoMask('t',
- "%s '%c' denied for %s (%s@%s)",
- (IS_LOCAL(user) ? "Stats" : "Remote stats"),
- statschar, user->nick.c_str(), user->ident.c_str(), user->host.c_str());
- results.push_back(sn + " 481 " + user->nick + " :Permission denied - STATS " + statschar + " requires the servers/auspex priv.");
- return;
- }
-
- ModResult MOD_RESULT;
- FIRST_MOD_RESULT(OnStats, MOD_RESULT, (statschar, user, results));
- if (MOD_RESULT == MOD_RES_DENY)
- {
- results.push_back(sn+" 219 "+user->nick+" "+statschar+" :End of /STATS report");
- ServerInstance->SNO->WriteToSnoMask('t',"%s '%c' requested by %s (%s@%s)",
- (IS_LOCAL(user) ? "Stats" : "Remote stats"), statschar, user->nick.c_str(), user->ident.c_str(), user->host.c_str());
- return;
- }
-
- switch (statschar)
- {
- /* stats p (show listening ports) */
- case 'p':
- {
- for (std::vector<ListenSocket*>::const_iterator i = ServerInstance->ports.begin(); i != ServerInstance->ports.end(); ++i)
- {
- ListenSocket* ls = *i;
- std::string ip = ls->bind_addr;
- if (ip.empty())
- ip.assign("*");
- std::string type = ls->bind_tag->getString("type", "clients");
- std::string hook = ls->bind_tag->getString("ssl", "plaintext");
-
- results.push_back(sn+" 249 "+user->nick+" :"+ ip + ":"+ConvToStr(ls->bind_port)+
- " (" + type + ", " + hook + ")");
- }
- }
- break;
-
- /* These stats symbols must be handled by a linking module */
- case 'n':
- case 'c':
- break;
-
- case 'i':
- {
- for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++)
- {
- ConnectClass* c = *i;
- std::stringstream res;
- res << sn << " 215 " << user->nick << " I " << c->name << ' ';
- if (c->type == CC_ALLOW)
- res << '+';
- if (c->type == CC_DENY)
- res << '-';
-
- if (c->type == CC_NAMED)
- res << '*';
- else
- res << c->host;
-
- res << ' ' << c->config->getString("port", "*") << ' ';
-
- res << c->GetRecvqMax() << ' ' << c->GetSendqSoftMax() << ' ' << c->GetSendqHardMax()
- << ' ' << c->GetCommandRate() << ' ' << c->GetPenaltyThreshold();
- if (c->fakelag)
- res << '*';
- results.push_back(res.str());
- }
- }
- break;
-
- case 'Y':
- {
- int idx = 0;
- for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++)
- {
- ConnectClass* c = *i;
- results.push_back(sn+" 215 "+user->nick+" i NOMATCH * "+c->GetHost()+" "+ConvToStr(c->limit ? c->limit : ServerInstance->SE->GetMaxFds())+" "+ConvToStr(idx)+" "+ServerInstance->Config->ServerName+" *");
- results.push_back(sn+" 218 "+user->nick+" Y "+ConvToStr(idx)+" "+ConvToStr(c->GetPingTime())+" 0 "+ConvToStr(c->GetSendqHardMax())+" :"+
- ConvToStr(c->GetRecvqMax())+" "+ConvToStr(c->GetRegTimeout()));
- idx++;
- }
- }
- break;
-
- case 'U':
- {
- for(std::map<irc::string, bool>::iterator i = ServerInstance->Config->ulines.begin(); i != ServerInstance->Config->ulines.end(); ++i)
- {
- results.push_back(sn+" 248 "+user->nick+" U "+std::string(i->first.c_str()));
- }
- }
- break;
-
- case 'P':
- {
- unsigned int idx = 0;
- for (std::list<User*>::const_iterator i = ServerInstance->Users->all_opers.begin(); i != ServerInstance->Users->all_opers.end(); ++i)
- {
- User* oper = *i;
- if (!ServerInstance->ULine(oper->server))
- {
- results.push_back(sn+" 249 " + user->nick + " :" + oper->nick + " (" + oper->ident + "@" + oper->dhost + ") Idle: " +
- (IS_LOCAL(oper) ? ConvToStr(ServerInstance->Time() - oper->idle_lastmsg) + " secs" : "unavailable"));
- idx++;
- }
- }
- results.push_back(sn+" 249 "+user->nick+" :"+ConvToStr(idx)+" OPER(s)");
- }
- break;
-
- case 'k':
- ServerInstance->XLines->InvokeStats("K",216,user,results);
- break;
- case 'g':
- ServerInstance->XLines->InvokeStats("G",223,user,results);
- break;
- case 'q':
- ServerInstance->XLines->InvokeStats("Q",217,user,results);
- break;
- case 'Z':
- ServerInstance->XLines->InvokeStats("Z",223,user,results);
- break;
- case 'e':
- ServerInstance->XLines->InvokeStats("E",223,user,results);
- break;
- case 'E':
- results.push_back(sn+" 249 "+user->nick+" :Total events: "+ConvToStr(ServerInstance->SE->TotalEvents));
- results.push_back(sn+" 249 "+user->nick+" :Read events: "+ConvToStr(ServerInstance->SE->ReadEvents));
- results.push_back(sn+" 249 "+user->nick+" :Write events: "+ConvToStr(ServerInstance->SE->WriteEvents));
- results.push_back(sn+" 249 "+user->nick+" :Error events: "+ConvToStr(ServerInstance->SE->ErrorEvents));
- break;
-
- /* stats m (list number of times each command has been used, plus bytecount) */
- case 'm':
- for (Commandtable::iterator i = ServerInstance->Parser->cmdlist.begin(); i != ServerInstance->Parser->cmdlist.end(); i++)
- {
- if (i->second->use_count)
- {
- /* RPL_STATSCOMMANDS */
- results.push_back(sn+" 212 "+user->nick+" "+i->second->name+" "+ConvToStr(i->second->use_count)+" "+ConvToStr(i->second->total_bytes));
- }
- }
- break;
-
- /* stats z (debug and memory info) */
- case 'z':
- {
- results.push_back(sn+" 249 "+user->nick+" :Users: "+ConvToStr(ServerInstance->Users->clientlist->size()));
- results.push_back(sn+" 249 "+user->nick+" :Channels: "+ConvToStr(ServerInstance->chanlist->size()));
- results.push_back(sn+" 249 "+user->nick+" :Commands: "+ConvToStr(ServerInstance->Parser->cmdlist.size()));
-
- if (ServerInstance->Config->WhoWasGroupSize && ServerInstance->Config->WhoWasMaxGroups)
- {
- Module* whowas = ServerInstance->Modules->Find("cmd_whowas.so");
- if (whowas)
- {
- WhowasRequest req(NULL, whowas, WhowasRequest::WHOWAS_STATS);
- req.user = user;
- req.Send();
- results.push_back(sn+" 249 "+user->nick+" :"+req.value);
- }
- }
-
- float kbitpersec_in, kbitpersec_out, kbitpersec_total;
- char kbitpersec_in_s[30], kbitpersec_out_s[30], kbitpersec_total_s[30];
-
- ServerInstance->SE->GetStats(kbitpersec_in, kbitpersec_out, kbitpersec_total);
-
- snprintf(kbitpersec_total_s, 30, "%03.5f", kbitpersec_total);
- snprintf(kbitpersec_out_s, 30, "%03.5f", kbitpersec_out);
- snprintf(kbitpersec_in_s, 30, "%03.5f", kbitpersec_in);
-
- results.push_back(sn+" 249 "+user->nick+" :Bandwidth total: "+ConvToStr(kbitpersec_total_s)+" kilobits/sec");
- results.push_back(sn+" 249 "+user->nick+" :Bandwidth out: "+ConvToStr(kbitpersec_out_s)+" kilobits/sec");
- results.push_back(sn+" 249 "+user->nick+" :Bandwidth in: "+ConvToStr(kbitpersec_in_s)+" kilobits/sec");
-
-#ifndef _WIN32
- /* Moved this down here so all the not-windows stuff (look w00tie, I didn't say win32!) is in one ifndef.
- * Also cuts out some identical code in both branches of the ifndef. -- Om
- */
- rusage R;
-
- /* Not sure why we were doing '0' with a RUSAGE_SELF comment rather than just using RUSAGE_SELF -- Om */
- if (!getrusage(RUSAGE_SELF,&R)) /* RUSAGE_SELF */
- {
- results.push_back(sn+" 249 "+user->nick+" :Total allocation: "+ConvToStr(R.ru_maxrss)+"K");
- results.push_back(sn+" 249 "+user->nick+" :Signals: "+ConvToStr(R.ru_nsignals));
- results.push_back(sn+" 249 "+user->nick+" :Page faults: "+ConvToStr(R.ru_majflt));
- results.push_back(sn+" 249 "+user->nick+" :Swaps: "+ConvToStr(R.ru_nswap));
- results.push_back(sn+" 249 "+user->nick+" :Context Switches: Voluntary; "+ConvToStr(R.ru_nvcsw)+" Involuntary; "+ConvToStr(R.ru_nivcsw));
-
- char percent[30];
-
- float n_elapsed = (ServerInstance->Time() - ServerInstance->stats->LastSampled.tv_sec) * 1000000
- + (ServerInstance->Time_ns() - ServerInstance->stats->LastSampled.tv_nsec) / 1000;
- float n_eaten = ((R.ru_utime.tv_sec - ServerInstance->stats->LastCPU.tv_sec) * 1000000 + R.ru_utime.tv_usec - ServerInstance->stats->LastCPU.tv_usec);
- float per = (n_eaten / n_elapsed) * 100;
-
- snprintf(percent, 30, "%03.5f%%", per);
- results.push_back(sn+" 249 "+user->nick+" :CPU Use (now): "+percent);
-
- n_elapsed = ServerInstance->Time() - ServerInstance->startup_time;
- n_eaten = (float)R.ru_utime.tv_sec + R.ru_utime.tv_usec / 100000.0;
- per = (n_eaten / n_elapsed) * 100;
- snprintf(percent, 30, "%03.5f%%", per);
- results.push_back(sn+" 249 "+user->nick+" :CPU Use (total): "+percent);
- }
-#else
- PROCESS_MEMORY_COUNTERS MemCounters;
- if (GetProcessMemoryInfo(GetCurrentProcess(), &MemCounters, sizeof(MemCounters)))
- {
- results.push_back(sn+" 249 "+user->nick+" :Total allocation: "+ConvToStr((MemCounters.WorkingSetSize + MemCounters.PagefileUsage) / 1024)+"K");
- results.push_back(sn+" 249 "+user->nick+" :Pagefile usage: "+ConvToStr(MemCounters.PagefileUsage / 1024)+"K");
- results.push_back(sn+" 249 "+user->nick+" :Page faults: "+ConvToStr(MemCounters.PageFaultCount));
- }
-
- FILETIME CreationTime;
- FILETIME ExitTime;
- FILETIME KernelTime;
- FILETIME UserTime;
- LARGE_INTEGER ThisSample;
- if(GetProcessTimes(GetCurrentProcess(), &CreationTime, &ExitTime, &KernelTime, &UserTime) &&
- QueryPerformanceCounter(&ThisSample))
- {
- KernelTime.dwHighDateTime += UserTime.dwHighDateTime;
- KernelTime.dwLowDateTime += UserTime.dwLowDateTime;
- double n_eaten = (double)( ( (uint64_t)(KernelTime.dwHighDateTime - ServerInstance->stats->LastCPU.dwHighDateTime) << 32 ) + (uint64_t)(KernelTime.dwLowDateTime - ServerInstance->stats->LastCPU.dwLowDateTime) )/100000;
- double n_elapsed = (double)(ThisSample.QuadPart - ServerInstance->stats->LastSampled.QuadPart) / ServerInstance->stats->QPFrequency.QuadPart;
- double per = (n_eaten/n_elapsed);
-
- char percent[30];
-
- snprintf(percent, 30, "%03.5f%%", per);
- results.push_back(sn+" 249 "+user->nick+" :CPU Use (now): "+percent);
-
- n_elapsed = ServerInstance->Time() - ServerInstance->startup_time;
- n_eaten = (double)(( (uint64_t)(KernelTime.dwHighDateTime) << 32 ) + (uint64_t)(KernelTime.dwLowDateTime))/100000;
- per = (n_eaten / n_elapsed);
- snprintf(percent, 30, "%03.5f%%", per);
- results.push_back(sn+" 249 "+user->nick+" :CPU Use (total): "+percent);
- }
-#endif
- }
- break;
-
- case 'T':
- {
- char buffer[MAXBUF];
- results.push_back(sn+" 249 "+user->nick+" :accepts "+ConvToStr(ServerInstance->stats->statsAccept)+" refused "+ConvToStr(ServerInstance->stats->statsRefused));
- results.push_back(sn+" 249 "+user->nick+" :unknown commands "+ConvToStr(ServerInstance->stats->statsUnknown));
- results.push_back(sn+" 249 "+user->nick+" :nick collisions "+ConvToStr(ServerInstance->stats->statsCollisions));
- results.push_back(sn+" 249 "+user->nick+" :dns requests "+ConvToStr(ServerInstance->stats->statsDnsGood+ServerInstance->stats->statsDnsBad)+" succeeded "+ConvToStr(ServerInstance->stats->statsDnsGood)+" failed "+ConvToStr(ServerInstance->stats->statsDnsBad));
- results.push_back(sn+" 249 "+user->nick+" :connection count "+ConvToStr(ServerInstance->stats->statsConnects));
- snprintf(buffer,MAXBUF," 249 %s :bytes sent %5.2fK recv %5.2fK",
- user->nick.c_str(),ServerInstance->stats->statsSent / 1024.0,ServerInstance->stats->statsRecv / 1024.0);
- results.push_back(sn+buffer);
- }
- break;
-
- /* stats o */
- case 'o':
- {
- ConfigTagList tags = ServerInstance->Config->ConfTags("oper");
- for(ConfigIter i = tags.first; i != tags.second; ++i)
- {
- ConfigTag* tag = i->second;
- results.push_back(sn+" 243 "+user->nick+" O "+tag->getString("host")+" * "+
- tag->getString("name") + " " + tag->getString("type")+" 0");
- }
- }
- break;
- case 'O':
- {
- for(OperIndex::iterator i = ServerInstance->Config->oper_blocks.begin(); i != ServerInstance->Config->oper_blocks.end(); i++)
- {
- // just the types, not the actual oper blocks...
- if (i->first[0] != ' ')
- continue;
- OperInfo* tag = i->second;
- tag->init();
- std::string umodes;
- std::string cmodes;
- for(char c='A'; c <= 'z'; c++)
- {
- ModeHandler* mh = ServerInstance->Modes->FindMode(c, MODETYPE_USER);
- if (mh && mh->NeedsOper() && tag->AllowedUserModes[c - 'A'])
- umodes.push_back(c);
- mh = ServerInstance->Modes->FindMode(c, MODETYPE_CHANNEL);
- if (mh && mh->NeedsOper() && tag->AllowedChanModes[c - 'A'])
- cmodes.push_back(c);
- }
- results.push_back(sn+" 243 "+user->nick+" O "+tag->NameStr() + " " + umodes + " " + cmodes);
- }
- }
- break;
-
- /* stats l (show user I/O stats) */
- case 'l':
- results.push_back(sn+" 211 "+user->nick+" :nick[ident@host] sendq cmds_out bytes_out cmds_in bytes_in time_open");
- for (LocalUserList::iterator n = ServerInstance->Users->local_users.begin(); n != ServerInstance->Users->local_users.end(); n++)
- {
- LocalUser* i = *n;
- results.push_back(sn+" 211 "+user->nick+" "+i->nick+"["+i->ident+"@"+i->dhost+"] "+ConvToStr(i->eh.getSendQSize())+" "+ConvToStr(i->cmds_out)+" "+ConvToStr(i->bytes_out)+" "+ConvToStr(i->cmds_in)+" "+ConvToStr(i->bytes_in)+" "+ConvToStr(ServerInstance->Time() - i->age));
- }
- break;
-
- /* stats L (show user I/O stats with IP addresses) */
- case 'L':
- results.push_back(sn+" 211 "+user->nick+" :nick[ident@ip] sendq cmds_out bytes_out cmds_in bytes_in time_open");
- for (LocalUserList::iterator n = ServerInstance->Users->local_users.begin(); n != ServerInstance->Users->local_users.end(); n++)
- {
- LocalUser* i = *n;
- results.push_back(sn+" 211 "+user->nick+" "+i->nick+"["+i->ident+"@"+i->GetIPString()+"] "+ConvToStr(i->eh.getSendQSize())+" "+ConvToStr(i->cmds_out)+" "+ConvToStr(i->bytes_out)+" "+ConvToStr(i->cmds_in)+" "+ConvToStr(i->bytes_in)+" "+ConvToStr(ServerInstance->Time() - i->age));
- }
- break;
-
- /* stats u (show server uptime) */
- case 'u':
- {
- time_t current_time = 0;
- current_time = ServerInstance->Time();
- time_t server_uptime = current_time - ServerInstance->startup_time;
- struct tm* stime;
- stime = gmtime(&server_uptime);
- /* i dont know who the hell would have an ircd running for over a year nonstop, but
- * Craig suggested this, and it seemed a good idea so in it went */
- if (stime->tm_year > 70)
- {
- char buffer[MAXBUF];
- snprintf(buffer,MAXBUF," 242 %s :Server up %d years, %d days, %.2d:%.2d:%.2d",user->nick.c_str(),(stime->tm_year-70),stime->tm_yday,stime->tm_hour,stime->tm_min,stime->tm_sec);
- results.push_back(sn+buffer);
- }
- else
- {
- char buffer[MAXBUF];
- snprintf(buffer,MAXBUF," 242 %s :Server up %d days, %.2d:%.2d:%.2d",user->nick.c_str(),stime->tm_yday,stime->tm_hour,stime->tm_min,stime->tm_sec);
- results.push_back(sn+buffer);
- }
- }
- break;
-
- default:
- break;
- }
-
- results.push_back(sn+" 219 "+user->nick+" "+statschar+" :End of /STATS report");
- ServerInstance->SNO->WriteToSnoMask('t',"%s '%c' requested by %s (%s@%s)",
- (IS_LOCAL(user) ? "Stats" : "Remote stats"), statschar, user->nick.c_str(), user->ident.c_str(), user->host.c_str());
- return;
-}
-
-CmdResult CommandStats::Handle (const std::vector<std::string>& parameters, User *user)
-{
- if (parameters.size() > 1 && parameters[1] != ServerInstance->Config->ServerName)
- return CMD_SUCCESS;
- string_list values;
- char search = parameters[0][0];
- DoStats(search, user, values);
- for (size_t i = 0; i < values.size(); i++)
- user->SendText(":%s", values[i].c_str());
-
- return CMD_SUCCESS;
-}
-
-COMMAND_INIT(CommandStats)
diff --git a/src/commands/cmd_time.cpp b/src/commands/cmd_time.cpp
deleted file mode 100644
index db452d381..000000000
--- a/src/commands/cmd_time.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-
-/** Handle /TIME. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandTime : public Command
-{
- public:
- /** Constructor for time.
- */
- CommandTime ( Module* parent) : Command(parent,"TIME",0,0) { syntax = "[<servername>]"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
- RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
- {
- if (parameters.size() > 0)
- return ROUTE_UNICAST(parameters[0]);
- return ROUTE_LOCALONLY;
- }
-};
-
-CmdResult CommandTime::Handle (const std::vector<std::string>& parameters, User *user)
-{
- if (parameters.size() > 0 && parameters[0] != ServerInstance->Config->ServerName)
- return CMD_SUCCESS;
- struct tm* timeinfo;
- time_t local = ServerInstance->Time();
-
- timeinfo = localtime(&local);
-
- char tms[26];
- snprintf(tms,26,"%s",asctime(timeinfo));
- tms[24] = 0;
-
- user->SendText(":%s %03d %s %s :%s", ServerInstance->Config->ServerName.c_str(), RPL_TIME, user->nick.c_str(),ServerInstance->Config->ServerName.c_str(),tms);
-
- return CMD_SUCCESS;
-}
-
-COMMAND_INIT(CommandTime)
diff --git a/src/commands/cmd_topic.cpp b/src/commands/cmd_topic.cpp
deleted file mode 100644
index 412ca1c06..000000000
--- a/src/commands/cmd_topic.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net>
- * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc>
- * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-
-/** Handle /TOPIC. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandTopic : public Command
-{
- public:
- /** Constructor for topic.
- */
- CommandTopic ( Module* parent) : Command(parent,"TOPIC",1, 2) { syntax = "<channel> [<topic>]"; Penalty = 2; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
-
-CmdResult CommandTopic::Handle (const std::vector<std::string>& parameters, User *user)
-{
- Channel* c;
-
- c = ServerInstance->FindChan(parameters[0]);
- if (!c)
- {
- user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
- return CMD_FAILURE;
- }
-
- if (parameters.size() == 1)
- {
- if (c)
- {
- if ((c->IsModeSet('s')) && (!c->HasUser(user)))
- {
- user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), c->name.c_str());
- return CMD_FAILURE;
- }
-
- if (c->topic.length())
- {
- user->WriteNumeric(332, "%s %s :%s", user->nick.c_str(), c->name.c_str(), c->topic.c_str());
- user->WriteNumeric(333, "%s %s %s %lu", user->nick.c_str(), c->name.c_str(), c->setby.c_str(), (unsigned long)c->topicset);
- }
- else
- {
- user->WriteNumeric(RPL_NOTOPICSET, "%s %s :No topic is set.", user->nick.c_str(), c->name.c_str());
- }
- }
- return CMD_SUCCESS;
- }
- else if (parameters.size()>1)
- {
- std::string t = parameters[1]; // needed, in case a module wants to change it
- c->SetTopic(user, t);
- }
-
- return CMD_SUCCESS;
-}
-
-
-COMMAND_INIT(CommandTopic)
diff --git a/src/commands/cmd_unloadmodule.cpp b/src/commands/cmd_unloadmodule.cpp
deleted file mode 100644
index 6d0f5f41c..000000000
--- a/src/commands/cmd_unloadmodule.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-
-/** Handle /UNLOADMODULE. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandUnloadmodule : public Command
-{
- public:
- /** Constructor for unloadmodule.
- */
- CommandUnloadmodule ( Module* parent) : Command(parent,"UNLOADMODULE",1) { flags_needed = 'o'; syntax = "<modulename>"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
-
-CmdResult CommandUnloadmodule::Handle (const std::vector<std::string>& parameters, User *user)
-{
- if (parameters[0] == "cmd_unloadmodule.so" || parameters[0] == "cmd_loadmodule.so")
- {
- user->WriteNumeric(972, "%s %s :You cannot unload module loading commands!", user->nick.c_str(), parameters[0].c_str());
- return CMD_FAILURE;
- }
-
- Module* m = ServerInstance->Modules->Find(parameters[0]);
- if (m && ServerInstance->Modules->Unload(m))
- {
- ServerInstance->SNO->WriteGlobalSno('a', "MODULE UNLOADED: %s unloaded %s", user->nick.c_str(), parameters[0].c_str());
- user->WriteNumeric(973, "%s %s :Module successfully unloaded.",user->nick.c_str(), parameters[0].c_str());
- }
- else
- {
- user->WriteNumeric(972, "%s %s :%s",user->nick.c_str(), parameters[0].c_str(),
- m ? ServerInstance->Modules->LastError().c_str() : "No such module");
- return CMD_FAILURE;
- }
-
- return CMD_SUCCESS;
-}
-
-COMMAND_INIT(CommandUnloadmodule)
diff --git a/src/commands/cmd_version.cpp b/src/commands/cmd_version.cpp
deleted file mode 100644
index 7620197fd..000000000
--- a/src/commands/cmd_version.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-
-/** Handle /VERSION. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandVersion : public Command
-{
- public:
- /** Constructor for version.
- */
- CommandVersion ( Module* parent) : Command(parent,"VERSION",0,0) { syntax = "[<servername>]"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
-
-CmdResult CommandVersion::Handle (const std::vector<std::string>&, User *user)
-{
- std::string version = ServerInstance->GetVersionString(IS_OPER(user));
- user->WriteNumeric(RPL_VERSION, "%s :%s", user->nick.c_str(), version.c_str());
- ServerInstance->Config->Send005(user);
- return CMD_SUCCESS;
-}
-
-COMMAND_INIT(CommandVersion)
diff --git a/src/commands/cmd_whois.cpp b/src/commands/cmd_whois.cpp
deleted file mode 100644
index ba2ad9c15..000000000
--- a/src/commands/cmd_whois.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
- * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-
-/** Handle /WHOIS. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandWhois : public Command
-{
- public:
- /** Constructor for whois.
- */
- CommandWhois ( Module* parent) : Command(parent,"WHOIS",1) { Penalty = 2; syntax = "<nick>{,<nick>}"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
-
-
-CmdResult CommandWhois::Handle (const std::vector<std::string>& parameters, User *user)
-{
- User *dest;
- int userindex = 0;
- unsigned long idle = 0, signon = 0;
-
- if (ServerInstance->Parser->LoopCall(user, this, parameters, 0))
- return CMD_SUCCESS;
-
-
- /*
- * If 2 paramters are specified (/whois nick nick), ignore the first one like spanningtree
- * does, and use the second one, otherwise, use the only paramter. -- djGrrr
- */
- if (parameters.size() > 1)
- userindex = 1;
-
- if (IS_LOCAL(user))
- dest = ServerInstance->FindNickOnly(parameters[userindex]);
- else
- dest = ServerInstance->FindNick(parameters[userindex]);
-
- if ((dest) && (dest->registered == REG_ALL))
- {
- /*
- * Okay. Umpteenth attempt at doing this, so let's re-comment...
- * For local users (/w localuser), we show idletime if hidewhois is disabled
- * For local users (/w localuser localuser), we always show idletime, hence parameters.size() > 1 check.
- * For remote users (/w remoteuser), we do NOT show idletime
- * For remote users (/w remoteuser remoteuser), spanningtree will handle calling do_whois, so we can ignore this case.
- * Thanks to djGrrr for not being impatient while I have a crap day coding. :p -- w00t
- */
- if (IS_LOCAL(dest) && (ServerInstance->Config->HideWhoisServer.empty() || parameters.size() > 1))
- {
- idle = abs((long)((dest->idle_lastmsg)-ServerInstance->Time()));
- signon = dest->signon;
- }
-
- ServerInstance->DoWhois(user,dest,signon,idle,parameters[userindex].c_str());
- }
- else
- {
- /* no such nick/channel */
- user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), !parameters[userindex].empty() ? parameters[userindex].c_str() : "*");
- user->WriteNumeric(318, "%s %s :End of /WHOIS list.",user->nick.c_str(), !parameters[userindex].empty() ? parameters[userindex].c_str() : "*");
- return CMD_FAILURE;
- }
-
- return CMD_SUCCESS;
-}
-
-
-
-COMMAND_INIT(CommandWhois)
diff --git a/src/commands/cmd_whowas.cpp b/src/commands/cmd_whowas.cpp
deleted file mode 100644
index 3a6444b45..000000000
--- a/src/commands/cmd_whowas.cpp
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
- * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc>
- * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-#include "commands/cmd_whowas.h"
-
-WhoWasMaintainTimer * timer;
-
-CommandWhowas::CommandWhowas( Module* parent) : Command(parent, "WHOWAS", 1)
-{
- syntax = "<nick>{,<nick>}";
- Penalty = 2;
- timer = new WhoWasMaintainTimer(3600);
- ServerInstance->Timers->AddTimer(timer);
-}
-
-CmdResult CommandWhowas::Handle (const std::vector<std::string>& parameters, User* user)
-{
- /* if whowas disabled in config */
- if (ServerInstance->Config->WhoWasGroupSize == 0 || ServerInstance->Config->WhoWasMaxGroups == 0)
- {
- user->WriteNumeric(421, "%s %s :This command has been disabled.",user->nick.c_str(),name.c_str());
- return CMD_FAILURE;
- }
-
- whowas_users::iterator i = whowas.find(assign(parameters[0]));
-
- if (i == whowas.end())
- {
- user->WriteNumeric(406, "%s %s :There was no such nickname",user->nick.c_str(),parameters[0].c_str());
- user->WriteNumeric(369, "%s %s :End of WHOWAS",user->nick.c_str(),parameters[0].c_str());
- return CMD_FAILURE;
- }
- else
- {
- whowas_set* grp = i->second;
- if (grp->size())
- {
- for (whowas_set::iterator ux = grp->begin(); ux != grp->end(); ux++)
- {
- WhoWasGroup* u = *ux;
-
- user->WriteNumeric(314, "%s %s %s %s * :%s",user->nick.c_str(),parameters[0].c_str(),
- u->ident.c_str(),u->dhost.c_str(),u->gecos.c_str());
-
- if (user->HasPrivPermission("users/auspex"))
- user->WriteNumeric(379, "%s %s :was connecting from *@%s",
- user->nick.c_str(), parameters[0].c_str(), u->host.c_str());
-
- std::string signon = ServerInstance->TimeString(u->signon);
- if (!ServerInstance->Config->HideWhoisServer.empty() && !user->HasPrivPermission("servers/auspex"))
- user->WriteNumeric(312, "%s %s %s :%s",user->nick.c_str(),parameters[0].c_str(), ServerInstance->Config->HideWhoisServer.c_str(), signon.c_str());
- else
- user->WriteNumeric(312, "%s %s %s :%s",user->nick.c_str(),parameters[0].c_str(), u->server.c_str(), signon.c_str());
- }
- }
- else
- {
- user->WriteNumeric(406, "%s %s :There was no such nickname",user->nick.c_str(),parameters[0].c_str());
- user->WriteNumeric(369, "%s %s :End of WHOWAS",user->nick.c_str(),parameters[0].c_str());
- return CMD_FAILURE;
- }
- }
-
- user->WriteNumeric(369, "%s %s :End of WHOWAS",user->nick.c_str(),parameters[0].c_str());
- return CMD_SUCCESS;
-}
-
-std::string CommandWhowas::GetStats()
-{
- int whowas_size = 0;
- int whowas_bytes = 0;
- whowas_users_fifo::iterator iter;
- for (iter = whowas_fifo.begin(); iter != whowas_fifo.end(); iter++)
- {
- whowas_set* n = (whowas_set*)whowas.find(iter->second)->second;
- if (n->size())
- {
- whowas_size += n->size();
- whowas_bytes += (sizeof(whowas_set) + ( sizeof(WhoWasGroup) * n->size() ) );
- }
- }
- return "Whowas entries: " +ConvToStr(whowas_size)+" ("+ConvToStr(whowas_bytes)+" bytes)";
-}
-
-void CommandWhowas::AddToWhoWas(User* user)
-{
- /* if whowas disabled */
- if (ServerInstance->Config->WhoWasGroupSize == 0 || ServerInstance->Config->WhoWasMaxGroups == 0)
- {
- return;
- }
-
- whowas_users::iterator iter = whowas.find(irc::string(user->nick.c_str()));
-
- if (iter == whowas.end())
- {
- whowas_set* n = new whowas_set;
- WhoWasGroup *a = new WhoWasGroup(user);
- n->push_back(a);
- whowas[user->nick.c_str()] = n;
- whowas_fifo.push_back(std::make_pair(ServerInstance->Time(),user->nick.c_str()));
-
- if ((int)(whowas.size()) > ServerInstance->Config->WhoWasMaxGroups)
- {
- whowas_users::iterator iter2 = whowas.find(whowas_fifo[0].second);
- if (iter2 != whowas.end())
- {
- whowas_set* n2 = (whowas_set*)iter2->second;
-
- if (n2->size())
- {
- while (n2->begin() != n2->end())
- {
- WhoWasGroup *a2 = *(n2->begin());
- delete a2;
- n2->pop_front();
- }
- }
-
- delete n2;
- whowas.erase(iter2);
- }
- whowas_fifo.pop_front();
- }
- }
- else
- {
- whowas_set* group = (whowas_set*)iter->second;
- WhoWasGroup *a = new WhoWasGroup(user);
- group->push_back(a);
-
- if ((int)(group->size()) > ServerInstance->Config->WhoWasGroupSize)
- {
- WhoWasGroup *a2 = (WhoWasGroup*)*(group->begin());
- delete a2;
- group->pop_front();
- }
- }
-}
-
-/* on rehash, refactor maps according to new conf values */
-void CommandWhowas::PruneWhoWas(time_t t)
-{
- /* config values */
- int groupsize = ServerInstance->Config->WhoWasGroupSize;
- int maxgroups = ServerInstance->Config->WhoWasMaxGroups;
- int maxkeep = ServerInstance->Config->WhoWasMaxKeep;
-
- /* first cut the list to new size (maxgroups) and also prune entries that are timed out. */
- whowas_users::iterator iter;
- int fifosize;
- while ((fifosize = (int)whowas_fifo.size()) > 0)
- {
- if (fifosize > maxgroups || whowas_fifo[0].first < t - maxkeep)
- {
- iter = whowas.find(whowas_fifo[0].second);
-
- /* hopefully redundant integrity check, but added while debugging r6216 */
- if (iter == whowas.end())
- {
- /* this should never happen, if it does maps are corrupt */
- ServerInstance->Logs->Log("WHOWAS",DEFAULT, "BUG: Whowas maps got corrupted! (1)");
- return;
- }
-
- whowas_set* n = (whowas_set*)iter->second;
-
- if (n->size())
- {
- while (n->begin() != n->end())
- {
- WhoWasGroup *a = *(n->begin());
- delete a;
- n->pop_front();
- }
- }
-
- delete n;
- whowas.erase(iter);
- whowas_fifo.pop_front();
- }
- else
- break;
- }
-
- /* Then cut the whowas sets to new size (groupsize) */
- fifosize = (int)whowas_fifo.size();
- for (int i = 0; i < fifosize; i++)
- {
- iter = whowas.find(whowas_fifo[0].second);
- /* hopefully redundant integrity check, but added while debugging r6216 */
- if (iter == whowas.end())
- {
- /* this should never happen, if it does maps are corrupt */
- ServerInstance->Logs->Log("WHOWAS",DEFAULT, "BUG: Whowas maps got corrupted! (2)");
- return;
- }
- whowas_set* n = (whowas_set*)iter->second;
- if (n->size())
- {
- int nickcount = n->size();
- while (n->begin() != n->end() && nickcount > groupsize)
- {
- WhoWasGroup *a = *(n->begin());
- delete a;
- n->pop_front();
- nickcount--;
- }
- }
- }
-}
-
-/* call maintain once an hour to remove expired nicks */
-void CommandWhowas::MaintainWhoWas(time_t t)
-{
- for (whowas_users::iterator iter = whowas.begin(); iter != whowas.end(); iter++)
- {
- whowas_set* n = (whowas_set*)iter->second;
- if (n->size())
- {
- while ((n->begin() != n->end()) && ((*n->begin())->signon < t - ServerInstance->Config->WhoWasMaxKeep))
- {
- WhoWasGroup *a = *(n->begin());
- delete a;
- n->erase(n->begin());
- }
- }
- }
-}
-
-CommandWhowas::~CommandWhowas()
-{
- if (timer)
- {
- ServerInstance->Timers->DelTimer(timer);
- }
-
- whowas_users::iterator iter;
- int fifosize;
- while ((fifosize = (int)whowas_fifo.size()) > 0)
- {
- iter = whowas.find(whowas_fifo[0].second);
-
- /* hopefully redundant integrity check, but added while debugging r6216 */
- if (iter == whowas.end())
- {
- /* this should never happen, if it does maps are corrupt */
- ServerInstance->Logs->Log("WHOWAS",DEFAULT, "BUG: Whowas maps got corrupted! (3)");
- return;
- }
-
- whowas_set* n = (whowas_set*)iter->second;
-
- if (n->size())
- {
- while (n->begin() != n->end())
- {
- WhoWasGroup *a = *(n->begin());
- delete a;
- n->pop_front();
- }
- }
-
- delete n;
- whowas.erase(iter);
- whowas_fifo.pop_front();
- }
-}
-
-WhoWasGroup::WhoWasGroup(User* user) : host(user->host), dhost(user->dhost), ident(user->ident),
- server(user->server), gecos(user->fullname), signon(user->signon)
-{
-}
-
-WhoWasGroup::~WhoWasGroup()
-{
-}
-
-/* every hour, run this function which removes all entries older than Config->WhoWasMaxKeep */
-void WhoWasMaintainTimer::Tick(time_t)
-{
- Module* whowas = ServerInstance->Modules->Find("cmd_whowas.so");
- if (whowas)
- {
- WhowasRequest(whowas, whowas, WhowasRequest::WHOWAS_MAINTAIN).Send();
- }
-}
-
-class ModuleWhoWas : public Module
-{
- CommandWhowas cmd;
- public:
- ModuleWhoWas() : cmd(this)
- {
- }
-
- void init()
- {
- ServerInstance->Modules->AddService(cmd);
- }
-
- void OnRequest(Request& request)
- {
- WhowasRequest& req = static_cast<WhowasRequest&>(request);
- switch (req.type)
- {
- case WhowasRequest::WHOWAS_ADD:
- cmd.AddToWhoWas(req.user);
- break;
- case WhowasRequest::WHOWAS_STATS:
- req.value = cmd.GetStats();
- break;
- case WhowasRequest::WHOWAS_PRUNE:
- cmd.PruneWhoWas(ServerInstance->Time());
- break;
- case WhowasRequest::WHOWAS_MAINTAIN:
- cmd.MaintainWhoWas(ServerInstance->Time());
- break;
- }
- }
-
- Version GetVersion()
- {
- return Version("WHOWAS Command", VF_VENDOR);
- }
-};
-
-MODULE_INIT(ModuleWhoWas)
diff --git a/src/configparser.cpp b/src/configparser.cpp
index 825dfc966..60770d16d 100644
--- a/src/configparser.cpp
+++ b/src/configparser.cpp
@@ -119,13 +119,13 @@ struct Parser
while (1)
{
ch = next();
- if (ch == '&' && (flags & FLAG_USE_XML))
+ if (ch == '&' && !(flags & FLAG_USE_COMPAT))
{
std::string varname;
while (1)
{
ch = next();
- if (isalnum(ch))
+ if (isalnum(ch) || (varname.empty() && ch == '#'))
varname.push_back(ch);
else if (ch == ';')
break;
@@ -136,12 +136,32 @@ struct Parser
throw CoreException("Parse error");
}
}
- std::map<std::string, std::string>::iterator var = stack.vars.find(varname);
- if (var == stack.vars.end())
- throw CoreException("Undefined XML entity reference '&" + varname + ";'");
- value.append(var->second);
+ if (varname.empty())
+ throw CoreException("Empty XML entity reference");
+ else if (varname[0] == '#' && (varname.size() == 1 || (varname.size() == 2 && varname[1] == 'x')))
+ throw CoreException("Empty numeric character reference");
+ else if (varname[0] == '#')
+ {
+ const char* cvarname = varname.c_str();
+ char* endptr;
+ unsigned long lvalue;
+ if (cvarname[1] == 'x')
+ lvalue = strtoul(cvarname + 2, &endptr, 16);
+ else
+ lvalue = strtoul(cvarname + 1, &endptr, 10);
+ if (*endptr != '\0' || lvalue > 255)
+ throw CoreException("Invalid numeric character reference '&" + varname + ";'");
+ value.push_back(static_cast<char>(lvalue));
+ }
+ else
+ {
+ std::map<std::string, std::string>::iterator var = stack.vars.find(varname);
+ if (var == stack.vars.end())
+ throw CoreException("Undefined XML entity reference '&" + varname + ";'");
+ value.append(var->second);
+ }
}
- else if (ch == '\\' && !(flags & FLAG_USE_XML))
+ else if (ch == '\\' && (flags & FLAG_USE_COMPAT))
{
int esc = next();
if (esc == 'n')
@@ -183,7 +203,10 @@ struct Parser
std::set<std::string> seen;
tag = ConfigTag::create(name, current.filename, current.line, items);
- while (kv(items, seen));
+ while (kv(items, seen))
+ {
+ // Do nothing here (silences a GCC warning).
+ }
if (name == mandatory_tag)
{
@@ -211,7 +234,7 @@ struct Parser
}
else if (name == "define")
{
- if (!(flags & FLAG_USE_XML))
+ if (flags & FLAG_USE_COMPAT)
throw CoreException("<define> tags may only be used in XML-style config (add <config format=\"xml\">)");
std::string varname = tag->getString("name");
std::string value = tag->getString("value");
@@ -223,9 +246,9 @@ struct Parser
{
std::string format = tag->getString("format");
if (format == "xml")
- flags |= FLAG_USE_XML;
+ flags &= ~FLAG_USE_COMPAT;
else if (format == "compat")
- flags &= ~FLAG_USE_XML;
+ flags |= FLAG_USE_COMPAT;
else if (!format.empty())
throw CoreException("Unknown configuration format " + format);
}
@@ -297,7 +320,7 @@ void ParseStack::DoInclude(ConfigTag* tag, int flags)
flags |= FLAG_NO_INC;
if (tag->getBool("noexec", false))
flags |= FLAG_NO_EXEC;
- if (!ParseFile(name, flags, mandatorytag))
+ if (!ParseFile(ServerInstance->Config->Paths.PrependConfig(name), flags, mandatorytag))
throw CoreException("Included");
}
else if (tag->readString("executable", name))
@@ -308,7 +331,7 @@ void ParseStack::DoInclude(ConfigTag* tag, int flags)
flags |= FLAG_NO_INC;
if (tag->getBool("noexec", true))
flags |= FLAG_NO_EXEC;
- if (!ParseExec(name, flags, mandatorytag))
+ if (!ParseFile(name, flags, mandatorytag, true))
throw CoreException("Included");
}
}
@@ -320,14 +343,15 @@ void ParseStack::DoReadFile(const std::string& key, const std::string& name, int
if (exec && (flags & FLAG_NO_EXEC))
throw CoreException("Invalid <execfiles> tag in file included with noexec=\"yes\"");
- FileWrapper file(exec ? popen(name.c_str(), "r") : fopen(name.c_str(), "r"), exec);
+ std::string path = ServerInstance->Config->Paths.PrependConfig(name);
+ FileWrapper file(exec ? popen(name.c_str(), "r") : fopen(path.c_str(), "r"), exec);
if (!file)
- throw CoreException("Could not read \"" + name + "\" for \"" + key + "\" file");
+ throw CoreException("Could not read \"" + path + "\" for \"" + key + "\" file");
file_cache& cache = FilesOutput[key];
cache.clear();
- char linebuf[MAXBUF*10];
+ char linebuf[5120];
while (fgets(linebuf, sizeof(linebuf), file))
{
size_t len = strlen(linebuf);
@@ -340,49 +364,20 @@ void ParseStack::DoReadFile(const std::string& key, const std::string& name, int
}
}
-bool ParseStack::ParseFile(const std::string& name, int flags, const std::string& mandatory_tag)
-{
- ServerInstance->Logs->Log("CONFIG", DEBUG, "Reading file %s", name.c_str());
- for (unsigned int t = 0; t < reading.size(); t++)
- {
- if (std::string(name) == reading[t])
- {
- throw CoreException("File " + name + " is included recursively (looped inclusion)");
- }
- }
-
- /* It's not already included, add it to the list of files we've loaded */
-
- FileWrapper file(fopen(name.c_str(), "r"));
- if (!file)
- throw CoreException("Could not read \"" + name + "\" for include");
-
- reading.push_back(name);
- Parser p(*this, flags, file, name, mandatory_tag);
- bool ok = p.outer_parse();
- reading.pop_back();
- return ok;
-}
-
-bool ParseStack::ParseExec(const std::string& name, int flags, const std::string& mandatory_tag)
+bool ParseStack::ParseFile(const std::string& path, int flags, const std::string& mandatory_tag, bool isexec)
{
- ServerInstance->Logs->Log("CONFIG", DEBUG, "Reading executable %s", name.c_str());
- for (unsigned int t = 0; t < reading.size(); t++)
- {
- if (std::string(name) == reading[t])
- {
- throw CoreException("Executable " + name + " is included recursively (looped inclusion)");
- }
- }
+ ServerInstance->Logs->Log("CONFIG", LOG_DEBUG, "Reading (isexec=%d) %s", isexec, path.c_str());
+ if (std::find(reading.begin(), reading.end(), path) != reading.end())
+ throw CoreException((isexec ? "Executable " : "File ") + path + " is included recursively (looped inclusion)");
/* It's not already included, add it to the list of files we've loaded */
- FileWrapper file(popen(name.c_str(), "r"), true);
+ FileWrapper file((isexec ? popen(path.c_str(), "r") : fopen(path.c_str(), "r")), isexec);
if (!file)
- throw CoreException("Could not open executable \"" + name + "\" for include");
+ throw CoreException("Could not read \"" + path + "\" for include");
- reading.push_back(name);
- Parser p(*this, flags, file, name, mandatory_tag);
+ reading.push_back(path);
+ Parser p(*this, flags, file, path, mandatory_tag);
bool ok = p.outer_parse();
reading.pop_back();
return ok;
@@ -399,7 +394,7 @@ bool ConfigTag::readString(const std::string& key, std::string& value, bool allo
value = j->second;
if (!allow_lf && (value.find('\n') != std::string::npos))
{
- ServerInstance->Logs->Log("CONFIG",DEFAULT, "Value of <" + tag + ":" + key + "> at " + getTagLocation() +
+ ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "Value of <" + tag + ":" + key + "> at " + getTagLocation() +
" contains a linefeed, and linefeeds in this value are not permitted -- stripped to spaces.");
for (std::string::iterator n = value.begin(); n != value.end(); n++)
if (*n == '\n')
@@ -417,7 +412,7 @@ std::string ConfigTag::getString(const std::string& key, const std::string& def)
return res;
}
-long ConfigTag::getInt(const std::string &key, long def)
+long ConfigTag::getInt(const std::string &key, long def, long min, long max)
{
std::string result;
if(!readString(key, result))
@@ -431,18 +426,41 @@ long ConfigTag::getInt(const std::string &key, long def)
switch (toupper(*res_tail))
{
case 'K':
- res= res* 1024;
+ res = res * 1024;
break;
case 'M':
- res= res* 1024 * 1024;
+ res = res * 1024 * 1024;
break;
case 'G':
- res= res* 1024 * 1024 * 1024;
+ res = res * 1024 * 1024 * 1024;
break;
}
+
+ CheckRange(key, res, def, min, max);
return res;
}
+void ConfigTag::CheckRange(const std::string& key, long& res, long def, long min, long max)
+{
+ if (res < min || res > max)
+ {
+ ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "WARNING: <%s:%s> value of %ld is not between %ld and %ld; set to %ld.",
+ tag.c_str(), key.c_str(), res, min, max, def);
+ res = def;
+ }
+}
+
+long ConfigTag::getDuration(const std::string& key, long def, long min, long max)
+{
+ std::string duration;
+ if (!readString(key, duration))
+ return def;
+
+ long ret = InspIRCd::Duration(duration);
+ CheckRange(key, ret, def, min, max);
+ return ret;
+}
+
double ConfigTag::getFloat(const std::string &key, double def)
{
std::string result;
@@ -462,7 +480,7 @@ bool ConfigTag::getBool(const std::string &key, bool def)
if (result == "no" || result == "false" || result == "0" || result == "off")
return false;
- ServerInstance->Logs->Log("CONFIG",DEFAULT, "Value of <" + tag + ":" + key + "> at " + getTagLocation() +
+ ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "Value of <" + tag + ":" + key + "> at " + getTagLocation() +
" is not valid, ignoring");
return def;
}
diff --git a/src/configreader.cpp b/src/configreader.cpp
index 060f66d16..a922543a3 100644
--- a/src/configreader.cpp
+++ b/src/configreader.cpp
@@ -23,26 +23,19 @@
#include "inspircd.h"
-#include <fstream>
#include "xline.h"
+#include "listmode.h"
#include "exitcodes.h"
-#include "commands/cmd_whowas.h"
#include "configparser.h"
#include <iostream>
-#ifdef _WIN32
-#include <Iphlpapi.h>
-#pragma comment(lib, "Iphlpapi.lib")
-#endif
ServerConfig::ServerConfig()
{
- WhoWasGroupSize = WhoWasMaxGroups = WhoWasMaxKeep = 0;
- RawLog = NoUserDns = HideBans = HideSplits = UndernetMsgPrefix = false;
- WildcardIPv6 = CycleHosts = InvBypassModes = true;
+ RawLog = HideBans = HideSplits = UndernetMsgPrefix = false;
+ WildcardIPv6 = InvBypassModes = true;
dns_timeout = 5;
MaxTargets = 20;
NetBufferSize = 10240;
- SoftLimit = ServerInstance->SE->GetMaxFds();
MaxConn = SOMAXCONN;
MaxChans = 20;
OperMaxChans = 30;
@@ -50,60 +43,6 @@ ServerConfig::ServerConfig()
c_ipv6_range = 128;
}
-void ServerConfig::Update005()
-{
- std::stringstream out(data005);
- std::vector<std::string> data;
- std::string token;
- while (out >> token)
- data.push_back(token);
- sort(data.begin(), data.end());
-
- std::string line5;
- isupport.clear();
- for(unsigned int i=0; i < data.size(); i++)
- {
- token = data[i];
- line5 = line5 + token + " ";
- if (i % 13 == 12)
- {
- line5.append(":are supported by this server");
- isupport.push_back(line5);
- line5.clear();
- }
- }
- if (!line5.empty())
- {
- line5.append(":are supported by this server");
- isupport.push_back(line5);
- }
-}
-
-void ServerConfig::Send005(User* user)
-{
- for (std::vector<std::string>::iterator line = ServerInstance->Config->isupport.begin(); line != ServerInstance->Config->isupport.end(); line++)
- user->WriteNumeric(RPL_ISUPPORT, "%s %s", user->nick.c_str(), line->c_str());
-}
-
-template<typename T, typename V>
-static void range(T& value, V min, V max, V def, const char* msg)
-{
- if (value >= (T)min && value <= (T)max)
- return;
- ServerInstance->Logs->Log("CONFIG", DEFAULT,
- "WARNING: %s value of %ld is not between %ld and %ld; set to %ld.",
- msg, (long)value, (long)min, (long)max, (long)def);
- value = def;
-}
-
-
-static void ValidIP(const std::string& ip, const std::string& key)
-{
- irc::sockets::sockaddrs dummy;
- if (!irc::sockets::aptosa(ip, 0, dummy))
- throw CoreException("The value of "+key+" is not an IP address");
-}
-
static void ValidHost(const std::string& p, const std::string& msg)
{
int num_dots = 0;
@@ -130,79 +69,20 @@ bool ServerConfig::ApplyDisabledCommands(const std::string& data)
std::string thiscmd;
/* Enable everything first */
- for (Commandtable::iterator x = ServerInstance->Parser->cmdlist.begin(); x != ServerInstance->Parser->cmdlist.end(); x++)
+ const CommandParser::CommandMap& commands = ServerInstance->Parser.GetCommands();
+ for (CommandParser::CommandMap::const_iterator x = commands.begin(); x != commands.end(); ++x)
x->second->Disable(false);
/* Now disable all the ones which the user wants disabled */
while (dcmds >> thiscmd)
{
- Commandtable::iterator cm = ServerInstance->Parser->cmdlist.find(thiscmd);
- if (cm != ServerInstance->Parser->cmdlist.end())
- {
- cm->second->Disable(true);
- }
+ Command* handler = ServerInstance->Parser.GetHandler(thiscmd);
+ if (handler)
+ handler->Disable(true);
}
return true;
}
-static void FindDNS(std::string& server)
-{
- if (!server.empty())
- return;
-#ifdef _WIN32
- // attempt to look up their nameserver from the system
- ServerInstance->Logs->Log("CONFIG",DEFAULT,"WARNING: <dns:server> not defined, attempting to find a working server in the system settings...");
-
- PFIXED_INFO pFixedInfo;
- DWORD dwBufferSize = sizeof(FIXED_INFO);
- pFixedInfo = (PFIXED_INFO) HeapAlloc(GetProcessHeap(), 0, sizeof(FIXED_INFO));
-
- if(pFixedInfo)
- {
- if (GetNetworkParams(pFixedInfo, &dwBufferSize) == ERROR_BUFFER_OVERFLOW) {
- HeapFree(GetProcessHeap(), 0, pFixedInfo);
- pFixedInfo = (PFIXED_INFO) HeapAlloc(GetProcessHeap(), 0, dwBufferSize);
- }
-
- if(pFixedInfo) {
- if (GetNetworkParams(pFixedInfo, &dwBufferSize) == NO_ERROR)
- server = pFixedInfo->DnsServerList.IpAddress.String;
-
- HeapFree(GetProcessHeap(), 0, pFixedInfo);
- }
-
- if(!server.empty())
- {
- ServerInstance->Logs->Log("CONFIG",DEFAULT,"<dns:server> set to '%s' as first active resolver in the system settings.", server.c_str());
- return;
- }
- }
-
- ServerInstance->Logs->Log("CONFIG",DEFAULT,"No viable nameserver found! Defaulting to nameserver '127.0.0.1'!");
-#else
- // attempt to look up their nameserver from /etc/resolv.conf
- ServerInstance->Logs->Log("CONFIG",DEFAULT,"WARNING: <dns:server> not defined, attempting to find working server in /etc/resolv.conf...");
-
- std::ifstream resolv("/etc/resolv.conf");
-
- while (resolv >> server)
- {
- if (server == "nameserver")
- {
- resolv >> server;
- if (server.find_first_not_of("0123456789.") == std::string::npos)
- {
- ServerInstance->Logs->Log("CONFIG",DEFAULT,"<dns:server> set to '%s' as first resolver in /etc/resolv.conf.",server.c_str());
- return;
- }
- }
- }
-
- ServerInstance->Logs->Log("CONFIG",DEFAULT,"/etc/resolv.conf contains no viable nameserver entries! Defaulting to nameserver '127.0.0.1'!");
-#endif
- server = "127.0.0.1";
-}
-
static void ReadXLine(ServerConfig* conf, const std::string& tag, const std::string& key, XLineFactory* make)
{
ConfigTagList tags = conf->ConfTags(tag);
@@ -241,13 +121,11 @@ void ServerConfig::CrossCheckOperClassType()
std::string name = tag->getString("name");
if (name.empty())
throw CoreException("<type:name> is missing from tag at " + tag->getTagLocation());
- if (!ServerInstance->IsNick(name.c_str(), Limits.NickMax))
- throw CoreException("<type:name> is invalid (value '" + name + "')");
- if (oper_blocks.find(" " + name) != oper_blocks.end())
+ if (OperTypes.find(name) != OperTypes.end())
throw CoreException("Duplicate type block with name " + name + " at " + tag->getTagLocation());
OperInfo* ifo = new OperInfo;
- oper_blocks[" " + name] = ifo;
+ OperTypes[name] = ifo;
ifo->name = name;
ifo->type_block = tag;
@@ -272,8 +150,8 @@ void ServerConfig::CrossCheckOperClassType()
throw CoreException("<oper:name> missing from tag at " + tag->getTagLocation());
std::string type = tag->getString("type");
- OperIndex::iterator tblk = oper_blocks.find(" " + type);
- if (tblk == oper_blocks.end())
+ OperIndex::iterator tblk = OperTypes.find(type);
+ if (tblk == OperTypes.end())
throw CoreException("Oper block " + name + " has missing type " + type);
if (oper_blocks.find(name) != oper_blocks.end())
throw CoreException("Duplicate oper block with name " + name + " at " + tag->getTagLocation());
@@ -296,7 +174,7 @@ void ServerConfig::CrossCheckConnectBlocks(ServerConfig* current)
for(ClassVector::iterator i = current->Classes.begin(); i != current->Classes.end(); ++i)
{
ConnectClass* c = *i;
- if (c->name.substr(0, 8) != "unnamed-")
+ if (c->name.compare(0, 8, "unnamed-", 8))
{
oldBlocksByMask["n" + c->name] = c;
}
@@ -419,6 +297,7 @@ void ServerConfig::CrossCheckConnectBlocks(ServerConfig* current)
me->maxchans = tag->getInt("maxchans", me->maxchans);
me->maxconnwarn = tag->getBool("maxconnwarn", me->maxconnwarn);
me->limit = tag->getInt("limit", me->limit);
+ me->resolvehostnames = tag->getBool("resolvehostnames", me->resolvehostnames);
ClassMap::iterator oldMask = oldBlocksByMask.find(typeMask);
if (oldMask != oldBlocksByMask.end())
@@ -436,42 +315,31 @@ void ServerConfig::CrossCheckConnectBlocks(ServerConfig* current)
/** Represents a deprecated configuration tag.
*/
-struct Deprecated
+struct DeprecatedConfig
{
- /** Tag name
- */
- const char* tag;
- /** Tag value
- */
- const char* value;
- /** Reason for deprecation
- */
- const char* reason;
+ /** Tag name. */
+ std::string tag;
+
+ /** Attribute key. */
+ std::string key;
+
+ /** Attribute value. */
+ std::string value;
+
+ /** Reason for deprecation. */
+ std::string reason;
};
-static const Deprecated ChangedConfig[] = {
- {"options", "hidelinks", "has been moved to <security:hidelinks> as of 1.2a3"},
- {"options", "hidewhois", "has been moved to <security:hidewhois> as of 1.2a3"},
- {"options", "userstats", "has been moved to <security:userstats> as of 1.2a3"},
- {"options", "customversion", "has been moved to <security:customversion> as of 1.2a3"},
- {"options", "hidesplits", "has been moved to <security:hidesplits> as of 1.2a3"},
- {"options", "hidebans", "has been moved to <security:hidebans> as of 1.2a3"},
- {"options", "hidekills", "has been moved to <security:hidekills> as of 1.2a3"},
- {"options", "operspywhois", "has been moved to <security:operspywhois> as of 1.2a3"},
- {"options", "announceinvites", "has been moved to <security:announceinvites> as of 1.2a3"},
- {"options", "hidemodes", "has been moved to <security:hidemodes> as of 1.2a3"},
- {"options", "maxtargets", "has been moved to <security:maxtargets> as of 1.2a3"},
- {"options", "nouserdns", "has been moved to <performance:nouserdns> as of 1.2a3"},
- {"options", "maxwho", "has been moved to <performance:maxwho> as of 1.2a3"},
- {"options", "softlimit", "has been moved to <performance:softlimit> as of 1.2a3"},
- {"options", "somaxconn", "has been moved to <performance:somaxconn> as of 1.2a3"},
- {"options", "netbuffersize", "has been moved to <performance:netbuffersize> as of 1.2a3"},
- {"options", "maxwho", "has been moved to <performance:maxwho> as of 1.2a3"},
- {"options", "loglevel", "1.2+ does not use the loglevel value. Please define <log> tags instead."},
- {"die", "value", "you need to reread your config"},
- {"bind", "transport", "has been moved to <bind:ssl> as of 2.0a1"},
- {"link", "transport", "has been moved to <link:ssl> as of 2.0a1"},
- {"link", "autoconnect", "2.0+ does not use the autoconnect value. Please define <autoconnect> tags instead."},
+static const DeprecatedConfig ChangedConfig[] = {
+ { "bind", "transport", "", "has been moved to <bind:ssl> as of 2.0" },
+ { "die", "value", "", "you need to reread your config" },
+ { "gnutls", "starttls", "", "has been replaced with m_starttls as of 2.2" },
+ { "link", "autoconnect", "", "2.0+ does not use this attribute - define <autoconnect> tags instead" },
+ { "link", "transport", "", "has been moved to <link:ssl> as of 2.0" },
+ { "module", "name", "m_chanprotect.so", "has been replaced with m_customprefix as of 2.2" },
+ { "module", "name", "m_halfop.so", "has been replaced with m_customprefix as of 2.2" },
+ { "options", "cyclehosts", "", "has been replaced with m_hostcycle as of 2.2" },
+ { "performance", "nouserdns", "", "has been moved to <connect:resolvehostnames> as of 2.2" }
};
void ServerConfig::Fill()
@@ -480,89 +348,71 @@ void ServerConfig::Fill()
ConfigTag* security = ConfValue("security");
if (sid.empty())
{
- ServerName = ConfValue("server")->getString("name");
- sid = ConfValue("server")->getString("id");
+ ServerName = ConfValue("server")->getString("name", "irc.example.com");
ValidHost(ServerName, "<server:name>");
- if (!sid.empty() && !ServerInstance->IsSID(sid))
+
+ sid = ConfValue("server")->getString("id");
+ if (!sid.empty() && !InspIRCd::IsSID(sid))
throw CoreException(sid + " is not a valid server ID. A server ID must be 3 characters long, with the first character a digit and the next two characters a digit or letter.");
}
else
{
if (ServerName != ConfValue("server")->getString("name"))
- throw CoreException("You must restart to change the server name or SID");
+ throw CoreException("You must restart to change the server name");
+
std::string nsid = ConfValue("server")->getString("id");
if (!nsid.empty() && nsid != sid)
- throw CoreException("You must restart to change the server name or SID");
- }
- diepass = ConfValue("power")->getString("diepass");
- restartpass = ConfValue("power")->getString("restartpass");
- powerhash = ConfValue("power")->getString("hash");
- PrefixQuit = options->getString("prefixquit");
- SuffixQuit = options->getString("suffixquit");
- FixedQuit = options->getString("fixedquit");
- PrefixPart = options->getString("prefixpart");
- SuffixPart = options->getString("suffixpart");
- FixedPart = options->getString("fixedpart");
- SoftLimit = ConfValue("performance")->getInt("softlimit", ServerInstance->SE->GetMaxFds());
+ throw CoreException("You must restart to change the server id");
+ }
+ SoftLimit = ConfValue("performance")->getInt("softlimit", (SocketEngine::GetMaxFds() > 0 ? SocketEngine::GetMaxFds() : LONG_MAX), 10);
+ CCOnConnect = ConfValue("performance")->getBool("clonesonconnect", true);
MaxConn = ConfValue("performance")->getInt("somaxconn", SOMAXCONN);
- MoronBanner = options->getString("moronbanner", "You're banned!");
+ XLineMessage = options->getString("xlinemessage", options->getString("moronbanner", "You're banned!"));
ServerDesc = ConfValue("server")->getString("description", "Configure Me");
Network = ConfValue("server")->getString("network", "Network");
- AdminName = ConfValue("admin")->getString("name", "");
- AdminEmail = ConfValue("admin")->getString("email", "null@example.com");
- AdminNick = ConfValue("admin")->getString("nick", "admin");
- ModPath = ConfValue("path")->getString("moduledir", MOD_PATH);
- NetBufferSize = ConfValue("performance")->getInt("netbuffersize", 10240);
+ NetBufferSize = ConfValue("performance")->getInt("netbuffersize", 10240, 1024, 65534);
dns_timeout = ConfValue("dns")->getInt("timeout", 5);
DisabledCommands = ConfValue("disabled")->getString("commands", "");
DisabledDontExist = ConfValue("disabled")->getBool("fakenonexistant");
UserStats = security->getString("userstats");
- CustomVersion = security->getString("customversion", Network + " IRCd");
+ CustomVersion = security->getString("customversion");
HideSplits = security->getBool("hidesplits");
HideBans = security->getBool("hidebans");
HideWhoisServer = security->getString("hidewhois");
HideKillsServer = security->getString("hidekills");
RestrictBannedUsers = security->getBool("restrictbannedusers", true);
GenericOper = security->getBool("genericoper");
- NoUserDns = ConfValue("performance")->getBool("nouserdns");
SyntaxHints = options->getBool("syntaxhints");
- CycleHosts = options->getBool("cyclehosts");
CycleHostsFromUser = options->getBool("cyclehostsfromuser");
UndernetMsgPrefix = options->getBool("ircumsgprefix");
FullHostInTopic = options->getBool("hostintopic");
- MaxTargets = security->getInt("maxtargets", 20);
- DefaultModes = options->getString("defaultmodes", "nt");
+ MaxTargets = security->getInt("maxtargets", 20, 1, 31);
+ DefaultModes = options->getString("defaultmodes", "not");
PID = ConfValue("pid")->getString("file");
- WhoWasGroupSize = ConfValue("whowas")->getInt("groupsize");
- WhoWasMaxGroups = ConfValue("whowas")->getInt("maxgroups");
- WhoWasMaxKeep = ServerInstance->Duration(ConfValue("whowas")->getString("maxkeep"));
MaxChans = ConfValue("channels")->getInt("users", 20);
- OperMaxChans = ConfValue("channels")->getInt("opers", 60);
+ OperMaxChans = ConfValue("channels")->getInt("opers");
c_ipv4_range = ConfValue("cidr")->getInt("ipv4clone", 32);
c_ipv6_range = ConfValue("cidr")->getInt("ipv6clone", 128);
Limits.NickMax = ConfValue("limits")->getInt("maxnick", 32);
Limits.ChanMax = ConfValue("limits")->getInt("maxchan", 64);
Limits.MaxModes = ConfValue("limits")->getInt("maxmodes", 20);
Limits.IdentMax = ConfValue("limits")->getInt("maxident", 11);
+ Limits.MaxHost = ConfValue("limits")->getInt("maxhost", 64);
Limits.MaxQuit = ConfValue("limits")->getInt("maxquit", 255);
Limits.MaxTopic = ConfValue("limits")->getInt("maxtopic", 307);
Limits.MaxKick = ConfValue("limits")->getInt("maxkick", 255);
Limits.MaxGecos = ConfValue("limits")->getInt("maxgecos", 128);
Limits.MaxAway = ConfValue("limits")->getInt("maxaway", 200);
+ Limits.MaxLine = ConfValue("limits")->getInt("maxline", 512);
+ Paths.Config = ConfValue("path")->getString("configdir", INSPIRCD_CONFIG_PATH);
+ Paths.Data = ConfValue("path")->getString("datadir", INSPIRCD_DATA_PATH);
+ Paths.Log = ConfValue("path")->getString("logdir", INSPIRCD_LOG_PATH);
+ Paths.Module = ConfValue("path")->getString("moduledir", INSPIRCD_MODULE_PATH);
InvBypassModes = options->getBool("invitebypassmodes", true);
NoSnoticeStack = options->getBool("nosnoticestack", false);
- WelcomeNotice = options->getBool("welcomenotice", true);
-
- range(SoftLimit, 10, ServerInstance->SE->GetMaxFds(), ServerInstance->SE->GetMaxFds(), "<performance:softlimit>");
- if (ConfValue("performance")->getBool("limitsomaxconn", true))
- range(MaxConn, 0, SOMAXCONN, SOMAXCONN, "<performance:somaxconn>");
- range(MaxTargets, 1, 31, 20, "<security:maxtargets>");
- range(NetBufferSize, 1024, 65534, 10240, "<performance:netbuffersize>");
- range(WhoWasGroupSize, 0, 10000, 10, "<whowas:groupsize>");
- range(WhoWasMaxGroups, 0, 1000000, 10240, "<whowas:maxgroups>");
- range(WhoWasMaxKeep, 3600, INT_MAX, 3600, "<whowas:maxkeep>");
- ValidIP(DNSServer, "<dns:server>");
+ if (Network.find(' ') != std::string::npos)
+ throw CoreException(Network + " is not a valid network name. A network name must not contain spaces.");
std::string defbind = options->getString("defaultbind");
if (assign(defbind) == "ipv4")
@@ -580,26 +430,7 @@ void ServerConfig::Fill()
if (socktest < 0)
WildcardIPv6 = false;
else
- ServerInstance->SE->Close(socktest);
- }
- ConfigTagList tags = ConfTags("uline");
- for(ConfigIter i = tags.first; i != tags.second; ++i)
- {
- ConfigTag* tag = i->second;
- std::string server;
- if (!tag->readString("server", server))
- throw CoreException("<uline> tag missing server at " + tag->getTagLocation());
- ulines[assign(server)] = tag->getBool("silent");
- }
-
- tags = ConfTags("banlist");
- for(ConfigIter i = tags.first; i != tags.second; ++i)
- {
- ConfigTag* tag = i->second;
- std::string chan;
- if (!tag->readString("chan", chan))
- throw CoreException("<banlist> tag missing chan at " + tag->getTagLocation());
- maxbans[chan] = tag->getInt("limit");
+ SocketEngine::Close(socktest);
}
ReadXLine(this, "badip", "ipmask", ServerInstance->XLines->GetFactory("Z"));
@@ -665,12 +496,7 @@ void ServerConfig::Read()
catch (CoreException& err)
{
valid = false;
- errstr << err.GetReason();
- }
- if (valid)
- {
- DNSServer = ConfValue("dns")->getString("server");
- FindDNS(DNSServer);
+ errstr << err.GetReason() << std::endl;
}
}
@@ -690,16 +516,26 @@ void ServerConfig::Apply(ServerConfig* old, const std::string &useruid)
/* The stuff in here may throw CoreException, be sure we're in a position to catch it. */
try
{
- for (int Index = 0; Index * sizeof(Deprecated) < sizeof(ChangedConfig); Index++)
+ for (int index = 0; index * sizeof(DeprecatedConfig) < sizeof(ChangedConfig); index++)
{
- std::string dummy;
- ConfigTagList tags = ConfTags(ChangedConfig[Index].tag);
+ std::string value;
+ ConfigTagList tags = ConfTags(ChangedConfig[index].tag);
for(ConfigIter i = tags.first; i != tags.second; ++i)
{
- if (i->second->readString(ChangedConfig[Index].value, dummy, true))
- errstr << "Your configuration contains a deprecated value: <"
- << ChangedConfig[Index].tag << ":" << ChangedConfig[Index].value << "> - " << ChangedConfig[Index].reason
- << " (at " << i->second->getTagLocation() << ")\n";
+ if (i->second->readString(ChangedConfig[index].key, value, true)
+ && (ChangedConfig[index].value.empty() || value == ChangedConfig[index].value))
+ {
+ errstr << "Your configuration contains a deprecated value: <" << ChangedConfig[index].tag;
+ if (ChangedConfig[index].value.empty())
+ {
+ errstr << ':' << ChangedConfig[index].key;
+ }
+ else
+ {
+ errstr << ' ' << ChangedConfig[index].key << "=\"" << ChangedConfig[index].value << "\"";
+ }
+ errstr << "> - " << ChangedConfig[index].reason << " (at " << i->second->getTagLocation() << ")" << std::endl;
+ }
}
}
@@ -721,6 +557,11 @@ void ServerConfig::Apply(ServerConfig* old, const std::string &useruid)
if (valid)
ServerInstance->WritePID(this->PID);
+ ConfigTagList binds = ConfTags("bind");
+ if (binds.first == binds.second)
+ errstr << "Possible configuration error: you have not defined any <bind> blocks." << std::endl
+ << "You will need to do this if you want clients to be able to connect!" << std::endl;
+
if (old)
{
// On first run, ports are bound later on
@@ -728,14 +569,14 @@ void ServerConfig::Apply(ServerConfig* old, const std::string &useruid)
ServerInstance->BindPorts(pl);
if (pl.size())
{
- errstr << "Not all your client ports could be bound.\nThe following port(s) failed to bind:\n";
+ errstr << "Not all your client ports could be bound." << std::endl
+ << "The following port(s) failed to bind:" << std::endl;
int j = 1;
for (FailedPortList::iterator i = pl.begin(); i != pl.end(); i++, j++)
{
- char buf[MAXBUF];
- snprintf(buf, MAXBUF, "%d. Address: %s Reason: %s\n", j, i->first.empty() ? "<all>" : i->first.c_str(), i->second.c_str());
- errstr << buf;
+ errstr << j << ".\tAddress: " << (i->first.empty() ? "<all>" : i->first.c_str()) << "\tReason: "
+ << i->second << std::endl;
}
}
}
@@ -744,7 +585,7 @@ void ServerConfig::Apply(ServerConfig* old, const std::string &useruid)
if (!valid)
{
- ServerInstance->Logs->Log("CONFIG",DEFAULT, "There were errors in your configuration file:");
+ ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "There were errors in your configuration file:");
Classes.clear();
}
@@ -778,10 +619,6 @@ void ServerConfig::Apply(ServerConfig* old, const std::string &useruid)
ConfigFileCache::iterator file = this->Files.find(tag->getString("motd", "motd"));
if (file != this->Files.end())
InspIRCd::ProcessColors(file->second);
-
- file = this->Files.find(tag->getString("rules", "rules"));
- if (file != this->Files.end())
- InspIRCd::ProcessColors(file->second);
}
/* No old configuration -> initial boot, nothing more to do here */
@@ -810,13 +647,8 @@ void ServerConfig::Apply(ServerConfig* old, const std::string &useruid)
void ServerConfig::ApplyModules(User* user)
{
- Module* whowas = ServerInstance->Modules->Find("cmd_whowas.so");
- if (whowas)
- WhowasRequest(NULL, whowas, WhowasRequest::WHOWAS_PRUNE).Send();
-
- const std::vector<std::string> v = ServerInstance->Modules->GetAllModuleNames(0);
std::vector<std::string> added_modules;
- std::set<std::string> removed_modules(v.begin(), v.end());
+ ModuleManager::ModuleMap removed_modules = ServerInstance->Modules->GetModules();
ConfigTagList tags = ConfTags("module");
for(ConfigIter i = tags.first; i != tags.second; ++i)
@@ -832,30 +664,27 @@ void ServerConfig::ApplyModules(User* user)
}
}
- if (ConfValue("options")->getBool("allowhalfop") && removed_modules.erase("m_halfop.so") == 0)
- added_modules.push_back("m_halfop.so");
-
- for (std::set<std::string>::iterator removing = removed_modules.begin(); removing != removed_modules.end(); removing++)
+ for (ModuleManager::ModuleMap::iterator i = removed_modules.begin(); i != removed_modules.end(); ++i)
{
- // Don't remove cmd_*.so, just remove m_*.so
- if (removing->c_str()[0] == 'c')
+ const std::string& modname = i->first;
+ // Don't remove core_*.so, just remove m_*.so
+ if (modname.c_str()[0] == 'c')
continue;
- Module* m = ServerInstance->Modules->Find(*removing);
- if (m && ServerInstance->Modules->Unload(m))
+ if (ServerInstance->Modules->Unload(i->second))
{
- ServerInstance->SNO->WriteGlobalSno('a', "*** REHASH UNLOADED MODULE: %s",removing->c_str());
+ ServerInstance->SNO->WriteGlobalSno('a', "*** REHASH UNLOADED MODULE: %s", modname.c_str());
if (user)
- user->WriteNumeric(RPL_UNLOADEDMODULE, "%s %s :Module %s successfully unloaded.",user->nick.c_str(), removing->c_str(), removing->c_str());
+ user->WriteNumeric(RPL_UNLOADEDMODULE, "%s :Module %s successfully unloaded.", modname.c_str(), modname.c_str());
else
- ServerInstance->SNO->WriteGlobalSno('a', "Module %s successfully unloaded.", removing->c_str());
+ ServerInstance->SNO->WriteGlobalSno('a', "Module %s successfully unloaded.", modname.c_str());
}
else
{
if (user)
- user->WriteNumeric(ERR_CANTUNLOADMODULE, "%s %s :Failed to unload module %s: %s",user->nick.c_str(), removing->c_str(), removing->c_str(), ServerInstance->Modules->LastError().c_str());
+ user->WriteNumeric(ERR_CANTUNLOADMODULE, "%s :Failed to unload module %s: %s", modname.c_str(), modname.c_str(), ServerInstance->Modules->LastError().c_str());
else
- ServerInstance->SNO->WriteGlobalSno('a', "Failed to unload module %s: %s", removing->c_str(), ServerInstance->Modules->LastError().c_str());
+ ServerInstance->SNO->WriteGlobalSno('a', "Failed to unload module %s: %s", modname.c_str(), ServerInstance->Modules->LastError().c_str());
}
}
@@ -865,25 +694,20 @@ void ServerConfig::ApplyModules(User* user)
{
ServerInstance->SNO->WriteGlobalSno('a', "*** REHASH LOADED MODULE: %s",adding->c_str());
if (user)
- user->WriteNumeric(RPL_LOADEDMODULE, "%s %s :Module %s successfully loaded.",user->nick.c_str(), adding->c_str(), adding->c_str());
+ user->WriteNumeric(RPL_LOADEDMODULE, "%s :Module %s successfully loaded.", adding->c_str(), adding->c_str());
else
ServerInstance->SNO->WriteGlobalSno('a', "Module %s successfully loaded.", adding->c_str());
}
else
{
if (user)
- user->WriteNumeric(ERR_CANTLOADMODULE, "%s %s :Failed to load module %s: %s",user->nick.c_str(), adding->c_str(), adding->c_str(), ServerInstance->Modules->LastError().c_str());
+ user->WriteNumeric(ERR_CANTLOADMODULE, "%s :Failed to load module %s: %s", adding->c_str(), adding->c_str(), ServerInstance->Modules->LastError().c_str());
else
ServerInstance->SNO->WriteGlobalSno('a', "Failed to load module %s: %s", adding->c_str(), ServerInstance->Modules->LastError().c_str());
}
}
}
-bool ServerConfig::StartsWithWindowsDriveLetter(const std::string &path)
-{
- return (path.length() > 2 && isalpha(path[0]) && path[1] == ':');
-}
-
ConfigTag* ServerConfig::ConfValue(const std::string &tag)
{
ConfigTagList found = config_data.equal_range(tag);
@@ -892,7 +716,7 @@ ConfigTag* ServerConfig::ConfValue(const std::string &tag)
ConfigTag* rv = found.first->second;
found.first++;
if (found.first != found.second)
- ServerInstance->Logs->Log("CONFIG",DEFAULT, "Multiple <" + tag + "> tags found; only first will be used "
+ ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "Multiple <" + tag + "> tags found; only first will be used "
"(first at " + rv->getTagLocation() + "; second at " + found.first->second->getTagLocation() + ")");
return rv;
}
@@ -902,35 +726,28 @@ ConfigTagList ServerConfig::ConfTags(const std::string& tag)
return config_data.equal_range(tag);
}
-bool ServerConfig::FileExists(const char* file)
+std::string ServerConfig::Escape(const std::string& str, bool xml)
{
- struct stat sb;
- if (stat(file, &sb) == -1)
- return false;
-
- if ((sb.st_mode & S_IFDIR) > 0)
- return false;
-
- FILE *input = fopen(file, "r");
- if (input == NULL)
- return false;
- else
+ std::string escaped;
+ for (std::string::const_iterator it = str.begin(); it != str.end(); ++it)
{
- fclose(input);
- return true;
+ switch (*it)
+ {
+ case '"':
+ escaped += xml ? "&quot;" : "\"";
+ break;
+ case '&':
+ escaped += xml ? "&amp;" : "&";
+ break;
+ case '\\':
+ escaped += xml ? "\\" : "\\\\";
+ break;
+ default:
+ escaped += *it;
+ break;
+ }
}
-}
-
-const char* ServerConfig::CleanFilename(const char* name)
-{
- const char* p = name + strlen(name);
- while ((p != name) && (*p != '/') && (*p != '\\')) p--;
- return (p != name ? ++p : p);
-}
-
-const std::string& ServerConfig::GetSID()
-{
- return sid;
+ return escaped;
}
void ConfigReaderThread::Run()
@@ -942,7 +759,7 @@ void ConfigReaderThread::Run()
void ConfigReaderThread::Finish()
{
ServerConfig* old = ServerInstance->Config;
- ServerInstance->Logs->Log("CONFIG",DEBUG,"Switching to new configuration...");
+ ServerInstance->Logs->Log("CONFIG", LOG_DEBUG, "Switching to new configuration...");
ServerInstance->Config = this->Config;
Config->Apply(old, TheUserUID);
@@ -956,12 +773,20 @@ void ConfigReaderThread::Finish()
*/
ServerInstance->XLines->CheckELines();
ServerInstance->XLines->ApplyLines();
- ServerInstance->Res->Rehash();
- ServerInstance->ResetMaxBans();
+ ChanModeReference ban(NULL, "ban");
+ static_cast<ListModeBase*>(*ban)->DoRehash();
Config->ApplyDisabledCommands(Config->DisabledCommands);
User* user = ServerInstance->FindNick(TheUserUID);
- FOREACH_MOD(I_OnRehash, OnRehash(user));
- ServerInstance->BuildISupport();
+
+ ConfigStatus status(user);
+ const ModuleManager::ModuleMap& mods = ServerInstance->Modules->GetModules();
+ for (ModuleManager::ModuleMap::const_iterator i = mods.begin(); i != mods.end(); ++i)
+ i->second->ReadConfig(status);
+
+ // The description of this server may have changed - update it for WHOIS etc.
+ ServerInstance->FakeClient->server->description = Config->ServerDesc;
+
+ ServerInstance->ISupport.Build();
ServerInstance->Logs->CloseLogs();
ServerInstance->Logs->OpenFileLogs();
diff --git a/src/commands/cmd_invite.cpp b/src/coremods/core_channel/cmd_invite.cpp
index c69e6bd1b..ea4692d04 100644
--- a/src/commands/cmd_invite.cpp
+++ b/src/coremods/core_channel/cmd_invite.cpp
@@ -21,26 +21,14 @@
#include "inspircd.h"
+#include "core_channel.h"
-/** Handle /INVITE. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandInvite : public Command
+CommandInvite::CommandInvite(Module* parent)
+ : Command(parent, "INVITE", 0, 0)
{
- public:
- /** Constructor for invite.
- */
- CommandInvite ( Module* parent) : Command(parent,"INVITE", 0, 0) { Penalty = 4; syntax = "[<nick> <channel>]"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
+ Penalty = 4;
+ syntax = "[<nick> <channel>]";
+}
/** Handle /INVITE
*/
@@ -48,7 +36,7 @@ CmdResult CommandInvite::Handle (const std::vector<std::string>& parameters, Use
{
ModResult MOD_RESULT;
- if (parameters.size() == 2 || parameters.size() == 3)
+ if (parameters.size() >= 2)
{
User* u;
if (IS_LOCAL(user))
@@ -58,29 +46,42 @@ CmdResult CommandInvite::Handle (const std::vector<std::string>& parameters, Use
Channel* c = ServerInstance->FindChan(parameters[1]);
time_t timeout = 0;
- if (parameters.size() == 3)
+ if (parameters.size() >= 3)
{
if (IS_LOCAL(user))
- timeout = ServerInstance->Time() + ServerInstance->Duration(parameters[2]);
- else
- timeout = ConvToInt(parameters[2]);
+ timeout = ServerInstance->Time() + InspIRCd::Duration(parameters[2]);
+ else if (parameters.size() > 3)
+ timeout = ConvToInt(parameters[3]);
}
if ((!c) || (!u) || (u->registered != REG_ALL))
{
- user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), c ? parameters[0].c_str() : parameters[1].c_str());
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", c ? parameters[0].c_str() : parameters[1].c_str());
return CMD_FAILURE;
}
+ // Verify channel timestamp if the INVITE is coming from a remote server
+ if (!IS_LOCAL(user))
+ {
+ // Remote INVITE commands must carry a channel timestamp
+ if (parameters.size() < 3)
+ return CMD_INVALID;
+
+ // Drop the invite if our channel TS is lower
+ time_t RemoteTS = ConvToInt(parameters[2]);
+ if (c->age < RemoteTS)
+ return CMD_FAILURE;
+ }
+
if ((IS_LOCAL(user)) && (!c->HasUser(user)))
{
- user->WriteNumeric(ERR_NOTONCHANNEL, "%s %s :You're not on that channel!",user->nick.c_str(), c->name.c_str());
+ user->WriteNumeric(ERR_NOTONCHANNEL, "%s :You're not on that channel!", c->name.c_str());
return CMD_FAILURE;
}
if (c->HasUser(u))
{
- user->WriteNumeric(ERR_USERONCHANNEL, "%s %s %s :is already on channel",user->nick.c_str(),u->nick.c_str(),c->name.c_str());
+ user->WriteNumeric(ERR_USERONCHANNEL, "%s %s :is already on channel", u->nick.c_str(), c->name.c_str());
return CMD_FAILURE;
}
@@ -99,17 +100,22 @@ CmdResult CommandInvite::Handle (const std::vector<std::string>& parameters, Use
{
// Check whether halfop mode is available and phrase error message accordingly
ModeHandler* mh = ServerInstance->Modes->FindMode('h', MODETYPE_CHANNEL);
- user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must be a channel %soperator",
- user->nick.c_str(), c->name.c_str(), (mh && mh->name == "halfop" ? "half-" : ""));
+ user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s :You must be a channel %soperator",
+ c->name.c_str(), (mh && mh->name == "halfop" ? "half-" : ""));
return CMD_FAILURE;
}
}
}
if (IS_LOCAL(u))
- IS_LOCAL(u)->InviteTo(c->name.c_str(), timeout);
- u->WriteFrom(user,"INVITE %s :%s",u->nick.c_str(),c->name.c_str());
- user->WriteNumeric(RPL_INVITING, "%s %s %s",user->nick.c_str(),u->nick.c_str(),c->name.c_str());
+ {
+ Invitation::Create(c, IS_LOCAL(u), timeout);
+ u->WriteFrom(user,"INVITE %s :%s",u->nick.c_str(),c->name.c_str());
+ }
+
+ if (IS_LOCAL(user))
+ user->WriteNumeric(RPL_INVITING, "%s %s", u->nick.c_str(),c->name.c_str());
+
if (ServerInstance->Config->AnnounceInvites != ServerConfig::INVITE_ANNOUNCE_NONE)
{
char prefix;
@@ -122,7 +128,7 @@ CmdResult CommandInvite::Handle (const std::vector<std::string>& parameters, Use
}
case ServerConfig::INVITE_ANNOUNCE_DYNAMIC:
{
- ModeHandler* mh = ServerInstance->Modes->FindMode('h', MODETYPE_CHANNEL);
+ PrefixMode* mh = ServerInstance->Modes->FindPrefixMode('h');
prefix = (mh && mh->name == "halfop" ? mh->GetPrefix() : '@');
break;
}
@@ -134,7 +140,7 @@ CmdResult CommandInvite::Handle (const std::vector<std::string>& parameters, Use
}
c->WriteAllExceptSender(user, true, prefix, "NOTICE %s :*** %s invited %s into the channel", c->name.c_str(), user->nick.c_str(), u->nick.c_str());
}
- FOREACH_MOD(I_OnUserInvite,OnUserInvite(user,u,c,timeout));
+ FOREACH_MOD(OnUserInvite, (user,u,c,timeout));
}
else if (IS_LOCAL(user))
{
@@ -143,12 +149,14 @@ CmdResult CommandInvite::Handle (const std::vector<std::string>& parameters, Use
InviteList& il = IS_LOCAL(user)->GetInviteList();
for (InviteList::const_iterator i = il.begin(); i != il.end(); ++i)
{
- user->WriteNumeric(RPL_INVITELIST, "%s :%s",user->nick.c_str(), (*i)->chan->name.c_str());
+ user->WriteNumeric(RPL_INVITELIST, ":%s", (*i)->chan->name.c_str());
}
- user->WriteNumeric(RPL_ENDOFINVITELIST, "%s :End of INVITE list",user->nick.c_str());
+ user->WriteNumeric(RPL_ENDOFINVITELIST, ":End of INVITE list");
}
return CMD_SUCCESS;
}
-
-COMMAND_INIT(CommandInvite)
+RouteDescriptor CommandInvite::GetRouting(User* user, const std::vector<std::string>& parameters)
+{
+ return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST);
+}
diff --git a/src/coremods/core_channel/cmd_join.cpp b/src/coremods/core_channel/cmd_join.cpp
new file mode 100644
index 000000000..1945bf52e
--- /dev/null
+++ b/src/coremods/core_channel/cmd_join.cpp
@@ -0,0 +1,60 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "core_channel.h"
+
+CommandJoin::CommandJoin(Module* parent)
+ : SplitCommand(parent, "JOIN", 1, 2)
+{
+ syntax = "<channel>{,<channel>} {<key>{,<key>}}";
+ Penalty = 2;
+}
+
+/** Handle /JOIN
+ */
+CmdResult CommandJoin::HandleLocal(const std::vector<std::string>& parameters, LocalUser *user)
+{
+ if (parameters.size() > 1)
+ {
+ if (CommandParser::LoopCall(user, this, parameters, 0, 1, false))
+ return CMD_SUCCESS;
+
+ if (ServerInstance->IsChannel(parameters[0]))
+ {
+ Channel::JoinUser(user, parameters[0], false, parameters[1]);
+ return CMD_SUCCESS;
+ }
+ }
+ else
+ {
+ if (CommandParser::LoopCall(user, this, parameters, 0, -1, false))
+ return CMD_SUCCESS;
+
+ if (ServerInstance->IsChannel(parameters[0]))
+ {
+ Channel::JoinUser(user, parameters[0]);
+ return CMD_SUCCESS;
+ }
+ }
+
+ user->WriteNumeric(ERR_NOSUCHCHANNEL, "%s :Invalid channel name", parameters[0].c_str());
+ return CMD_FAILURE;
+}
diff --git a/src/coremods/core_channel/cmd_kick.cpp b/src/coremods/core_channel/cmd_kick.cpp
new file mode 100644
index 000000000..e2fdd7877
--- /dev/null
+++ b/src/coremods/core_channel/cmd_kick.cpp
@@ -0,0 +1,128 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "core_channel.h"
+
+CommandKick::CommandKick(Module* parent)
+ : Command(parent, "KICK", 2, 3)
+{
+ syntax = "<channel> <nick>{,<nick>} [<reason>]";
+}
+
+/** Handle /KICK
+ */
+CmdResult CommandKick::Handle (const std::vector<std::string>& parameters, User *user)
+{
+ Channel* c = ServerInstance->FindChan(parameters[0]);
+ User* u;
+
+ if (CommandParser::LoopCall(user, this, parameters, 1))
+ return CMD_SUCCESS;
+
+ if (IS_LOCAL(user))
+ u = ServerInstance->FindNickOnly(parameters[1]);
+ else
+ u = ServerInstance->FindNick(parameters[1]);
+
+ if ((!u) || (!c) || (u->registered != REG_ALL))
+ {
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", c ? parameters[1].c_str() : parameters[0].c_str());
+ return CMD_FAILURE;
+ }
+
+ Membership* srcmemb = NULL;
+ if (IS_LOCAL(user))
+ {
+ srcmemb = c->GetUser(user);
+ if (!srcmemb)
+ {
+ user->WriteNumeric(ERR_NOTONCHANNEL, "%s :You're not on that channel!", parameters[0].c_str());
+ return CMD_FAILURE;
+ }
+
+ if (u->server->IsULine())
+ {
+ user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s :You may not kick a u-lined client", c->name.c_str());
+ return CMD_FAILURE;
+ }
+ }
+
+ const Channel::MemberMap::iterator victimiter = c->userlist.find(u);
+ if (victimiter == c->userlist.end())
+ {
+ user->WriteNumeric(ERR_USERNOTINCHANNEL, "%s %s :They are not on that channel", u->nick.c_str(), c->name.c_str());
+ return CMD_FAILURE;
+ }
+ Membership* const memb = victimiter->second;
+
+ // KICKs coming from servers can carry a membership id
+ if ((!IS_LOCAL(user)) && (parameters.size() > 3))
+ {
+ // If the current membership id is not equal to the one in the message then the user rejoined
+ if (memb->id != Membership::IdFromString(parameters[2]))
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Dropped KICK due to membership id mismatch: " + ConvToStr(memb->id) + " != " + parameters[2]);
+ return CMD_FAILURE;
+ }
+ }
+
+ const bool has_reason = (parameters.size() > 2);
+ const std::string reason((has_reason ? parameters.back() : user->nick), 0, ServerInstance->Config->Limits.MaxKick);
+
+ // Do the following checks only if the KICK is done by a local user;
+ // each server enforces its own rules.
+ if (srcmemb)
+ {
+ // Modules are allowed to explicitly allow or deny kicks done by local users
+ ModResult res;
+ FIRST_MOD_RESULT(OnUserPreKick, res, (user, memb, reason));
+ if (res == MOD_RES_DENY)
+ return CMD_FAILURE;
+
+ if (res == MOD_RES_PASSTHRU)
+ {
+ unsigned int them = srcmemb->getRank();
+ unsigned int req = HALFOP_VALUE;
+ for (std::string::size_type i = 0; i < memb->modes.length(); i++)
+ {
+ ModeHandler* mh = ServerInstance->Modes->FindMode(memb->modes[i], MODETYPE_CHANNEL);
+ if (mh && mh->GetLevelRequired() > req)
+ req = mh->GetLevelRequired();
+ }
+
+ if (them < req)
+ {
+ user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s :You must be a channel %soperator",
+ this->name.c_str(), req > HALFOP_VALUE ? "" : "half-");
+ return CMD_FAILURE;
+ }
+ }
+ }
+
+ c->KickUser(user, victimiter, reason);
+
+ return CMD_SUCCESS;
+}
+
+RouteDescriptor CommandKick::GetRouting(User* user, const std::vector<std::string>& parameters)
+{
+ return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST);
+}
diff --git a/src/commands/cmd_names.cpp b/src/coremods/core_channel/cmd_names.cpp
index fd4a9cef5..20faae774 100644
--- a/src/commands/cmd_names.cpp
+++ b/src/coremods/core_channel/cmd_names.cpp
@@ -19,26 +19,14 @@
#include "inspircd.h"
+#include "core_channel.h"
-/** Handle /NAMES. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandNames : public Command
+CommandNames::CommandNames(Module* parent)
+ : Command(parent, "NAMES", 0, 0)
+ , secretmode(parent, "secret")
{
- public:
- /** Constructor for names.
- */
- CommandNames ( Module* parent) : Command(parent,"NAMES",0,0) { syntax = "{<channel>{,<channel>}}"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
+ syntax = "{<channel>{,<channel>}}";
+}
/** Handle /NAMES
*/
@@ -48,24 +36,29 @@ CmdResult CommandNames::Handle (const std::vector<std::string>& parameters, User
if (!parameters.size())
{
- user->WriteNumeric(366, "%s * :End of /NAMES list.",user->nick.c_str());
+ user->WriteNumeric(RPL_ENDOFNAMES, "* :End of /NAMES list.");
return CMD_SUCCESS;
}
- if (ServerInstance->Parser->LoopCall(user, this, parameters, 0))
+ if (CommandParser::LoopCall(user, this, parameters, 0))
return CMD_SUCCESS;
c = ServerInstance->FindChan(parameters[0]);
if (c)
{
- c->UserList(user);
- }
- else
- {
- user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
+ // Show the NAMES list if one of the following is true:
+ // - the channel is not secret
+ // - the user doing the /NAMES is inside the channel
+ // - the user doing the /NAMES has the channels/auspex privilege
+
+ bool has_user = c->HasUser(user);
+ if ((!c->IsModeSet(secretmode)) || (has_user) || (user->HasPrivPermission("channels/auspex")))
+ {
+ c->UserList(user, has_user);
+ return CMD_SUCCESS;
+ }
}
- return CMD_SUCCESS;
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", parameters[0].c_str());
+ return CMD_FAILURE;
}
-
-COMMAND_INIT(CommandNames)
diff --git a/src/coremods/core_channel/cmd_topic.cpp b/src/coremods/core_channel/cmd_topic.cpp
new file mode 100644
index 000000000..ea723c024
--- /dev/null
+++ b/src/coremods/core_channel/cmd_topic.cpp
@@ -0,0 +1,86 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net>
+ * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc>
+ * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "core_channel.h"
+
+CommandTopic::CommandTopic(Module* parent)
+ : SplitCommand(parent, "TOPIC", 1, 2)
+ , secretmode(parent, "secret")
+ , topiclockmode(parent, "topiclock")
+{
+ syntax = "<channel> [<topic>]";
+ Penalty = 2;
+}
+
+CmdResult CommandTopic::HandleLocal(const std::vector<std::string>& parameters, LocalUser* user)
+{
+ Channel* c = ServerInstance->FindChan(parameters[0]);
+ if (!c)
+ {
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", parameters[0].c_str());
+ return CMD_FAILURE;
+ }
+
+ if (parameters.size() == 1)
+ {
+ if ((c->IsModeSet(secretmode)) && (!c->HasUser(user)))
+ {
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", c->name.c_str());
+ return CMD_FAILURE;
+ }
+
+ if (c->topic.length())
+ {
+ user->WriteNumeric(RPL_TOPIC, "%s :%s", c->name.c_str(), c->topic.c_str());
+ user->WriteNumeric(RPL_TOPICTIME, "%s %s %lu", c->name.c_str(), c->setby.c_str(), (unsigned long)c->topicset);
+ }
+ else
+ {
+ user->WriteNumeric(RPL_NOTOPICSET, "%s :No topic is set.", c->name.c_str());
+ }
+ return CMD_SUCCESS;
+ }
+
+ std::string t = parameters[1]; // needed, in case a module wants to change it
+ ModResult res;
+ FIRST_MOD_RESULT(OnPreTopicChange, res, (user,c,t));
+
+ if (res == MOD_RES_DENY)
+ return CMD_FAILURE;
+ if (res != MOD_RES_ALLOW)
+ {
+ if (!c->HasUser(user))
+ {
+ user->WriteNumeric(ERR_NOTONCHANNEL, "%s :You're not on that channel!", c->name.c_str());
+ return CMD_FAILURE;
+ }
+ if (c->IsModeSet(topiclockmode) && !ServerInstance->OnCheckExemption(user, c, "topiclock").check(c->GetPrefixValue(user) >= HALFOP_VALUE))
+ {
+ user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s :You do not have access to change the topic on this channel", c->name.c_str());
+ return CMD_FAILURE;
+ }
+ }
+
+ c->SetTopic(user, t);
+ return CMD_SUCCESS;
+}
diff --git a/src/modules/account.h b/src/coremods/core_channel/core_channel.cpp
index ba671ba0b..47f722e1e 100644
--- a/src/modules/account.h
+++ b/src/coremods/core_channel/core_channel.cpp
@@ -1,7 +1,7 @@
/*
* InspIRCd -- Internet Relay Chat Daemon
*
- * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc>
+ * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com>
*
* This file is part of InspIRCd. InspIRCd is free software: you can
* redistribute it and/or modify it under the terms of the GNU General Public
@@ -17,28 +17,27 @@
*/
-#ifndef ACCOUNT_H
-#define ACCOUNT_H
+#include "inspircd.h"
+#include "core_channel.h"
-#include <map>
-#include <string>
-
-class AccountEvent : public Event
+class CoreModChannel : public Module
{
+ CommandInvite cmdinvite;
+ CommandJoin cmdjoin;
+ CommandKick cmdkick;
+ CommandNames cmdnames;
+ CommandTopic cmdtopic;
+
public:
- User* const user;
- const std::string account;
- AccountEvent(Module* me, User* u, const std::string& name)
- : Event(me, "account_login"), user(u), account(name)
+ CoreModChannel()
+ : cmdinvite(this), cmdjoin(this), cmdkick(this), cmdnames(this), cmdtopic(this)
{
}
-};
-
-typedef StringExtItem AccountExtItem;
-inline AccountExtItem* GetAccountExtItem()
-{
- return static_cast<AccountExtItem*>(ServerInstance->Extensions.GetItem("accountname"));
-}
+ Version GetVersion() CXX11_OVERRIDE
+ {
+ return Version("Provides the INVITE, JOIN, KICK, NAMES, and TOPIC commands", VF_VENDOR|VF_CORE);
+ }
+};
-#endif
+MODULE_INIT(CoreModChannel)
diff --git a/src/coremods/core_channel/core_channel.h b/src/coremods/core_channel/core_channel.h
new file mode 100644
index 000000000..d3adbc9c9
--- /dev/null
+++ b/src/coremods/core_channel/core_channel.h
@@ -0,0 +1,114 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#pragma once
+
+#include "inspircd.h"
+
+/** Handle /INVITE.
+ */
+class CommandInvite : public Command
+{
+ public:
+ /** Constructor for invite.
+ */
+ CommandInvite (Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User*user);
+ RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters);
+};
+
+/** Handle /JOIN.
+ */
+class CommandJoin : public SplitCommand
+{
+ public:
+ /** Constructor for join.
+ */
+ CommandJoin(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult HandleLocal(const std::vector<std::string>& parameters, LocalUser* user);
+};
+
+/** Handle /TOPIC.
+ */
+class CommandTopic : public SplitCommand
+{
+ ChanModeReference secretmode;
+ ChanModeReference topiclockmode;
+
+ public:
+ /** Constructor for topic.
+ */
+ CommandTopic(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult HandleLocal(const std::vector<std::string>& parameters, LocalUser* user);
+};
+
+/** Handle /NAMES.
+ */
+class CommandNames : public Command
+{
+ ChanModeReference secretmode;
+
+ public:
+ /** Constructor for names.
+ */
+ CommandNames(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User *user);
+};
+
+/** Handle /KICK.
+ */
+class CommandKick : public Command
+{
+ public:
+ /** Constructor for kick.
+ */
+ CommandKick(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User *user);
+ RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters);
+};
diff --git a/src/coremods/core_dns.cpp b/src/coremods/core_dns.cpp
new file mode 100644
index 000000000..47d5b3cab
--- /dev/null
+++ b/src/coremods/core_dns.cpp
@@ -0,0 +1,833 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2013 Adam <Adam@anope.org>
+ * Copyright (C) 2003-2013 Anope Team <team@anope.org>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "inspircd.h"
+#include "modules/dns.h"
+#include <iostream>
+#include <fstream>
+
+#ifdef _WIN32
+#include <Iphlpapi.h>
+#pragma comment(lib, "Iphlpapi.lib")
+#endif
+
+using namespace DNS;
+
+/** A full packet sent or recieved to/from the nameserver
+ */
+class Packet : public Query
+{
+ void PackName(unsigned char* output, unsigned short output_size, unsigned short& pos, const std::string& name)
+ {
+ if (pos + name.length() + 2 > output_size)
+ throw Exception("Unable to pack name");
+
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Packing name " + name);
+
+ irc::sepstream sep(name, '.');
+ std::string token;
+
+ while (sep.GetToken(token))
+ {
+ output[pos++] = token.length();
+ memcpy(&output[pos], token.data(), token.length());
+ pos += token.length();
+ }
+
+ output[pos++] = 0;
+ }
+
+ std::string UnpackName(const unsigned char* input, unsigned short input_size, unsigned short& pos)
+ {
+ std::string name;
+ unsigned short pos_ptr = pos, lowest_ptr = input_size;
+ bool compressed = false;
+
+ if (pos_ptr >= input_size)
+ throw Exception("Unable to unpack name - no input");
+
+ while (input[pos_ptr] > 0)
+ {
+ unsigned short offset = input[pos_ptr];
+
+ if (offset & POINTER)
+ {
+ if ((offset & POINTER) != POINTER)
+ throw Exception("Unable to unpack name - bogus compression header");
+ if (pos_ptr + 1 >= input_size)
+ throw Exception("Unable to unpack name - bogus compression header");
+
+ /* Place pos at the second byte of the first (farthest) compression pointer */
+ if (compressed == false)
+ {
+ ++pos;
+ compressed = true;
+ }
+
+ pos_ptr = (offset & LABEL) << 8 | input[pos_ptr + 1];
+
+ /* Pointers can only go back */
+ if (pos_ptr >= lowest_ptr)
+ throw Exception("Unable to unpack name - bogus compression pointer");
+ lowest_ptr = pos_ptr;
+ }
+ else
+ {
+ if (pos_ptr + offset + 1 >= input_size)
+ throw Exception("Unable to unpack name - offset too large");
+ if (!name.empty())
+ name += ".";
+ for (unsigned i = 1; i <= offset; ++i)
+ name += input[pos_ptr + i];
+
+ pos_ptr += offset + 1;
+ if (compressed == false)
+ /* Move up pos */
+ pos = pos_ptr;
+ }
+ }
+
+ /* +1 pos either to one byte after the compression pointer or one byte after the ending \0 */
+ ++pos;
+
+ if (name.empty())
+ throw Exception("Unable to unpack name - no name");
+
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Unpack name " + name);
+
+ return name;
+ }
+
+ Question UnpackQuestion(const unsigned char* input, unsigned short input_size, unsigned short& pos)
+ {
+ Question question;
+
+ question.name = this->UnpackName(input, input_size, pos);
+
+ if (pos + 4 > input_size)
+ throw Exception("Unable to unpack question");
+
+ question.type = static_cast<QueryType>(input[pos] << 8 | input[pos + 1]);
+ pos += 2;
+
+ question.qclass = input[pos] << 8 | input[pos + 1];
+ pos += 2;
+
+ return question;
+ }
+
+ ResourceRecord UnpackResourceRecord(const unsigned char* input, unsigned short input_size, unsigned short& pos)
+ {
+ ResourceRecord record = static_cast<ResourceRecord>(this->UnpackQuestion(input, input_size, pos));
+
+ if (pos + 6 > input_size)
+ throw Exception("Unable to unpack resource record");
+
+ record.ttl = (input[pos] << 24) | (input[pos + 1] << 16) | (input[pos + 2] << 8) | input[pos + 3];
+ pos += 4;
+
+ //record.rdlength = input[pos] << 8 | input[pos + 1];
+ pos += 2;
+
+ switch (record.type)
+ {
+ case QUERY_A:
+ {
+ if (pos + 4 > input_size)
+ throw Exception("Unable to unpack resource record");
+
+ irc::sockets::sockaddrs addrs;
+ memset(&addrs, 0, sizeof(addrs));
+
+ addrs.in4.sin_family = AF_INET;
+ addrs.in4.sin_addr.s_addr = input[pos] | (input[pos + 1] << 8) | (input[pos + 2] << 16) | (input[pos + 3] << 24);
+ pos += 4;
+
+ record.rdata = addrs.addr();
+ break;
+ }
+ case QUERY_AAAA:
+ {
+ if (pos + 16 > input_size)
+ throw Exception("Unable to unpack resource record");
+
+ irc::sockets::sockaddrs addrs;
+ memset(&addrs, 0, sizeof(addrs));
+
+ addrs.in6.sin6_family = AF_INET6;
+ for (int j = 0; j < 16; ++j)
+ addrs.in6.sin6_addr.s6_addr[j] = input[pos + j];
+ pos += 16;
+
+ record.rdata = addrs.addr();
+
+ break;
+ }
+ case QUERY_CNAME:
+ case QUERY_PTR:
+ {
+ record.rdata = this->UnpackName(input, input_size, pos);
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (!record.name.empty() && !record.rdata.empty())
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, record.name + " -> " + record.rdata);
+
+ return record;
+ }
+
+ public:
+ static const int POINTER = 0xC0;
+ static const int LABEL = 0x3F;
+ static const int HEADER_LENGTH = 12;
+
+ /* ID for this packet */
+ unsigned short id;
+ /* Flags on the packet */
+ unsigned short flags;
+
+ Packet() : id(0), flags(0)
+ {
+ }
+
+ void Fill(const unsigned char* input, const unsigned short len)
+ {
+ if (len < HEADER_LENGTH)
+ throw Exception("Unable to fill packet");
+
+ unsigned short packet_pos = 0;
+
+ this->id = (input[packet_pos] << 8) | input[packet_pos + 1];
+ packet_pos += 2;
+
+ if (this->id >= MAX_REQUEST_ID)
+ throw Exception("Query ID too large?");
+
+ this->flags = (input[packet_pos] << 8) | input[packet_pos + 1];
+ packet_pos += 2;
+
+ unsigned short qdcount = (input[packet_pos] << 8) | input[packet_pos + 1];
+ packet_pos += 2;
+
+ unsigned short ancount = (input[packet_pos] << 8) | input[packet_pos + 1];
+ packet_pos += 2;
+
+ unsigned short nscount = (input[packet_pos] << 8) | input[packet_pos + 1];
+ packet_pos += 2;
+
+ unsigned short arcount = (input[packet_pos] << 8) | input[packet_pos + 1];
+ packet_pos += 2;
+
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "qdcount: " + ConvToStr(qdcount) + " ancount: " + ConvToStr(ancount) + " nscount: " + ConvToStr(nscount) + " arcount: " + ConvToStr(arcount));
+
+ for (unsigned i = 0; i < qdcount; ++i)
+ this->questions.push_back(this->UnpackQuestion(input, len, packet_pos));
+
+ for (unsigned i = 0; i < ancount; ++i)
+ this->answers.push_back(this->UnpackResourceRecord(input, len, packet_pos));
+ }
+
+ unsigned short Pack(unsigned char* output, unsigned short output_size)
+ {
+ if (output_size < HEADER_LENGTH)
+ throw Exception("Unable to pack packet");
+
+ unsigned short pos = 0;
+
+ output[pos++] = this->id >> 8;
+ output[pos++] = this->id & 0xFF;
+ output[pos++] = this->flags >> 8;
+ output[pos++] = this->flags & 0xFF;
+ output[pos++] = this->questions.size() >> 8;
+ output[pos++] = this->questions.size() & 0xFF;
+ output[pos++] = this->answers.size() >> 8;
+ output[pos++] = this->answers.size() & 0xFF;
+ output[pos++] = 0;
+ output[pos++] = 0;
+ output[pos++] = 0;
+ output[pos++] = 0;
+
+ for (unsigned i = 0; i < this->questions.size(); ++i)
+ {
+ Question& q = this->questions[i];
+
+ if (q.type == QUERY_PTR)
+ {
+ irc::sockets::sockaddrs ip;
+ irc::sockets::aptosa(q.name, 0, ip);
+
+ if (q.name.find(':') != std::string::npos)
+ {
+ static const char* const hex = "0123456789abcdef";
+ char reverse_ip[128];
+ unsigned reverse_ip_count = 0;
+ for (int j = 15; j >= 0; --j)
+ {
+ reverse_ip[reverse_ip_count++] = hex[ip.in6.sin6_addr.s6_addr[j] & 0xF];
+ reverse_ip[reverse_ip_count++] = '.';
+ reverse_ip[reverse_ip_count++] = hex[ip.in6.sin6_addr.s6_addr[j] >> 4];
+ reverse_ip[reverse_ip_count++] = '.';
+ }
+ reverse_ip[reverse_ip_count++] = 0;
+
+ q.name = reverse_ip;
+ q.name += "ip6.arpa";
+ }
+ else
+ {
+ unsigned long forward = ip.in4.sin_addr.s_addr;
+ ip.in4.sin_addr.s_addr = forward << 24 | (forward & 0xFF00) << 8 | (forward & 0xFF0000) >> 8 | forward >> 24;
+
+ q.name = ip.addr() + ".in-addr.arpa";
+ }
+ }
+
+ this->PackName(output, output_size, pos, q.name);
+
+ if (pos + 4 >= output_size)
+ throw Exception("Unable to pack packet");
+
+ short s = htons(q.type);
+ memcpy(&output[pos], &s, 2);
+ pos += 2;
+
+ s = htons(q.qclass);
+ memcpy(&output[pos], &s, 2);
+ pos += 2;
+ }
+
+ for (unsigned int i = 0; i < answers.size(); i++)
+ {
+ ResourceRecord& rr = answers[i];
+
+ this->PackName(output, output_size, pos, rr.name);
+
+ if (pos + 8 >= output_size)
+ throw Exception("Unable to pack packet");
+
+ short s = htons(rr.type);
+ memcpy(&output[pos], &s, 2);
+ pos += 2;
+
+ s = htons(rr.qclass);
+ memcpy(&output[pos], &s, 2);
+ pos += 2;
+
+ long l = htonl(rr.ttl);
+ memcpy(&output[pos], &l, 4);
+ pos += 4;
+
+ switch (rr.type)
+ {
+ case QUERY_A:
+ {
+ if (pos + 6 > output_size)
+ throw Exception("Unable to pack packet");
+
+ irc::sockets::sockaddrs a;
+ irc::sockets::aptosa(rr.rdata, 0, a);
+
+ s = htons(4);
+ memcpy(&output[pos], &s, 2);
+ pos += 2;
+
+ memcpy(&output[pos], &a.in4.sin_addr, 4);
+ pos += 4;
+ break;
+ }
+ case QUERY_AAAA:
+ {
+ if (pos + 18 > output_size)
+ throw Exception("Unable to pack packet");
+
+ irc::sockets::sockaddrs a;
+ irc::sockets::aptosa(rr.rdata, 0, a);
+
+ s = htons(16);
+ memcpy(&output[pos], &s, 2);
+ pos += 2;
+
+ memcpy(&output[pos], &a.in6.sin6_addr, 16);
+ pos += 16;
+ break;
+ }
+ case QUERY_CNAME:
+ case QUERY_PTR:
+ {
+ if (pos + 2 >= output_size)
+ throw Exception("Unable to pack packet");
+
+ unsigned short packet_pos_save = pos;
+ pos += 2;
+
+ this->PackName(output, output_size, pos, rr.rdata);
+
+ s = htons(pos - packet_pos_save - 2);
+ memcpy(&output[packet_pos_save], &s, 2);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ return pos;
+ }
+};
+
+class MyManager : public Manager, public Timer, public EventHandler
+{
+ typedef TR1NS::unordered_map<Question, Query, Question::hash> cache_map;
+ cache_map cache;
+
+ irc::sockets::sockaddrs myserver;
+
+ static bool IsExpired(const Query& record, time_t now = ServerInstance->Time())
+ {
+ const ResourceRecord& req = record.answers[0];
+ return (req.created + static_cast<time_t>(req.ttl) < now);
+ }
+
+ /** Check the DNS cache to see if request can be handled by a cached result
+ * @return true if a cached result was found.
+ */
+ bool CheckCache(DNS::Request* req, const DNS::Question& question)
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_SPARSE, "cache: Checking cache for " + question.name);
+
+ cache_map::iterator it = this->cache.find(question);
+ if (it == this->cache.end())
+ return false;
+
+ Query& record = it->second;
+ if (IsExpired(record))
+ {
+ this->cache.erase(it);
+ return false;
+ }
+
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "cache: Using cached result for " + question.name);
+ record.cached = true;
+ req->OnLookupComplete(&record);
+ return true;
+ }
+
+ /** Add a record to the dns cache
+ * @param r The record
+ */
+ void AddCache(Query& r)
+ {
+ const ResourceRecord& rr = r.answers[0];
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "cache: added cache for " + rr.name + " -> " + rr.rdata + " ttl: " + ConvToStr(rr.ttl));
+ this->cache[r.questions[0]] = r;
+ }
+
+ public:
+ DNS::Request* requests[MAX_REQUEST_ID];
+
+ MyManager(Module* c) : Manager(c), Timer(3600, true)
+ {
+ for (int i = 0; i < MAX_REQUEST_ID; ++i)
+ requests[i] = NULL;
+ ServerInstance->Timers.AddTimer(this);
+ }
+
+ ~MyManager()
+ {
+ for (int i = 0; i < MAX_REQUEST_ID; ++i)
+ {
+ DNS::Request* request = requests[i];
+ if (!request)
+ continue;
+
+ Query rr(*request);
+ rr.error = ERROR_UNKNOWN;
+ request->OnError(&rr);
+
+ delete request;
+ }
+ }
+
+ void Process(DNS::Request* req)
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Processing request to lookup " + req->name + " of type " + ConvToStr(req->type) + " to " + this->myserver.addr());
+
+ /* Create an id */
+ unsigned int tries = 0;
+ do
+ {
+ req->id = ServerInstance->GenRandomInt(DNS::MAX_REQUEST_ID);
+
+ if (++tries == DNS::MAX_REQUEST_ID*5)
+ {
+ // If we couldn't find an empty slot this many times, do a sequential scan as a last
+ // resort. If an empty slot is found that way, go on, otherwise throw an exception
+ req->id = 0;
+ for (int i = 1; i < DNS::MAX_REQUEST_ID; i++)
+ {
+ if (!this->requests[i])
+ {
+ req->id = i;
+ break;
+ }
+ }
+
+ if (req->id == 0)
+ throw Exception("DNS: All ids are in use");
+
+ break;
+ }
+ }
+ while (!req->id || this->requests[req->id]);
+
+ this->requests[req->id] = req;
+
+ Packet p;
+ p.flags = QUERYFLAGS_RD;
+ p.id = req->id;
+ p.questions.push_back(*req);
+
+ unsigned char buffer[524];
+ unsigned short len = p.Pack(buffer, sizeof(buffer));
+
+ /* Note that calling Pack() above can actually change the contents of p.questions[0].name, if the query is a PTR,
+ * to contain the value that would be in the DNS cache, which is why this is here.
+ */
+ if (req->use_cache && this->CheckCache(req, p.questions[0]))
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Using cached result");
+ delete req;
+ return;
+ }
+
+ if (SocketEngine::SendTo(this, buffer, len, 0, &this->myserver.sa, this->myserver.sa_size()) != len)
+ throw Exception("DNS: Unable to send query");
+ }
+
+ void RemoveRequest(DNS::Request* req)
+ {
+ this->requests[req->id] = NULL;
+ }
+
+ std::string GetErrorStr(Error e)
+ {
+ switch (e)
+ {
+ case ERROR_UNLOADED:
+ return "Module is unloading";
+ case ERROR_TIMEDOUT:
+ return "Request timed out";
+ case ERROR_NOT_AN_ANSWER:
+ case ERROR_NONSTANDARD_QUERY:
+ case ERROR_FORMAT_ERROR:
+ return "Malformed answer";
+ case ERROR_SERVER_FAILURE:
+ case ERROR_NOT_IMPLEMENTED:
+ case ERROR_REFUSED:
+ case ERROR_INVALIDTYPE:
+ return "Nameserver failure";
+ case ERROR_DOMAIN_NOT_FOUND:
+ case ERROR_NO_RECORDS:
+ return "Domain not found";
+ case ERROR_NONE:
+ case ERROR_UNKNOWN:
+ default:
+ return "Unknown error";
+ }
+ }
+
+ void HandleEvent(EventType et, int)
+ {
+ if (et == EVENT_ERROR)
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "UDP socket got an error event");
+ return;
+ }
+
+ unsigned char buffer[524];
+ irc::sockets::sockaddrs from;
+ socklen_t x = sizeof(from);
+
+ int length = SocketEngine::RecvFrom(this, buffer, sizeof(buffer), 0, &from.sa, &x);
+
+ if (length < Packet::HEADER_LENGTH)
+ return;
+
+ Packet recv_packet;
+
+ try
+ {
+ recv_packet.Fill(buffer, length);
+ }
+ catch (Exception& ex)
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, ex.GetReason());
+ return;
+ }
+
+ if (myserver != from)
+ {
+ std::string server1 = from.str();
+ std::string server2 = myserver.str();
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Got a result from the wrong server! Bad NAT or DNS forging attempt? '%s' != '%s'",
+ server1.c_str(), server2.c_str());
+ return;
+ }
+
+ DNS::Request* request = this->requests[recv_packet.id];
+ if (request == NULL)
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Received an answer for something we didn't request");
+ return;
+ }
+
+ if (recv_packet.flags & QUERYFLAGS_OPCODE)
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Received a nonstandard query");
+ ServerInstance->stats.DnsBad++;
+ recv_packet.error = ERROR_NONSTANDARD_QUERY;
+ request->OnError(&recv_packet);
+ }
+ else if (recv_packet.flags & QUERYFLAGS_RCODE)
+ {
+ Error error = ERROR_UNKNOWN;
+
+ switch (recv_packet.flags & QUERYFLAGS_RCODE)
+ {
+ case 1:
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "format error");
+ error = ERROR_FORMAT_ERROR;
+ break;
+ case 2:
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "server error");
+ error = ERROR_SERVER_FAILURE;
+ break;
+ case 3:
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "domain not found");
+ error = ERROR_DOMAIN_NOT_FOUND;
+ break;
+ case 4:
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "not implemented");
+ error = ERROR_NOT_IMPLEMENTED;
+ break;
+ case 5:
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "refused");
+ error = ERROR_REFUSED;
+ break;
+ default:
+ break;
+ }
+
+ ServerInstance->stats.DnsBad++;
+ recv_packet.error = error;
+ request->OnError(&recv_packet);
+ }
+ else if (recv_packet.questions.empty() || recv_packet.answers.empty())
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "No resource records returned");
+ ServerInstance->stats.DnsBad++;
+ recv_packet.error = ERROR_NO_RECORDS;
+ request->OnError(&recv_packet);
+ }
+ else
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Lookup complete for " + request->name);
+ ServerInstance->stats.DnsGood++;
+ request->OnLookupComplete(&recv_packet);
+ this->AddCache(recv_packet);
+ }
+
+ ServerInstance->stats.Dns++;
+
+ /* Request's destructor removes it from the request map */
+ delete request;
+ }
+
+ bool Tick(time_t now)
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "cache: purging DNS cache");
+
+ for (cache_map::iterator it = this->cache.begin(); it != this->cache.end(); )
+ {
+ const Query& query = it->second;
+ if (IsExpired(query, now))
+ this->cache.erase(it++);
+ else
+ ++it;
+ }
+ return true;
+ }
+
+ void Rehash(const std::string& dnsserver)
+ {
+ if (this->GetFd() > -1)
+ {
+ SocketEngine::Shutdown(this, 2);
+ SocketEngine::Close(this);
+
+ /* Remove expired entries from the cache */
+ this->Tick(ServerInstance->Time());
+ }
+
+ irc::sockets::aptosa(dnsserver, DNS::PORT, myserver);
+
+ /* Initialize mastersocket */
+ int s = socket(myserver.sa.sa_family, SOCK_DGRAM, 0);
+ this->SetFd(s);
+
+ /* Have we got a socket? */
+ if (this->GetFd() != -1)
+ {
+ SocketEngine::SetReuse(s);
+ SocketEngine::NonBlocking(s);
+
+ irc::sockets::sockaddrs bindto;
+ memset(&bindto, 0, sizeof(bindto));
+ bindto.sa.sa_family = myserver.sa.sa_family;
+
+ if (SocketEngine::Bind(this->GetFd(), bindto) < 0)
+ {
+ /* Failed to bind */
+ ServerInstance->Logs->Log(MODNAME, LOG_SPARSE, "Error binding dns socket - hostnames will NOT resolve");
+ SocketEngine::Close(this->GetFd());
+ this->SetFd(-1);
+ }
+ else if (!SocketEngine::AddFd(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE))
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_SPARSE, "Internal error starting DNS - hostnames will NOT resolve.");
+ SocketEngine::Close(this->GetFd());
+ this->SetFd(-1);
+ }
+ }
+ else
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_SPARSE, "Error creating DNS socket - hostnames will NOT resolve");
+ }
+ }
+};
+
+class ModuleDNS : public Module
+{
+ MyManager manager;
+ std::string DNSServer;
+
+ void FindDNSServer()
+ {
+#ifdef _WIN32
+ // attempt to look up their nameserver from the system
+ ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "WARNING: <dns:server> not defined, attempting to find a working server in the system settings...");
+
+ PFIXED_INFO pFixedInfo;
+ DWORD dwBufferSize = sizeof(FIXED_INFO);
+ pFixedInfo = (PFIXED_INFO) HeapAlloc(GetProcessHeap(), 0, sizeof(FIXED_INFO));
+
+ if (pFixedInfo)
+ {
+ if (GetNetworkParams(pFixedInfo, &dwBufferSize) == ERROR_BUFFER_OVERFLOW)
+ {
+ HeapFree(GetProcessHeap(), 0, pFixedInfo);
+ pFixedInfo = (PFIXED_INFO) HeapAlloc(GetProcessHeap(), 0, dwBufferSize);
+ }
+
+ if (pFixedInfo)
+ {
+ if (GetNetworkParams(pFixedInfo, &dwBufferSize) == NO_ERROR)
+ DNSServer = pFixedInfo->DnsServerList.IpAddress.String;
+
+ HeapFree(GetProcessHeap(), 0, pFixedInfo);
+ }
+
+ if (!DNSServer.empty())
+ {
+ ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "<dns:server> set to '%s' as first active resolver in the system settings.", DNSServer.c_str());
+ return;
+ }
+ }
+
+ ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "No viable nameserver found! Defaulting to nameserver '127.0.0.1'!");
+#else
+ // attempt to look up their nameserver from /etc/resolv.conf
+ ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "WARNING: <dns:server> not defined, attempting to find working server in /etc/resolv.conf...");
+
+ std::ifstream resolv("/etc/resolv.conf");
+
+ while (resolv >> DNSServer)
+ {
+ if (DNSServer == "nameserver")
+ {
+ resolv >> DNSServer;
+ if (DNSServer.find_first_not_of("0123456789.") == std::string::npos)
+ {
+ ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "<dns:server> set to '%s' as first resolver in /etc/resolv.conf.",DNSServer.c_str());
+ return;
+ }
+ }
+ }
+
+ ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "/etc/resolv.conf contains no viable nameserver entries! Defaulting to nameserver '127.0.0.1'!");
+#endif
+ DNSServer = "127.0.0.1";
+ }
+
+ public:
+ ModuleDNS() : manager(this)
+ {
+ }
+
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
+ {
+ std::string oldserver = DNSServer;
+ DNSServer = ServerInstance->Config->ConfValue("dns")->getString("server");
+ if (DNSServer.empty())
+ FindDNSServer();
+
+ if (oldserver != DNSServer)
+ this->manager.Rehash(DNSServer);
+ }
+
+ void OnUnloadModule(Module* mod)
+ {
+ for (int i = 0; i < MAX_REQUEST_ID; ++i)
+ {
+ DNS::Request* req = this->manager.requests[i];
+ if (!req)
+ continue;
+
+ if (req->creator == mod)
+ {
+ Query rr(*req);
+ rr.error = ERROR_UNLOADED;
+ req->OnError(&rr);
+
+ delete req;
+ }
+ }
+ }
+
+ Version GetVersion()
+ {
+ return Version("DNS support", VF_CORE|VF_VENDOR);
+ }
+};
+
+MODULE_INIT(ModuleDNS)
+
diff --git a/src/coremods/core_hostname_lookup.cpp b/src/coremods/core_hostname_lookup.cpp
new file mode 100644
index 000000000..2c9de3c86
--- /dev/null
+++ b/src/coremods/core_hostname_lookup.cpp
@@ -0,0 +1,233 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2013 Adam <Adam@anope.org>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "modules/dns.h"
+
+namespace
+{
+ LocalIntExt* dl;
+ LocalStringExt* ph;
+}
+
+/** Derived from Resolver, and performs user forward/reverse lookups.
+ */
+class UserResolver : public DNS::Request
+{
+ /** UUID we are looking up */
+ const std::string uuid;
+
+ /** True if the lookup is forward, false if is a reverse lookup
+ */
+ const bool fwd;
+
+ public:
+ /** Create a resolver.
+ * @param mgr DNS Manager
+ * @param me this module
+ * @param user The user to begin lookup on
+ * @param to_resolve The IP or host to resolve
+ * @param qt The query type
+ */
+ UserResolver(DNS::Manager* mgr, Module* me, LocalUser* user, const std::string& to_resolve, DNS::QueryType qt)
+ : DNS::Request(mgr, me, to_resolve, qt)
+ , uuid(user->uuid)
+ , fwd(qt == DNS::QUERY_A || qt == DNS::QUERY_AAAA)
+ {
+ }
+
+ /** Called on successful lookup
+ * if a previous result has already come back.
+ * @param r The finished query
+ */
+ void OnLookupComplete(const DNS::Query* r)
+ {
+ LocalUser* bound_user = (LocalUser*)ServerInstance->FindUUID(uuid);
+ if (!bound_user)
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Resolution finished for user '%s' who is gone", uuid.c_str());
+ return;
+ }
+
+ const DNS::ResourceRecord& ans_record = r->answers[0];
+
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "DNS result for %s: '%s' -> '%s'", uuid.c_str(), ans_record.name.c_str(), ans_record.rdata.c_str());
+
+ if (!fwd)
+ {
+ // first half of resolution is done. We now need to verify that the host matches.
+ ph->set(bound_user, ans_record.rdata);
+
+ UserResolver* res_forward;
+ if (bound_user->client_sa.sa.sa_family == AF_INET6)
+ {
+ /* IPV6 forward lookup */
+ res_forward = new UserResolver(this->manager, this->creator, bound_user, ans_record.rdata, DNS::QUERY_AAAA);
+ }
+ else
+ {
+ /* IPV4 lookup */
+ res_forward = new UserResolver(this->manager, this->creator, bound_user, ans_record.rdata, DNS::QUERY_A);
+ }
+ try
+ {
+ this->manager->Process(res_forward);
+ }
+ catch (DNS::Exception& e)
+ {
+ delete res_forward;
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Error in resolver: " + e.GetReason());
+
+ bound_user->WriteNotice("*** There was an internal error resolving your host, using your IP address (" + bound_user->GetIPString() + ") instead.");
+ dl->set(bound_user, 0);
+ }
+ }
+ else
+ {
+ /* Both lookups completed */
+
+ irc::sockets::sockaddrs* user_ip = &bound_user->client_sa;
+ bool rev_match = false;
+ if (user_ip->sa.sa_family == AF_INET6)
+ {
+ struct in6_addr res_bin;
+ if (inet_pton(AF_INET6, ans_record.rdata.c_str(), &res_bin))
+ {
+ rev_match = !memcmp(&user_ip->in6.sin6_addr, &res_bin, sizeof(res_bin));
+ }
+ }
+ else
+ {
+ struct in_addr res_bin;
+ if (inet_pton(AF_INET, ans_record.rdata.c_str(), &res_bin))
+ {
+ rev_match = !memcmp(&user_ip->in4.sin_addr, &res_bin, sizeof(res_bin));
+ }
+ }
+
+ dl->set(bound_user, 0);
+
+ if (rev_match)
+ {
+ std::string* hostname = ph->get(bound_user);
+
+ if (hostname == NULL)
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "ERROR: User has no hostname attached when doing a forward lookup");
+ bound_user->WriteNotice("*** There was an internal error resolving your host, using your IP address (" + bound_user->GetIPString() + ") instead.");
+ return;
+ }
+ else if (hostname->length() <= ServerInstance->Config->Limits.MaxHost)
+ {
+ /* Hostnames starting with : are not a good thing (tm) */
+ if ((*hostname)[0] == ':')
+ hostname->insert(0, "0");
+
+ bound_user->WriteNotice("*** Found your hostname (" + *hostname + (r->cached ? ") -- cached" : ")"));
+ bound_user->host.assign(*hostname, 0, ServerInstance->Config->Limits.MaxHost);
+ bound_user->dhost = bound_user->host;
+
+ /* Invalidate cache */
+ bound_user->InvalidateCache();
+ }
+ else
+ {
+ bound_user->WriteNotice("*** Your hostname is longer than the maximum of " + ConvToStr(ServerInstance->Config->Limits.MaxHost) + " characters, using your IP address (" + bound_user->GetIPString() + ") instead.");
+ }
+
+ ph->unset(bound_user);
+ }
+ else
+ {
+ bound_user->WriteNotice("*** Your hostname does not match up with your IP address. Sorry, using your IP address (" + bound_user->GetIPString() + ") instead.");
+ }
+ }
+ }
+
+ /** Called on failed lookup
+ * @param query The errored query
+ */
+ void OnError(const DNS::Query* query)
+ {
+ LocalUser* bound_user = (LocalUser*)ServerInstance->FindUUID(uuid);
+ if (bound_user)
+ {
+ bound_user->WriteNotice("*** Could not resolve your hostname: " + this->manager->GetErrorStr(query->error) + "; using your IP address (" + bound_user->GetIPString() + ") instead.");
+ dl->set(bound_user, 0);
+ ServerInstance->stats.DnsBad++;
+ }
+ }
+};
+
+class ModuleHostnameLookup : public Module
+{
+ LocalIntExt dnsLookup;
+ LocalStringExt ptrHosts;
+ dynamic_reference<DNS::Manager> DNS;
+
+ public:
+ ModuleHostnameLookup()
+ : dnsLookup("dnsLookup", this)
+ , ptrHosts("ptrHosts", this)
+ , DNS(this, "DNS")
+ {
+ dl = &dnsLookup;
+ ph = &ptrHosts;
+ }
+
+ void OnUserInit(LocalUser *user)
+ {
+ if (!DNS || !user->MyClass->resolvehostnames)
+ {
+ user->WriteNotice("*** Skipping host resolution (disabled by server administrator)");
+ return;
+ }
+
+ user->WriteNotice("*** Looking up your hostname...");
+
+ UserResolver* res_reverse = new UserResolver(*this->DNS, this, user, user->GetIPString(), DNS::QUERY_PTR);
+ try
+ {
+ /* If both the reverse and forward queries are cached, the user will be able to pass DNS completely
+ * before Process() completes, which is why dnsLookup.set() is here, before Process()
+ */
+ this->dnsLookup.set(user, 1);
+ this->DNS->Process(res_reverse);
+ }
+ catch (DNS::Exception& e)
+ {
+ this->dnsLookup.set(user, 0);
+ delete res_reverse;
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Error in resolver: " + e.GetReason());
+ ServerInstance->stats.DnsBad++;
+ }
+ }
+
+ ModResult OnCheckReady(LocalUser* user)
+ {
+ return this->dnsLookup.get(user) ? MOD_RES_DENY : MOD_RES_PASSTHRU;
+ }
+
+ Version GetVersion()
+ {
+ return Version("Provides support for DNS lookups on connecting clients", VF_CORE|VF_VENDOR);
+ }
+};
+
+MODULE_INIT(ModuleHostnameLookup)
diff --git a/src/commands/cmd_admin.cpp b/src/coremods/core_info/cmd_admin.cpp
index 0d6c235f0..722ef8668 100644
--- a/src/commands/cmd_admin.cpp
+++ b/src/coremods/core_info/cmd_admin.cpp
@@ -19,37 +19,14 @@
#include "inspircd.h"
+#include "core_info.h"
-/** Handle /ADMIN. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandAdmin : public Command
+CommandAdmin::CommandAdmin(Module* parent)
+ : Command(parent, "ADMIN", 0, 0)
{
- public:
- /** Constructor for admin.
- */
- CommandAdmin(Module* parent) : Command(parent,"ADMIN",0,0)
- {
- Penalty = 2;
- syntax = "[<servername>]";
- }
-
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
- RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
- {
- if (parameters.size() > 0)
- return ROUTE_UNICAST(parameters[0]);
- return ROUTE_LOCALONLY;
- }
-};
+ Penalty = 2;
+ syntax = "[<servername>]";
+}
/** Handle /ADMIN
*/
@@ -59,14 +36,19 @@ CmdResult CommandAdmin::Handle (const std::vector<std::string>& parameters, User
return CMD_SUCCESS;
user->SendText(":%s %03d %s :Administrative info for %s", ServerInstance->Config->ServerName.c_str(),
RPL_ADMINME, user->nick.c_str(),ServerInstance->Config->ServerName.c_str());
- if (!ServerInstance->Config->AdminName.empty())
+ if (!AdminName.empty())
user->SendText(":%s %03d %s :Name - %s", ServerInstance->Config->ServerName.c_str(),
- RPL_ADMINLOC1, user->nick.c_str(), ServerInstance->Config->AdminName.c_str());
+ RPL_ADMINLOC1, user->nick.c_str(), AdminName.c_str());
user->SendText(":%s %03d %s :Nickname - %s", ServerInstance->Config->ServerName.c_str(),
- RPL_ADMINLOC2, user->nick.c_str(), ServerInstance->Config->AdminNick.c_str());
+ RPL_ADMINLOC2, user->nick.c_str(), AdminNick.c_str());
user->SendText(":%s %03d %s :E-Mail - %s", ServerInstance->Config->ServerName.c_str(),
- RPL_ADMINEMAIL, user->nick.c_str(), ServerInstance->Config->AdminEmail.c_str());
+ RPL_ADMINEMAIL, user->nick.c_str(), AdminEmail.c_str());
return CMD_SUCCESS;
}
-COMMAND_INIT(CommandAdmin)
+RouteDescriptor CommandAdmin::GetRouting(User* user, const std::vector<std::string>& parameters)
+{
+ if (parameters.size() > 0)
+ return ROUTE_UNICAST(parameters[0]);
+ return ROUTE_LOCALONLY;
+}
diff --git a/src/coremods/core_info/cmd_commands.cpp b/src/coremods/core_info/cmd_commands.cpp
new file mode 100644
index 000000000..3ff6728d8
--- /dev/null
+++ b/src/coremods/core_info/cmd_commands.cpp
@@ -0,0 +1,53 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "core_info.h"
+
+CommandCommands::CommandCommands(Module* parent)
+ : Command(parent, "COMMANDS", 0, 0)
+{
+ Penalty = 3;
+}
+
+/** Handle /COMMANDS
+ */
+CmdResult CommandCommands::Handle (const std::vector<std::string>&, User *user)
+{
+ const CommandParser::CommandMap& commands = ServerInstance->Parser.GetCommands();
+ std::vector<std::string> list;
+ list.reserve(commands.size());
+ for (CommandParser::CommandMap::const_iterator i = commands.begin(); i != commands.end(); ++i)
+ {
+ // Don't show S2S commands to users
+ if (i->second->flags_needed == FLAG_SERVERONLY)
+ continue;
+
+ Module* src = i->second->creator;
+ list.push_back(InspIRCd::Format(":%s %03d %s :%s %s %d %d", ServerInstance->Config->ServerName.c_str(),
+ RPL_COMMANDS, user->nick.c_str(), i->second->name.c_str(), src->ModuleSourceFile.c_str(),
+ i->second->min_params, i->second->Penalty));
+ }
+ std::sort(list.begin(), list.end());
+ for(unsigned int i=0; i < list.size(); i++)
+ user->Write(list[i]);
+ user->WriteNumeric(RPL_COMMANDSEND, ":End of COMMANDS list");
+ return CMD_SUCCESS;
+}
diff --git a/src/commands/cmd_info.cpp b/src/coremods/core_info/cmd_info.cpp
index 76e414b19..0d8c1a45a 100644
--- a/src/commands/cmd_info.cpp
+++ b/src/coremods/core_info/cmd_info.cpp
@@ -21,37 +21,14 @@
#include "inspircd.h"
+#include "core_info.h"
-/** Handle /INFO. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandInfo : public Command
+CommandInfo::CommandInfo(Module* parent)
+ : Command(parent, "INFO")
{
- public:
- /** Constructor for info.
- */
- CommandInfo(Module* parent) : Command(parent,"INFO")
- {
- Penalty = 4;
- syntax = "[<servername>]";
- }
-
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
- RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
- {
- if (parameters.size() > 0)
- return ROUTE_UNICAST(parameters[0]);
- return ROUTE_LOCALONLY;
- }
-};
+ Penalty = 4;
+ syntax = "[<servername>]";
+}
static const char* const lines[] = {
" -/\\- \2InspIRCd\2 -\\/-",
@@ -105,9 +82,14 @@ CmdResult CommandInfo::Handle (const std::vector<std::string>& parameters, User
int i=0;
while (lines[i])
user->SendText(":%s %03d %s :%s", ServerInstance->Config->ServerName.c_str(), RPL_INFO, user->nick.c_str(), lines[i++]);
- FOREACH_MOD(I_OnInfo,OnInfo(user));
+ FOREACH_MOD(OnInfo, (user));
user->SendText(":%s %03d %s :End of /INFO list", ServerInstance->Config->ServerName.c_str(), RPL_ENDOFINFO, user->nick.c_str());
return CMD_SUCCESS;
}
-COMMAND_INIT(CommandInfo)
+RouteDescriptor CommandInfo::GetRouting(User* user, const std::vector<std::string>& parameters)
+{
+ if (parameters.size() > 0)
+ return ROUTE_UNICAST(parameters[0]);
+ return ROUTE_LOCALONLY;
+}
diff --git a/src/commands/cmd_modules.cpp b/src/coremods/core_info/cmd_modules.cpp
index 2a15b43ed..cee370870 100644
--- a/src/commands/cmd_modules.cpp
+++ b/src/coremods/core_info/cmd_modules.cpp
@@ -20,50 +20,40 @@
#include "inspircd.h"
+#include "core_info.h"
-/** Handle /MODULES. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandModules : public Command
+CommandModules::CommandModules(Module* parent)
+ : Command(parent, "MODULES", 0, 0)
{
- public:
- /** Constructor for modules.
- */
- CommandModules(Module* parent) : Command(parent,"MODULES",0,0)
- {
- Penalty = 4;
- syntax = "[<servername>]";
- }
-
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
- RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
- {
- if (parameters.size() >= 1)
- return ROUTE_UNICAST(parameters[0]);
- return ROUTE_LOCALONLY;
- }
-};
+ Penalty = 4;
+ syntax = "[<servername>]";
+}
/** Handle /MODULES
*/
CmdResult CommandModules::Handle (const std::vector<std::string>& parameters, User *user)
{
- if (parameters.size() >= 1 && parameters[0] != ServerInstance->Config->ServerName)
- return CMD_SUCCESS;
+ // Don't ask remote servers about their modules unless the local user asking is an oper
+ // 2.0 asks anyway, so let's handle that the same way
+ bool for_us = (parameters.empty() || parameters[0] == ServerInstance->Config->ServerName);
+ if ((!for_us) || (!IS_LOCAL(user)))
+ {
+ if (!user->IsOper())
+ {
+ user->WriteNotice("*** You cannot check what modules other servers have loaded.");
+ return CMD_FAILURE;
+ }
- std::vector<std::string> module_names = ServerInstance->Modules->GetAllModuleNames(0);
+ // From an oper and not for us, forward
+ if (!for_us)
+ return CMD_SUCCESS;
+ }
- for (unsigned int i = 0; i < module_names.size(); i++)
+ const ModuleManager::ModuleMap& mods = ServerInstance->Modules->GetModules();
+
+ for (ModuleManager::ModuleMap::const_iterator i = mods.begin(); i != mods.end(); ++i)
{
- Module* m = ServerInstance->Modules->Find(module_names[i]);
+ Module* m = i->second;
Version V = m->GetVersion();
if (IS_LOCAL(user) && user->HasPrivPermission("servers/auspex"))
@@ -76,17 +66,17 @@ CmdResult CommandModules::Handle (const std::vector<std::string>& parameters, Us
#ifdef PURE_STATIC
user->SendText(":%s 702 %s :%p %s %s :%s", ServerInstance->Config->ServerName.c_str(),
- user->nick.c_str(), (void*)m, module_names[i].c_str(), flags.c_str(), V.description.c_str());
+ user->nick.c_str(), (void*)m, m->ModuleSourceFile.c_str(), flags.c_str(), V.description.c_str());
#else
std::string srcrev = m->ModuleDLLManager->GetVersion();
user->SendText(":%s 702 %s :%p %s %s :%s - %s", ServerInstance->Config->ServerName.c_str(),
- user->nick.c_str(), (void*)m, module_names[i].c_str(), flags.c_str(), V.description.c_str(), srcrev.c_str());
+ user->nick.c_str(), (void*)m, m->ModuleSourceFile.c_str(), flags.c_str(), V.description.c_str(), srcrev.c_str());
#endif
}
else
{
user->SendText(":%s 702 %s :%s %s", ServerInstance->Config->ServerName.c_str(),
- user->nick.c_str(), module_names[i].c_str(), V.description.c_str());
+ user->nick.c_str(), m->ModuleSourceFile.c_str(), V.description.c_str());
}
}
user->SendText(":%s 703 %s :End of MODULES list", ServerInstance->Config->ServerName.c_str(), user->nick.c_str());
@@ -94,4 +84,9 @@ CmdResult CommandModules::Handle (const std::vector<std::string>& parameters, Us
return CMD_SUCCESS;
}
-COMMAND_INIT(CommandModules)
+RouteDescriptor CommandModules::GetRouting(User* user, const std::vector<std::string>& parameters)
+{
+ if (parameters.size() >= 1)
+ return ROUTE_UNICAST(parameters[0]);
+ return ROUTE_LOCALONLY;
+}
diff --git a/src/commands/cmd_motd.cpp b/src/coremods/core_info/cmd_motd.cpp
index 8e227723e..4481e2d53 100644
--- a/src/commands/cmd_motd.cpp
+++ b/src/coremods/core_info/cmd_motd.cpp
@@ -19,32 +19,13 @@
#include "inspircd.h"
+#include "core_info.h"
-/** Handle /MOTD. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandMotd : public Command
+CommandMotd::CommandMotd(Module* parent)
+ : Command(parent, "MOTD", 0, 1)
{
- public:
- /** Constructor for motd.
- */
- CommandMotd ( Module* parent) : Command(parent,"MOTD",0,1) { syntax = "[<servername>]"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
- RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
- {
- if (parameters.size() > 0)
- return ROUTE_UNICAST(parameters[0]);
- return ROUTE_LOCALONLY;
- }
-};
+ syntax = "[<servername>]";
+}
/** Handle /MOTD
*/
@@ -54,8 +35,9 @@ CmdResult CommandMotd::Handle (const std::vector<std::string>& parameters, User
return CMD_SUCCESS;
ConfigTag* tag = NULL;
- if (IS_LOCAL(user))
- tag = user->GetClass()->config;
+ LocalUser* localuser = IS_LOCAL(user);
+ if (localuser)
+ tag = localuser->GetClass()->config;
std::string motd_name = tag->getString("motd", "motd");
ConfigFileCache::iterator motd = ServerInstance->Config->Files.find(motd_name);
if (motd == ServerInstance->Config->Files.end())
@@ -76,4 +58,9 @@ CmdResult CommandMotd::Handle (const std::vector<std::string>& parameters, User
return CMD_SUCCESS;
}
-COMMAND_INIT(CommandMotd)
+RouteDescriptor CommandMotd::GetRouting(User* user, const std::vector<std::string>& parameters)
+{
+ if (parameters.size() > 0)
+ return ROUTE_UNICAST(parameters[0]);
+ return ROUTE_LOCALONLY;
+}
diff --git a/src/coremods/core_info/cmd_time.cpp b/src/coremods/core_info/cmd_time.cpp
new file mode 100644
index 000000000..95cfb12fd
--- /dev/null
+++ b/src/coremods/core_info/cmd_time.cpp
@@ -0,0 +1,46 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "core_info.h"
+
+CommandTime::CommandTime(Module* parent)
+ : Command(parent, "TIME", 0, 0)
+{
+ syntax = "[<servername>]";
+}
+
+CmdResult CommandTime::Handle (const std::vector<std::string>& parameters, User *user)
+{
+ if (parameters.size() > 0 && parameters[0] != ServerInstance->Config->ServerName)
+ return CMD_SUCCESS;
+
+ user->SendText(":%s %03d %s %s :%s", ServerInstance->Config->ServerName.c_str(), RPL_TIME, user->nick.c_str(),
+ ServerInstance->Config->ServerName.c_str(), InspIRCd::TimeString(ServerInstance->Time()).c_str());
+
+ return CMD_SUCCESS;
+}
+
+RouteDescriptor CommandTime::GetRouting(User* user, const std::vector<std::string>& parameters)
+{
+ if (parameters.size() > 0)
+ return ROUTE_UNICAST(parameters[0]);
+ return ROUTE_LOCALONLY;
+}
diff --git a/src/modules/spanningtree.h b/src/coremods/core_info/cmd_version.cpp
index 212f35ff3..eb3ab2c4e 100644
--- a/src/modules/spanningtree.h
+++ b/src/coremods/core_info/cmd_version.cpp
@@ -2,6 +2,7 @@
* InspIRCd -- Internet Relay Chat Daemon
*
* Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
*
* This file is part of InspIRCd. InspIRCd is free software: you can
* redistribute it and/or modify it under the terms of the GNU General Public
@@ -17,27 +18,23 @@
*/
-#ifndef SPANNINGTREE_H
-#define SPANNINGTREE_H
+#include "inspircd.h"
+#include "core_info.h"
-struct AddServerEvent : public Event
+CommandVersion::CommandVersion(Module* parent)
+ : Command(parent, "VERSION", 0, 0)
{
- const std::string servername;
- AddServerEvent(Module* me, const std::string& name)
- : Event(me, "new_server"), servername(name)
- {
- Send();
- }
-};
+ syntax = "[<servername>]";
+}
-struct DelServerEvent : public Event
+CmdResult CommandVersion::Handle (const std::vector<std::string>&, User *user)
{
- const std::string servername;
- DelServerEvent(Module* me, const std::string& name)
- : Event(me, "lost_server"), servername(name)
+ std::string version = ServerInstance->GetVersionString((user->IsOper()));
+ user->WriteNumeric(RPL_VERSION, ":%s", version.c_str());
+ LocalUser *lu = IS_LOCAL(user);
+ if (lu != NULL)
{
- Send();
+ ServerInstance->ISupport.SendTo(lu);
}
-};
-
-#endif
+ return CMD_SUCCESS;
+}
diff --git a/src/coremods/core_info/core_info.cpp b/src/coremods/core_info/core_info.cpp
new file mode 100644
index 000000000..56c3c956d
--- /dev/null
+++ b/src/coremods/core_info/core_info.cpp
@@ -0,0 +1,53 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "core_info.h"
+
+class CoreModInfo : public Module
+{
+ CommandAdmin cmdadmin;
+ CommandCommands cmdcommands;
+ CommandInfo cmdinfo;
+ CommandModules cmdmodules;
+ CommandMotd cmdmotd;
+ CommandTime cmdtime;
+ CommandVersion cmdversion;
+
+ public:
+ CoreModInfo()
+ : cmdadmin(this), cmdcommands(this), cmdinfo(this), cmdmodules(this), cmdmotd(this), cmdtime(this), cmdversion(this)
+ {
+ }
+
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
+ {
+ ConfigTag* tag = ServerInstance->Config->ConfValue("admin");
+ cmdadmin.AdminName = tag->getString("name");
+ cmdadmin.AdminEmail = tag->getString("email", "null@example.com");
+ cmdadmin.AdminNick = tag->getString("nick", "admin");
+ }
+
+ Version GetVersion() CXX11_OVERRIDE
+ {
+ return Version("Provides the ADMIN, COMMANDS, INFO, MODULES, MOTD, TIME and VERSION commands", VF_VENDOR|VF_CORE);
+ }
+};
+
+MODULE_INIT(CoreModInfo)
diff --git a/src/coremods/core_info/core_info.h b/src/coremods/core_info/core_info.h
new file mode 100644
index 000000000..f5dd9e648
--- /dev/null
+++ b/src/coremods/core_info/core_info.h
@@ -0,0 +1,161 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#pragma once
+
+#include "inspircd.h"
+
+/** Handle /ADMIN.
+ */
+class CommandAdmin : public Command
+{
+ public:
+ /** Holds the admin's name, for output in
+ * the /ADMIN command.
+ */
+ std::string AdminName;
+
+ /** Holds the email address of the admin,
+ * for output in the /ADMIN command.
+ */
+ std::string AdminEmail;
+
+ /** Holds the admin's nickname, for output
+ * in the /ADMIN command
+ */
+ std::string AdminNick;
+
+ /** Constructor for admin.
+ */
+ CommandAdmin(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user);
+ RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters);
+};
+
+/** Handle /COMMANDS.
+ */
+class CommandCommands : public Command
+{
+ public:
+ /** Constructor for commands.
+ */
+ CommandCommands(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user);
+};
+
+/** Handle /INFO.
+ */
+class CommandInfo : public Command
+{
+ public:
+ /** Constructor for info.
+ */
+ CommandInfo(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user);
+ RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters);
+};
+
+/** Handle /MODULES.
+ */
+class CommandModules : public Command
+{
+ public:
+ /** Constructor for modules.
+ */
+ CommandModules(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user);
+ RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters);
+};
+
+/** Handle /MOTD.
+ */
+class CommandMotd : public Command
+{
+ public:
+ /** Constructor for motd.
+ */
+ CommandMotd(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user);
+ RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters);
+};
+
+/** Handle /TIME.
+ */
+class CommandTime : public Command
+{
+ public:
+ /** Constructor for time.
+ */
+ CommandTime(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user);
+ RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters);
+};
+
+/** Handle /VERSION.
+ */
+class CommandVersion : public Command
+{
+ public:
+ /** Constructor for version.
+ */
+ CommandVersion(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user);
+};
diff --git a/src/commands/cmd_ison.cpp b/src/coremods/core_ison.cpp
index 01d12e13b..ebb43bdf9 100644
--- a/src/commands/cmd_ison.cpp
+++ b/src/coremods/core_ison.cpp
@@ -20,13 +20,18 @@
#include "inspircd.h"
-/** Handle /ISON. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
+/** Handle /ISON.
*/
class CommandIson : public Command
{
+ /** Helper function to append a nick to an ISON reply
+ * @param user User doing the /ISON
+ * @param toadd User to append to the ISON reply
+ * @param reply Reply string to append the nick to
+ * @param pos If the reply gets too long it is sent to the user and truncated from this position
+ */
+ static bool AddNick(User* user, User* toadd, std::string& reply, const std::string::size_type pos);
+
public:
/** Constructor for ison.
*/
@@ -34,71 +39,56 @@ class CommandIson : public Command
syntax = "<nick> {nick}";
}
/** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
+ * @param parameters The parameters to the command
* @param user The user issuing the command
* @return A value from CmdResult to indicate command success or failure.
*/
CmdResult Handle(const std::vector<std::string>& parameters, User *user);
};
+bool CommandIson::AddNick(User* user, User* toadd, std::string& reply, const std::string::size_type pos)
+{
+ if ((toadd) && (toadd->registered == REG_ALL))
+ {
+ reply.append(toadd->nick).push_back(' ');
+ if (reply.length() > 450)
+ {
+ user->WriteServ(reply);
+ reply.erase(pos);
+ }
+ return true;
+ }
+ return false;
+}
+
/** Handle /ISON
*/
CmdResult CommandIson::Handle (const std::vector<std::string>& parameters, User *user)
{
- std::map<User*,User*> ison_already;
- User *u;
std::string reply = "303 " + user->nick + " :";
+ const std::string::size_type pos = reply.size();
- for (unsigned int i = 0; i < parameters.size(); i++)
+ for (std::vector<std::string>::const_iterator i = parameters.begin(); i != parameters.end(); ++i)
{
- u = ServerInstance->FindNickOnly(parameters[i]);
- if (ison_already.find(u) != ison_already.end())
- continue;
+ const std::string& targetstr = *i;
- if ((u) && (u->registered == REG_ALL))
+ User* const u = ServerInstance->FindNickOnly(targetstr);
+ if (!AddNick(user, u, reply, pos))
{
- reply.append(u->nick).append(" ");
- if (reply.length() > 450)
- {
- user->WriteServ(reply);
- reply = "303 " + user->nick + " :";
- }
- ison_already[u] = u;
- }
- else
- {
- if ((i == parameters.size() - 1) && (parameters[i].find(' ') != std::string::npos))
+ if ((i == parameters.end() - 1) && (targetstr.find(' ') != std::string::npos))
{
/* Its a space seperated list of nicks (RFC1459 says to support this)
*/
- irc::spacesepstream list(parameters[i]);
+ irc::spacesepstream list(targetstr);
std::string item;
while (list.GetToken(item))
- {
- u = ServerInstance->FindNickOnly(item);
- if (ison_already.find(u) != ison_already.end())
- continue;
-
- if ((u) && (u->registered == REG_ALL))
- {
- reply.append(u->nick).append(" ");
- if (reply.length() > 450)
- {
- user->WriteServ(reply);
- reply = "303 " + user->nick + " :";
- }
- ison_already[u] = u;
- }
- }
+ AddNick(user, ServerInstance->FindNickOnly(item), reply, pos);
}
}
}
- if (!reply.empty())
- user->WriteServ(reply);
-
+ user->WriteServ(reply);
return CMD_SUCCESS;
}
diff --git a/src/commands/cmd_list.cpp b/src/coremods/core_list.cpp
index 2f417bc04..745f019f2 100644
--- a/src/commands/cmd_list.cpp
+++ b/src/coremods/core_list.cpp
@@ -20,20 +20,26 @@
#include "inspircd.h"
-/** Handle /LIST. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
+/** Handle /LIST.
*/
class CommandList : public Command
{
+ ChanModeReference secretmode;
+ ChanModeReference privatemode;
+
public:
/** Constructor for list.
*/
- CommandList ( Module* parent) : Command(parent,"LIST", 0, 0) { Penalty = 5; }
+ CommandList(Module* parent)
+ : Command(parent,"LIST", 0, 0)
+ , secretmode(creator, "secret")
+ , privatemode(creator, "private")
+ {
+ Penalty = 5;
+ }
+
/** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
+ * @param parameters The parameters to the command
* @param user The user issuing the command
* @return A value from CmdResult to indicate command success or failure.
*/
@@ -47,7 +53,7 @@ CmdResult CommandList::Handle (const std::vector<std::string>& parameters, User
{
int minusers = 0, maxusers = 0;
- user->WriteNumeric(321, "%s Channel :Users Name",user->nick.c_str());
+ user->WriteNumeric(RPL_LISTSTART, "Channel :Users Name");
/* Work around mIRC suckyness. YOU SUCK, KHALED! */
if (parameters.size() == 1)
@@ -62,10 +68,16 @@ CmdResult CommandList::Handle (const std::vector<std::string>& parameters, User
}
}
- for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
+ const bool has_privs = user->HasPrivPermission("channels/auspex");
+ const bool match_name_topic = ((!parameters.empty()) && (!parameters[0].empty()) && (parameters[0][0] != '<') && (parameters[0][0] != '>'));
+
+ const chan_hash& chans = ServerInstance->GetChans();
+ for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); ++i)
{
+ Channel* const chan = i->second;
+
// attempt to match a glob pattern
- long users = i->second->GetUserCounter();
+ long users = chan->GetUserCounter();
bool too_few = (minusers && (users <= minusers));
bool too_many = (maxusers && (users >= maxusers));
@@ -73,30 +85,30 @@ CmdResult CommandList::Handle (const std::vector<std::string>& parameters, User
if (too_many || too_few)
continue;
- if (parameters.size() && !parameters[0].empty() && (parameters[0][0] != '<' && parameters[0][0] != '>'))
+ if (match_name_topic)
{
- if (!InspIRCd::Match(i->second->name, parameters[0]) && !InspIRCd::Match(i->second->topic, parameters[0]))
+ if (!InspIRCd::Match(chan->name, parameters[0]) && !InspIRCd::Match(chan->topic, parameters[0]))
continue;
}
// if the channel is not private/secret, OR the user is on the channel anyway
- bool n = (i->second->HasUser(user) || user->HasPrivPermission("channels/auspex"));
+ bool n = (has_privs || chan->HasUser(user));
- if (!n && i->second->IsModeSet('p'))
+ if ((!n) && (chan->IsModeSet(privatemode)))
{
/* Channel is +p and user is outside/not privileged */
- user->WriteNumeric(322, "%s * %ld :",user->nick.c_str(), users);
+ user->WriteNumeric(RPL_LIST, "* %ld :", users);
}
else
{
- if (n || !i->second->IsModeSet('s'))
+ if ((n) || (!chan->IsModeSet(secretmode)))
{
/* User is in the channel/privileged, channel is not +s */
- user->WriteNumeric(322, "%s %s %ld :[+%s] %s",user->nick.c_str(),i->second->name.c_str(),users,i->second->ChanModes(n),i->second->topic.c_str());
+ user->WriteNumeric(RPL_LIST, "%s %ld :[+%s] %s", chan->name.c_str(), users, chan->ChanModes(n), chan->topic.c_str());
}
}
}
- user->WriteNumeric(323, "%s :End of channel list.",user->nick.c_str());
+ user->WriteNumeric(RPL_LISTEND, ":End of channel list.");
return CMD_SUCCESS;
}
diff --git a/src/coremods/core_loadmodule.cpp b/src/coremods/core_loadmodule.cpp
new file mode 100644
index 000000000..1d49d89d0
--- /dev/null
+++ b/src/coremods/core_loadmodule.cpp
@@ -0,0 +1,126 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+
+/** Handle /LOADMODULE.
+ */
+class CommandLoadmodule : public Command
+{
+ public:
+ /** Constructor for loadmodule.
+ */
+ CommandLoadmodule ( Module* parent) : Command(parent,"LOADMODULE",1,1) { flags_needed='o'; syntax = "<modulename>"; }
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User *user);
+};
+
+/** Handle /LOADMODULE
+ */
+CmdResult CommandLoadmodule::Handle (const std::vector<std::string>& parameters, User *user)
+{
+ if (ServerInstance->Modules->Load(parameters[0]))
+ {
+ ServerInstance->SNO->WriteGlobalSno('a', "NEW MODULE: %s loaded %s",user->nick.c_str(), parameters[0].c_str());
+ user->WriteNumeric(RPL_LOADEDMODULE, "%s :Module successfully loaded.", parameters[0].c_str());
+ return CMD_SUCCESS;
+ }
+ else
+ {
+ user->WriteNumeric(ERR_CANTLOADMODULE, "%s :%s", parameters[0].c_str(), ServerInstance->Modules->LastError().c_str());
+ return CMD_FAILURE;
+ }
+}
+
+/** Handle /UNLOADMODULE.
+ */
+class CommandUnloadmodule : public Command
+{
+ public:
+ /** Constructor for unloadmodule.
+ */
+ CommandUnloadmodule(Module* parent)
+ : Command(parent,"UNLOADMODULE", 1)
+ {
+ flags_needed = 'o';
+ syntax = "<modulename>";
+ }
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user);
+};
+
+CmdResult CommandUnloadmodule::Handle(const std::vector<std::string>& parameters, User* user)
+{
+ if (!ServerInstance->Config->ConfValue("security")->getBool("allowcoreunload") &&
+ InspIRCd::Match(parameters[0], "core_*.so", ascii_case_insensitive_map))
+ {
+ user->WriteNumeric(ERR_CANTUNLOADMODULE, "%s :You cannot unload core commands!", parameters[0].c_str());
+ return CMD_FAILURE;
+ }
+
+ Module* m = ServerInstance->Modules->Find(parameters[0]);
+ if (m == creator)
+ {
+ user->WriteNumeric(ERR_CANTUNLOADMODULE, "%s :You cannot unload module loading commands!", parameters[0].c_str());
+ return CMD_FAILURE;
+ }
+
+ if (m && ServerInstance->Modules->Unload(m))
+ {
+ ServerInstance->SNO->WriteGlobalSno('a', "MODULE UNLOADED: %s unloaded %s", user->nick.c_str(), parameters[0].c_str());
+ user->WriteNumeric(RPL_UNLOADEDMODULE, "%s :Module successfully unloaded.", parameters[0].c_str());
+ }
+ else
+ {
+ user->WriteNumeric(ERR_CANTUNLOADMODULE, "%s :%s", parameters[0].c_str(),
+ m ? ServerInstance->Modules->LastError().c_str() : "No such module");
+ return CMD_FAILURE;
+ }
+
+ return CMD_SUCCESS;
+}
+
+class CoreModLoadModule : public Module
+{
+ CommandLoadmodule cmdloadmod;
+ CommandUnloadmodule cmdunloadmod;
+
+ public:
+ CoreModLoadModule()
+ : cmdloadmod(this), cmdunloadmod(this)
+ {
+ }
+
+ Version GetVersion()
+ {
+ return Version("Provides the LOADMODULE and UNLOADMODULE commands", VF_VENDOR|VF_CORE);
+ }
+};
+
+MODULE_INIT(CoreModLoadModule)
diff --git a/src/commands/cmd_lusers.cpp b/src/coremods/core_lusers.cpp
index 91a718090..2529ca42b 100644
--- a/src/commands/cmd_lusers.cpp
+++ b/src/coremods/core_lusers.cpp
@@ -26,10 +26,10 @@ struct LusersCounters
unsigned int max_global;
unsigned int invisible;
- LusersCounters()
+ LusersCounters(unsigned int inv)
: max_local(ServerInstance->Users->LocalUserCount())
, max_global(ServerInstance->Users->RegisteredUserCount())
- , invisible(ServerInstance->Users->ModeCount('i'))
+ , invisible(inv)
{
}
@@ -45,10 +45,7 @@ struct LusersCounters
}
};
-/** Handle /LUSERS. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
+/** Handle /LUSERS.
*/
class CommandLusers : public Command
{
@@ -60,8 +57,7 @@ class CommandLusers : public Command
: Command(parent,"LUSERS",0,0), counters(Counters)
{ }
/** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
+ * @param parameters The parameters to the command
* @param user The user issuing the command
* @return A value from CmdResult to indicate command success or failure.
*/
@@ -73,11 +69,11 @@ class CommandLusers : public Command
CmdResult CommandLusers::Handle (const std::vector<std::string>&, User *user)
{
unsigned int n_users = ServerInstance->Users->RegisteredUserCount();
- ProtoServerList serverlist;
+ ProtocolInterface::ServerList serverlist;
ServerInstance->PI->GetServerList(serverlist);
unsigned int n_serv = serverlist.size();
unsigned int n_local_servs = 0;
- for(ProtoServerList::iterator i = serverlist.begin(); i != serverlist.end(); ++i)
+ for (ProtocolInterface::ServerList::const_iterator i = serverlist.begin(); i != serverlist.end(); ++i)
{
if (i->parentname == ServerInstance->Config->ServerName)
n_local_servs++;
@@ -88,19 +84,19 @@ CmdResult CommandLusers::Handle (const std::vector<std::string>&, User *user)
counters.UpdateMaxUsers();
- user->WriteNumeric(251, "%s :There are %d users and %d invisible on %d servers",user->nick.c_str(),
+ user->WriteNumeric(RPL_LUSERCLIENT, ":There are %d users and %d invisible on %d servers",
n_users - counters.invisible, counters.invisible, n_serv);
if (ServerInstance->Users->OperCount())
- user->WriteNumeric(252, "%s %d :operator(s) online",user->nick.c_str(),ServerInstance->Users->OperCount());
+ user->WriteNumeric(RPL_LUSEROP, "%d :operator(s) online", ServerInstance->Users->OperCount());
if (ServerInstance->Users->UnregisteredUserCount())
- user->WriteNumeric(253, "%s %d :unknown connections",user->nick.c_str(),ServerInstance->Users->UnregisteredUserCount());
+ user->WriteNumeric(RPL_LUSERUNKNOWN, "%d :unknown connections", ServerInstance->Users->UnregisteredUserCount());
- user->WriteNumeric(254, "%s %ld :channels formed",user->nick.c_str(),ServerInstance->ChannelCount());
- user->WriteNumeric(255, "%s :I have %d clients and %d servers",user->nick.c_str(),ServerInstance->Users->LocalUserCount(),n_local_servs);
- user->WriteNumeric(265, "%s :Current Local Users: %d Max: %d", user->nick.c_str(), ServerInstance->Users->LocalUserCount(), counters.max_local);
- user->WriteNumeric(266, "%s :Current Global Users: %d Max: %d", user->nick.c_str(), n_users, counters.max_global);
+ user->WriteNumeric(RPL_LUSERCHANNELS, "%lu :channels formed", (unsigned long)ServerInstance->GetChans().size());
+ user->WriteNumeric(RPL_LUSERME, ":I have %d clients and %d servers", ServerInstance->Users->LocalUserCount(),n_local_servs);
+ user->WriteNumeric(RPL_LOCALUSERS, ":Current local users: %d Max: %d", ServerInstance->Users->LocalUserCount(), counters.max_local);
+ user->WriteNumeric(RPL_GLOBALUSERS, ":Current global users: %d Max: %d", n_users, counters.max_global);
return CMD_SUCCESS;
}
@@ -110,11 +106,11 @@ class InvisibleWatcher : public ModeWatcher
unsigned int& invisible;
public:
InvisibleWatcher(Module* mod, unsigned int& Invisible)
- : ModeWatcher(mod, 'i', MODETYPE_USER), invisible(Invisible)
+ : ModeWatcher(mod, "invisible", MODETYPE_USER), invisible(Invisible)
{
}
- void AfterMode(User* source, User* dest, Channel* channel, const std::string& parameter, bool adding, ModeType type)
+ void AfterMode(User* source, User* dest, Channel* channel, const std::string& parameter, bool adding)
{
if (dest->registered != REG_ALL)
return;
@@ -128,42 +124,46 @@ public:
class ModuleLusers : public Module
{
+ UserModeReference invisiblemode;
LusersCounters counters;
CommandLusers cmd;
InvisibleWatcher mw;
- public:
- ModuleLusers()
- : cmd(this, counters), mw(this, counters.invisible)
+ unsigned int CountInvisible()
{
+ unsigned int c = 0;
+ const user_hash& users = ServerInstance->Users->GetUsers();
+ for (user_hash::const_iterator i = users.begin(); i != users.end(); ++i)
+ {
+ User* u = i->second;
+ if (u->IsModeSet(invisiblemode))
+ c++;
+ }
+ return c;
}
- void init()
+ public:
+ ModuleLusers()
+ : invisiblemode(this, "invisible")
+ , counters(CountInvisible())
+ , cmd(this, counters)
+ , mw(this, counters.invisible)
{
- ServerInstance->Modules->AddService(cmd);
- Implementation events[] = { I_OnPostConnect, I_OnUserQuit };
- ServerInstance->Modules->Attach(events, this, sizeof(events)/sizeof(Implementation));
- ServerInstance->Modes->AddModeWatcher(&mw);
}
void OnPostConnect(User* user)
{
counters.UpdateMaxUsers();
- if (user->IsModeSet('i'))
+ if (user->IsModeSet(invisiblemode))
counters.invisible++;
}
void OnUserQuit(User* user, const std::string& message, const std::string& oper_message)
{
- if (user->IsModeSet('i'))
+ if (user->IsModeSet(invisiblemode))
counters.invisible--;
}
- ~ModuleLusers()
- {
- ServerInstance->Modes->DelModeWatcher(&mw);
- }
-
Version GetVersion()
{
return Version("LUSERS", VF_VENDOR | VF_CORE);
diff --git a/src/commands/cmd_die.cpp b/src/coremods/core_oper/cmd_die.cpp
index 1d6640213..5a9415915 100644
--- a/src/commands/cmd_die.cpp
+++ b/src/coremods/core_oper/cmd_die.cpp
@@ -19,38 +19,25 @@
#include "inspircd.h"
+#include "exitcodes.h"
+#include "core_oper.h"
-/** Handle /DIE. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandDie : public Command
+CommandDie::CommandDie(Module* parent)
+ : Command(parent, "DIE", 1)
{
- public:
- /** Constructor for die.
- */
- CommandDie ( Module* parent) : Command(parent,"DIE",1) { flags_needed = 'o'; syntax = "<password>"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
-
-#include "exitcodes.h"
+ flags_needed = 'o';
+ syntax = "<password>";
+}
/** Handle /DIE
*/
CmdResult CommandDie::Handle (const std::vector<std::string>& parameters, User *user)
{
- if (!ServerInstance->PassCompare(user, ServerInstance->Config->diepass, parameters[0].c_str(), ServerInstance->Config->powerhash))
+ if (DieRestart::CheckPass(user, parameters[0], "diepass"))
{
{
std::string diebuf = "*** DIE command from " + user->GetFullHost() + ". Terminating.";
- ServerInstance->Logs->Log("COMMAND",SPARSE, diebuf);
+ ServerInstance->Logs->Log("COMMAND", LOG_SPARSE, diebuf);
ServerInstance->SendError(diebuf);
}
@@ -58,11 +45,9 @@ CmdResult CommandDie::Handle (const std::vector<std::string>& parameters, User *
}
else
{
- ServerInstance->Logs->Log("COMMAND",SPARSE, "Failed /DIE command from %s", user->GetFullRealHost().c_str());
+ ServerInstance->Logs->Log("COMMAND", LOG_SPARSE, "Failed /DIE command from %s", user->GetFullRealHost().c_str());
ServerInstance->SNO->WriteGlobalSno('a', "Failed DIE Command from %s.", user->GetFullRealHost().c_str());
return CMD_FAILURE;
}
return CMD_SUCCESS;
}
-
-COMMAND_INIT(CommandDie)
diff --git a/src/commands/cmd_kill.cpp b/src/coremods/core_oper/cmd_kill.cpp
index 17c8a76a0..b60885c64 100644
--- a/src/commands/cmd_kill.cpp
+++ b/src/coremods/core_oper/cmd_kill.cpp
@@ -20,45 +20,28 @@
#include "inspircd.h"
+#include "core_oper.h"
-/** Handle /KILL. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandKill : public Command
+CommandKill::CommandKill(Module* parent)
+ : Command(parent, "KILL", 2, 2)
{
- public:
- /** Constructor for kill.
- */
- CommandKill ( Module* parent) : Command(parent,"KILL",2,2) {
- flags_needed = 'o';
- syntax = "<nickname> <reason>";
- TRANSLATE3(TR_NICK, TR_TEXT, TR_END);
- }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
- RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
- {
- // local kills of remote users are routed via the OnRemoteKill hook
- if (IS_LOCAL(user))
- return ROUTE_LOCALONLY;
- return ROUTE_BROADCAST;
- }
-};
+ flags_needed = 'o';
+ syntax = "<nickname> <reason>";
+ TRANSLATE2(TR_CUSTOM, TR_CUSTOM);
+}
+
/** Handle /KILL
*/
CmdResult CommandKill::Handle (const std::vector<std::string>& parameters, User *user)
{
/* Allow comma seperated lists of users for /KILL (thanks w00t) */
- if (ServerInstance->Parser->LoopCall(user, this, parameters, 0))
- return CMD_SUCCESS;
+ if (CommandParser::LoopCall(user, this, parameters, 0))
+ {
+ // If we got a colon delimited list of nicks then the handler ran for each nick,
+ // and KILL commands were broadcast for remote targets.
+ return CMD_FAILURE;
+ }
User *u = ServerInstance->FindNick(parameters[0]);
if ((u) && (!IS_SERVER(u)))
@@ -71,7 +54,6 @@ CmdResult CommandKill::Handle (const std::vector<std::string>& parameters, User
* just gets processed and passed on, otherwise, if they are local, it gets prefixed. Makes sense :-) -- w00t
*/
- std::string killreason;
if (IS_LOCAL(user))
{
/*
@@ -111,8 +93,9 @@ CmdResult CommandKill::Handle (const std::vector<std::string>& parameters, User
if (!IS_LOCAL(u))
{
// remote kill
- ServerInstance->SNO->WriteToSnoMask('K', "Remote kill by %s: %s (%s)", user->nick.c_str(), u->GetFullRealHost().c_str(), parameters[1].c_str());
- FOREACH_MOD(I_OnRemoteKill, OnRemoteKill(user, u, killreason, killreason));
+ if (!user->server->IsULine())
+ ServerInstance->SNO->WriteToSnoMask('K', "Remote kill by %s: %s (%s)", user->nick.c_str(), u->GetFullRealHost().c_str(), parameters[1].c_str());
+ this->lastuuid = u->uuid;
}
else
{
@@ -121,23 +104,24 @@ CmdResult CommandKill::Handle (const std::vector<std::string>& parameters, User
* XXX - this isn't entirely correct, servers A - B - C, oper on A, client on C. Oper kills client, A and B will get remote kill
* snotices, C will get a local kill snotice. this isn't accurate, and needs fixing at some stage. -- w00t
*/
- if (IS_LOCAL(user))
- ServerInstance->SNO->WriteGlobalSno('k',"Local Kill by %s: %s (%s)", user->nick.c_str(), u->GetFullRealHost().c_str(), parameters[1].c_str());
- else
- ServerInstance->SNO->WriteToSnoMask('k',"Local Kill by %s: %s (%s)", user->nick.c_str(), u->GetFullRealHost().c_str(), parameters[1].c_str());
- ServerInstance->Logs->Log("KILL",DEFAULT,"LOCAL KILL: %s :%s!%s!%s (%s)", u->nick.c_str(), ServerInstance->Config->ServerName.c_str(), user->dhost.c_str(), user->nick.c_str(), parameters[1].c_str());
- /* Bug #419, make sure this message can only occur once even in the case of multiple KILL messages crossing the network, and change to show
- * hidekillsserver as source if possible
- */
- if (!u->quitting)
+ if (!user->server->IsULine())
{
- u->Write(":%s KILL %s :%s!%s!%s (%s)", ServerInstance->Config->HideKillsServer.empty() ? user->GetFullHost().c_str() : ServerInstance->Config->HideKillsServer.c_str(),
- u->nick.c_str(),
- ServerInstance->Config->ServerName.c_str(),
- user->dhost.c_str(),
- ServerInstance->Config->HideKillsServer.empty() ? user->nick.c_str() : ServerInstance->Config->HideKillsServer.c_str(),
- parameters[1].c_str());
+ if (IS_LOCAL(user))
+ ServerInstance->SNO->WriteGlobalSno('k',"Local Kill by %s: %s (%s)", user->nick.c_str(), u->GetFullRealHost().c_str(), parameters[1].c_str());
+ else
+ ServerInstance->SNO->WriteToSnoMask('k',"Local Kill by %s: %s (%s)", user->nick.c_str(), u->GetFullRealHost().c_str(), parameters[1].c_str());
}
+
+ ServerInstance->Logs->Log("KILL", LOG_DEFAULT, "LOCAL KILL: %s :%s!%s!%s (%s)", u->nick.c_str(), ServerInstance->Config->ServerName.c_str(), user->dhost.c_str(), user->nick.c_str(), parameters[1].c_str());
+
+ u->Write(":%s KILL %s :%s!%s!%s (%s)", ServerInstance->Config->HideKillsServer.empty() ? user->GetFullHost().c_str() : ServerInstance->Config->HideKillsServer.c_str(),
+ u->nick.c_str(),
+ ServerInstance->Config->ServerName.c_str(),
+ user->dhost.c_str(),
+ ServerInstance->Config->HideKillsServer.empty() ? user->nick.c_str() : ServerInstance->Config->HideKillsServer.c_str(),
+ parameters[1].c_str());
+
+ this->lastuuid.clear();
}
// send the quit out
@@ -145,12 +129,28 @@ CmdResult CommandKill::Handle (const std::vector<std::string>& parameters, User
}
else
{
- user->WriteServ( "401 %s %s :No such nick/channel", user->nick.c_str(), parameters[0].c_str());
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", parameters[0].c_str());
return CMD_FAILURE;
}
return CMD_SUCCESS;
}
+RouteDescriptor CommandKill::GetRouting(User* user, const std::vector<std::string>& parameters)
+{
+ // FindNick() doesn't work here because we quit the target user in Handle() which
+ // removes it from the nicklist, so we check lastuuid: if it's empty then this KILL
+ // was for a local user, otherwise it contains the uuid of the user who was killed.
+ if (lastuuid.empty())
+ return ROUTE_LOCALONLY;
+ return ROUTE_BROADCAST;
+}
+
-COMMAND_INIT(CommandKill)
+void CommandKill::EncodeParameter(std::string& param, int index)
+{
+ // Manually translate the nick -> uuid (see above), and also the reason (params[1])
+ // because we decorate it if the oper is local and want remote servers to see the
+ // decorated reason not the original.
+ param = ((index == 0) ? lastuuid : killreason);
+}
diff --git a/src/coremods/core_oper/cmd_oper.cpp b/src/coremods/core_oper/cmd_oper.cpp
new file mode 100644
index 000000000..e4ba69549
--- /dev/null
+++ b/src/coremods/core_oper/cmd_oper.cpp
@@ -0,0 +1,72 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
+ * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "core_oper.h"
+
+CommandOper::CommandOper(Module* parent)
+ : SplitCommand(parent, "OPER", 2, 2)
+{
+ syntax = "<username> <password>";
+}
+
+CmdResult CommandOper::HandleLocal(const std::vector<std::string>& parameters, LocalUser *user)
+{
+ bool match_login = false;
+ bool match_pass = false;
+ bool match_hosts = false;
+
+ const std::string userHost = user->ident + "@" + user->host;
+ const std::string userIP = user->ident + "@" + user->GetIPString();
+
+ ServerConfig::OperIndex::const_iterator i = ServerInstance->Config->oper_blocks.find(parameters[0]);
+ if (i != ServerInstance->Config->oper_blocks.end())
+ {
+ OperInfo* ifo = i->second;
+ ConfigTag* tag = ifo->oper_block;
+ match_login = true;
+ match_pass = ServerInstance->PassCompare(user, tag->getString("password"), parameters[1], tag->getString("hash"));
+ match_hosts = InspIRCd::MatchMask(tag->getString("host"), userHost, userIP);
+
+ if (match_pass && match_hosts)
+ {
+ /* found this oper's opertype */
+ user->Oper(ifo);
+ return CMD_SUCCESS;
+ }
+ }
+
+ std::string fields;
+ if (!match_login)
+ fields.append("login ");
+ if (!match_pass)
+ fields.append("password ");
+ if (!match_hosts)
+ fields.append("hosts");
+
+ // tell them they suck, and lag them up to help prevent brute-force attacks
+ user->WriteNumeric(ERR_NOOPERHOST, ":Invalid oper credentials");
+ user->CommandFloodPenalty += 10000;
+
+ ServerInstance->SNO->WriteGlobalSno('o', "WARNING! Failed oper attempt by %s using login '%s': The following fields do not match: %s", user->GetFullRealHost().c_str(), parameters[0].c_str(), fields.c_str());
+ ServerInstance->Logs->Log("OPER", LOG_DEFAULT, "OPER: Failed oper attempt by %s using login '%s': The following fields did not match: %s", user->GetFullRealHost().c_str(), parameters[0].c_str(), fields.c_str());
+ return CMD_FAILURE;
+}
diff --git a/src/commands/cmd_rehash.cpp b/src/coremods/core_oper/cmd_rehash.cpp
index abf0b7876..48dfa6fb1 100644
--- a/src/commands/cmd_rehash.cpp
+++ b/src/coremods/core_oper/cmd_rehash.cpp
@@ -20,32 +20,21 @@
#include "inspircd.h"
+#include "core_oper.h"
-/** Handle /REHASH. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandRehash : public Command
+CommandRehash::CommandRehash(Module* parent)
+ : Command(parent, "REHASH", 0)
{
- public:
- /** Constructor for rehash.
- */
- CommandRehash ( Module* parent) : Command(parent,"REHASH",0) { flags_needed = 'o'; Penalty = 2; syntax = "[<servermask>]"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
+ flags_needed = 'o';
+ Penalty = 2;
+ syntax = "[<servermask>]";
+}
CmdResult CommandRehash::Handle (const std::vector<std::string>& parameters, User *user)
{
std::string param = parameters.size() ? parameters[0] : "";
- FOREACH_MOD(I_OnPreRehash,OnPreRehash(user, param));
+ FOREACH_MOD(OnPreRehash, (user, param));
if (param.empty())
{
@@ -68,32 +57,25 @@ CmdResult CommandRehash::Handle (const std::vector<std::string>& parameters, Use
if (param[0] == '-')
param = param.substr(1);
- FOREACH_MOD(I_OnModuleRehash,OnModuleRehash(user, param));
+ FOREACH_MOD(OnModuleRehash, (user, param));
return CMD_SUCCESS;
}
// Rehash for me. Try to start the rehash thread
if (!ServerInstance->ConfigThread)
{
- std::string m = user->nick + " is rehashing config file " + ServerConfig::CleanFilename(ServerInstance->ConfigFileName.c_str()) + " on " + ServerInstance->Config->ServerName;
+ std::string m = user->nick + " is rehashing config file " + FileSystem::GetFileName(ServerInstance->ConfigFileName) + " on " + ServerInstance->Config->ServerName;
ServerInstance->SNO->WriteGlobalSno('a', m);
if (IS_LOCAL(user))
- user->WriteNumeric(RPL_REHASHING, "%s %s :Rehashing",
- user->nick.c_str(),ServerConfig::CleanFilename(ServerInstance->ConfigFileName.c_str()));
+ user->WriteNumeric(RPL_REHASHING, "%s :Rehashing", FileSystem::GetFileName(ServerInstance->ConfigFileName).c_str());
else
- ServerInstance->PI->SendUserNotice(user, std::string("*** Rehashing server ") +
- ServerConfig::CleanFilename(ServerInstance->ConfigFileName.c_str()));
+ ServerInstance->PI->SendUserNotice(user, "*** Rehashing server " + FileSystem::GetFileName(ServerInstance->ConfigFileName));
/* Don't do anything with the logs here -- logs are restarted
* after the config thread has completed.
*/
- ServerInstance->RehashUsersAndChans();
- FOREACH_MOD(I_OnGarbageCollect, OnGarbageCollect());
-
-
- ServerInstance->ConfigThread = new ConfigReaderThread(user->uuid);
- ServerInstance->Threads->Start(ServerInstance->ConfigThread);
+ ServerInstance->Rehash(user->uuid);
}
else
{
@@ -102,7 +84,7 @@ CmdResult CommandRehash::Handle (const std::vector<std::string>& parameters, Use
* XXX, todo: we should find some way to kill runaway rehashes that are blocking, this is a major problem for unrealircd users
*/
if (IS_LOCAL(user))
- user->WriteServ("NOTICE %s :*** Could not rehash: A rehash is already in progress.", user->nick.c_str());
+ user->WriteNotice("*** Could not rehash: A rehash is already in progress.");
else
ServerInstance->PI->SendUserNotice(user, "*** Could not rehash: A rehash is already in progress.");
}
@@ -110,6 +92,3 @@ CmdResult CommandRehash::Handle (const std::vector<std::string>& parameters, Use
// Always return success so spanningtree forwards an incoming REHASH even if we failed
return CMD_SUCCESS;
}
-
-
-COMMAND_INIT(CommandRehash)
diff --git a/src/commands/cmd_restart.cpp b/src/coremods/core_oper/cmd_restart.cpp
index bdbcfed35..4fad752a2 100644
--- a/src/commands/cmd_restart.cpp
+++ b/src/coremods/core_oper/cmd_restart.cpp
@@ -19,28 +19,19 @@
#include "inspircd.h"
+#include "core_oper.h"
-/** Handle /RESTART
- */
-class CommandRestart : public Command
+CommandRestart::CommandRestart(Module* parent)
+ : Command(parent, "RESTART", 1, 1)
{
- public:
- /** Constructor for restart.
- */
- CommandRestart(Module* parent) : Command(parent,"RESTART",1,1) { flags_needed = 'o'; syntax = "<password>"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
+ flags_needed = 'o';
+ syntax = "<password>";
+}
CmdResult CommandRestart::Handle (const std::vector<std::string>& parameters, User *user)
{
- ServerInstance->Logs->Log("COMMAND",DEFAULT,"Restart: %s",user->nick.c_str());
- if (!ServerInstance->PassCompare(user, ServerInstance->Config->restartpass, parameters[0].c_str(), ServerInstance->Config->powerhash))
+ ServerInstance->Logs->Log("COMMAND", LOG_DEFAULT, "Restart: %s",user->nick.c_str());
+ if (DieRestart::CheckPass(user, parameters[0], "restartpass"))
{
ServerInstance->SNO->WriteGlobalSno('a', "RESTART command from %s, restarting server.", user->GetFullRealHost().c_str());
@@ -71,6 +62,3 @@ CmdResult CommandRestart::Handle (const std::vector<std::string>& parameters, Us
}
return CMD_FAILURE;
}
-
-
-COMMAND_INIT(CommandRestart)
diff --git a/src/coremods/core_oper/core_oper.cpp b/src/coremods/core_oper/core_oper.cpp
new file mode 100644
index 000000000..0fc82df8f
--- /dev/null
+++ b/src/coremods/core_oper/core_oper.cpp
@@ -0,0 +1,55 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "core_oper.h"
+
+namespace DieRestart
+{
+ bool CheckPass(User* user, const std::string& inputpass, const char* confentry)
+ {
+ ConfigTag* tag = ServerInstance->Config->ConfValue("power");
+ // The hash method for *BOTH* the die and restart passwords
+ const std::string hash = tag->getString("hash");
+ const std::string correctpass = tag->getString(confentry);
+ return ServerInstance->PassCompare(user, correctpass, inputpass, hash);
+ }
+}
+
+class CoreModOper : public Module
+{
+ CommandDie cmddie;
+ CommandKill cmdkill;
+ CommandOper cmdoper;
+ CommandRehash cmdrehash;
+ CommandRestart cmdrestart;
+
+ public:
+ CoreModOper()
+ : cmddie(this), cmdkill(this), cmdoper(this), cmdrehash(this), cmdrestart(this)
+ {
+ }
+
+ Version GetVersion() CXX11_OVERRIDE
+ {
+ return Version("Provides the DIE, KILL, OPER, REHASH, and RESTART commands", VF_VENDOR|VF_CORE);
+ }
+};
+
+MODULE_INIT(CoreModOper)
diff --git a/src/coremods/core_oper/core_oper.h b/src/coremods/core_oper/core_oper.h
new file mode 100644
index 000000000..3b3dfd4b2
--- /dev/null
+++ b/src/coremods/core_oper/core_oper.h
@@ -0,0 +1,124 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#pragma once
+
+#include "inspircd.h"
+
+namespace DieRestart
+{
+ /** Checks a die or restart password
+ * @param user The user executing /DIE or /RESTART
+ * @param inputpass The password given by the user
+ * @param confkey The name of the key in the power tag containing the correct password
+ * @return True if the given password was correct, false if it was not
+ */
+ bool CheckPass(User* user, const std::string& inputpass, const char* confkey);
+}
+
+/** Handle /DIE.
+ */
+class CommandDie : public Command
+{
+ public:
+ /** Constructor for die.
+ */
+ CommandDie(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user);
+};
+
+/** Handle /KILL.
+ */
+class CommandKill : public Command
+{
+ std::string lastuuid;
+ std::string killreason;
+
+ public:
+ /** Constructor for kill.
+ */
+ CommandKill(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user);
+ RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters);
+
+ void EncodeParameter(std::string& param, int index);
+};
+
+/** Handle /OPER.
+ */
+class CommandOper : public SplitCommand
+{
+ public:
+ /** Constructor for oper.
+ */
+ CommandOper(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult HandleLocal(const std::vector<std::string>& parameters, LocalUser* user);
+};
+
+/** Handle /REHASH.
+ */
+class CommandRehash : public Command
+{
+ public:
+ /** Constructor for rehash.
+ */
+ CommandRehash(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User *user);
+};
+
+/** Handle /RESTART
+ */
+class CommandRestart : public Command
+{
+ public:
+ /** Constructor for restart.
+ */
+ CommandRestart(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user);
+};
diff --git a/src/coremods/core_privmsg.cpp b/src/coremods/core_privmsg.cpp
new file mode 100644
index 000000000..34527027c
--- /dev/null
+++ b/src/coremods/core_privmsg.cpp
@@ -0,0 +1,296 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc>
+ * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+
+namespace
+{
+ const char* MessageTypeString[] = { "PRIVMSG", "NOTICE" };
+}
+
+class MessageCommandBase : public Command
+{
+ ChanModeReference moderatedmode;
+ ChanModeReference noextmsgmode;
+
+ /** Send a PRIVMSG or NOTICE message to all local users from the given user
+ * @param user User sending the message
+ * @param msg The message to send
+ * @param mt Type of the message (MSG_PRIVMSG or MSG_NOTICE)
+ */
+ static void SendAll(User* user, const std::string& msg, MessageType mt);
+
+ public:
+ MessageCommandBase(Module* parent, MessageType mt)
+ : Command(parent, MessageTypeString[mt], 2, 2)
+ , moderatedmode(parent, "moderated")
+ , noextmsgmode(parent, "noextmsg")
+ {
+ syntax = "<target>{,<target>} <message>";
+ }
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult HandleMessage(const std::vector<std::string>& parameters, User* user, MessageType mt);
+
+ RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
+ {
+ if (IS_LOCAL(user))
+ // This is handled by the OnUserMessage hook to split the LoopCall pieces
+ return ROUTE_LOCALONLY;
+ else
+ return ROUTE_MESSAGE(parameters[0]);
+ }
+};
+
+void MessageCommandBase::SendAll(User* user, const std::string& msg, MessageType mt)
+{
+ const std::string message = ":" + user->GetFullHost() + " " + MessageTypeString[mt] + " $* :" + msg;
+ const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers();
+ for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i)
+ {
+ if ((*i)->registered == REG_ALL)
+ (*i)->Write(message);
+ }
+}
+
+CmdResult MessageCommandBase::HandleMessage(const std::vector<std::string>& parameters, User* user, MessageType mt)
+{
+ User *dest;
+ Channel *chan;
+ CUList except_list;
+
+ LocalUser* localuser = IS_LOCAL(user);
+ if (localuser)
+ localuser->idle_lastmsg = ServerInstance->Time();
+
+ if (CommandParser::LoopCall(user, this, parameters, 0))
+ return CMD_SUCCESS;
+
+ if (parameters[0][0] == '$')
+ {
+ if (!user->HasPrivPermission("users/mass-message"))
+ return CMD_SUCCESS;
+
+ ModResult MOD_RESULT;
+ std::string temp = parameters[1];
+ FIRST_MOD_RESULT(OnUserPreMessage, MOD_RESULT, (user, (void*)parameters[0].c_str(), TYPE_SERVER, temp, 0, except_list, mt));
+ if (MOD_RESULT == MOD_RES_DENY)
+ return CMD_FAILURE;
+
+ const char* text = temp.c_str();
+ const char* servermask = (parameters[0].c_str()) + 1;
+
+ FOREACH_MOD(OnText, (user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, except_list));
+ if (InspIRCd::Match(ServerInstance->Config->ServerName, servermask, NULL))
+ {
+ SendAll(user, text, mt);
+ }
+ FOREACH_MOD(OnUserMessage, (user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, except_list, mt));
+ return CMD_SUCCESS;
+ }
+ char status = 0;
+ const char* target = parameters[0].c_str();
+
+ if (ServerInstance->Modes->FindPrefix(*target))
+ {
+ status = *target;
+ target++;
+ }
+ if (*target == '#')
+ {
+ chan = ServerInstance->FindChan(target);
+
+ except_list.insert(user);
+
+ if (chan)
+ {
+ if (localuser && chan->GetPrefixValue(user) < VOICE_VALUE)
+ {
+ if (chan->IsModeSet(noextmsgmode) && !chan->HasUser(user))
+ {
+ user->WriteNumeric(ERR_CANNOTSENDTOCHAN, "%s :Cannot send to channel (no external messages)", chan->name.c_str());
+ return CMD_FAILURE;
+ }
+
+ if (chan->IsModeSet(moderatedmode))
+ {
+ user->WriteNumeric(ERR_CANNOTSENDTOCHAN, "%s :Cannot send to channel (+m)", chan->name.c_str());
+ return CMD_FAILURE;
+ }
+
+ if (ServerInstance->Config->RestrictBannedUsers)
+ {
+ if (chan->IsBanned(user))
+ {
+ user->WriteNumeric(ERR_CANNOTSENDTOCHAN, "%s :Cannot send to channel (you're banned)", chan->name.c_str());
+ return CMD_FAILURE;
+ }
+ }
+ }
+ ModResult MOD_RESULT;
+
+ std::string temp = parameters[1];
+ FIRST_MOD_RESULT(OnUserPreMessage, MOD_RESULT, (user, chan, TYPE_CHANNEL, temp, status, except_list, mt));
+ if (MOD_RESULT == MOD_RES_DENY)
+ return CMD_FAILURE;
+
+ const char* text = temp.c_str();
+
+ /* Check again, a module may have zapped the input string */
+ if (temp.empty())
+ {
+ user->WriteNumeric(ERR_NOTEXTTOSEND, ":No text to send");
+ return CMD_FAILURE;
+ }
+
+ FOREACH_MOD(OnText, (user,chan,TYPE_CHANNEL,text,status,except_list));
+
+ if (status)
+ {
+ if (ServerInstance->Config->UndernetMsgPrefix)
+ {
+ chan->WriteAllExcept(user, false, status, except_list, "%s %c%s :%c %s", MessageTypeString[mt], status, chan->name.c_str(), status, text);
+ }
+ else
+ {
+ chan->WriteAllExcept(user, false, status, except_list, "%s %c%s :%s", MessageTypeString[mt], status, chan->name.c_str(), text);
+ }
+ }
+ else
+ {
+ chan->WriteAllExcept(user, false, status, except_list, "%s %s :%s", MessageTypeString[mt], chan->name.c_str(), text);
+ }
+
+ FOREACH_MOD(OnUserMessage, (user,chan, TYPE_CHANNEL, text, status, except_list, mt));
+ }
+ else
+ {
+ /* no such nick/channel */
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", target);
+ return CMD_FAILURE;
+ }
+ return CMD_SUCCESS;
+ }
+
+ const char* destnick = parameters[0].c_str();
+
+ if (localuser)
+ {
+ const char* targetserver = strchr(destnick, '@');
+
+ if (targetserver)
+ {
+ std::string nickonly;
+
+ nickonly.assign(destnick, 0, targetserver - destnick);
+ dest = ServerInstance->FindNickOnly(nickonly);
+ if (dest && strcasecmp(dest->server->GetName().c_str(), targetserver + 1))
+ {
+ /* Incorrect server for user */
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", parameters[0].c_str());
+ return CMD_FAILURE;
+ }
+ }
+ else
+ dest = ServerInstance->FindNickOnly(destnick);
+ }
+ else
+ dest = ServerInstance->FindNick(destnick);
+
+ if ((dest) && (dest->registered == REG_ALL))
+ {
+ if (parameters[1].empty())
+ {
+ user->WriteNumeric(ERR_NOTEXTTOSEND, ":No text to send");
+ return CMD_FAILURE;
+ }
+
+ if ((dest->IsAway()) && (mt == MSG_PRIVMSG))
+ {
+ /* auto respond with aweh msg */
+ user->WriteNumeric(RPL_AWAY, "%s :%s", dest->nick.c_str(), dest->awaymsg.c_str());
+ }
+
+ ModResult MOD_RESULT;
+
+ std::string temp = parameters[1];
+ FIRST_MOD_RESULT(OnUserPreMessage, MOD_RESULT, (user, dest, TYPE_USER, temp, 0, except_list, mt));
+ if (MOD_RESULT == MOD_RES_DENY)
+ return CMD_FAILURE;
+
+ const char* text = temp.c_str();
+
+ FOREACH_MOD(OnText, (user, dest, TYPE_USER, text, 0, except_list));
+
+ if (IS_LOCAL(dest))
+ {
+ // direct write, same server
+ dest->WriteFrom(user, "%s %s :%s", MessageTypeString[mt], dest->nick.c_str(), text);
+ }
+
+ FOREACH_MOD(OnUserMessage, (user, dest, TYPE_USER, text, 0, except_list, mt));
+ }
+ else
+ {
+ /* no such nick/channel */
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", parameters[0].c_str());
+ return CMD_FAILURE;
+ }
+ return CMD_SUCCESS;
+}
+
+template<MessageType MT>
+class CommandMessage : public MessageCommandBase
+{
+ public:
+ CommandMessage(Module* parent)
+ : MessageCommandBase(parent, MT)
+ {
+ }
+
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user)
+ {
+ return HandleMessage(parameters, user, MT);
+ }
+};
+
+class ModuleCoreMessage : public Module
+{
+ CommandMessage<MSG_PRIVMSG> CommandPrivmsg;
+ CommandMessage<MSG_NOTICE> CommandNotice;
+
+ public:
+ ModuleCoreMessage()
+ : CommandPrivmsg(this), CommandNotice(this)
+ {
+ }
+
+ Version GetVersion()
+ {
+ return Version("PRIVMSG, NOTICE", VF_CORE|VF_VENDOR);
+ }
+};
+
+MODULE_INIT(ModuleCoreMessage)
diff --git a/src/commands/cmd_reloadmodule.cpp b/src/coremods/core_reloadmodule.cpp
index 81ecce1cb..1561131dc 100644
--- a/src/commands/cmd_reloadmodule.cpp
+++ b/src/coremods/core_reloadmodule.cpp
@@ -27,8 +27,7 @@ class CommandReloadmodule : public Command
*/
CommandReloadmodule ( Module* parent) : Command( parent, "RELOADMODULE",1) { flags_needed = 'o'; syntax = "<modulename>"; }
/** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
+ * @param parameters The parameters to the command
* @param user The user issuing the command
* @return A value from CmdResult to indicate command success or failure.
*/
@@ -48,22 +47,22 @@ class ReloadModuleWorker : public HandlerBase1<void, bool>
name.c_str(), result ? "" : "un");
User* user = ServerInstance->FindNick(uid);
if (user)
- user->WriteNumeric(975, "%s %s :Module %ssuccessfully reloaded.",
- user->nick.c_str(), name.c_str(), result ? "" : "un");
+ user->WriteNumeric(RPL_LOADEDMODULE, "%s :Module %ssuccessfully reloaded.",
+ name.c_str(), result ? "" : "un");
ServerInstance->GlobalCulls.AddItem(this);
}
};
CmdResult CommandReloadmodule::Handle (const std::vector<std::string>& parameters, User *user)
{
- if (parameters[0] == "cmd_reloadmodule.so")
+ Module* m = ServerInstance->Modules->Find(parameters[0]);
+ if (m == creator)
{
- user->WriteNumeric(975, "%s %s :You cannot reload cmd_reloadmodule.so (unload and load it)",
- user->nick.c_str(), parameters[0].c_str());
+ user->WriteNumeric(RPL_LOADEDMODULE, "%s :You cannot reload core_reloadmodule.so (unload and load it)",
+ parameters[0].c_str());
return CMD_FAILURE;
}
- Module* m = ServerInstance->Modules->Find(parameters[0]);
if (m)
{
ServerInstance->Modules->Reload(m, new ReloadModuleWorker(user->uuid, parameters[0]));
@@ -71,7 +70,7 @@ CmdResult CommandReloadmodule::Handle (const std::vector<std::string>& parameter
}
else
{
- user->WriteNumeric(975, "%s %s :Could not find module by that name", user->nick.c_str(), parameters[0].c_str());
+ user->WriteNumeric(RPL_LOADEDMODULE, "%s :Could not find module by that name", parameters[0].c_str());
return CMD_FAILURE;
}
}
diff --git a/src/coremods/core_stats.cpp b/src/coremods/core_stats.cpp
new file mode 100644
index 000000000..997dd3afe
--- /dev/null
+++ b/src/coremods/core_stats.cpp
@@ -0,0 +1,393 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc>
+ * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "xline.h"
+
+#ifdef _WIN32
+#include <psapi.h>
+#pragma comment(lib, "psapi.lib") // For GetProcessMemoryInfo()
+#endif
+
+/** Handle /STATS.
+ */
+class CommandStats : public Command
+{
+ void DoStats(char statschar, User* user, string_list &results);
+ public:
+ /** Constructor for stats.
+ */
+ CommandStats ( Module* parent) : Command(parent,"STATS",1,2) { syntax = "<stats-symbol> [<servername>]"; }
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User *user);
+ RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
+ {
+ if (parameters.size() > 1)
+ return ROUTE_UNICAST(parameters[1]);
+ return ROUTE_LOCALONLY;
+ }
+};
+
+static void GenerateStatsLl(User* user, string_list& results, char c)
+{
+ results.push_back(InspIRCd::Format("211 %s nick[ident@%s] sendq cmds_out bytes_out cmds_in bytes_in time_open", user->nick.c_str(), (c == 'l' ? "host" : "ip")));
+
+ const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers();
+ for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i)
+ {
+ LocalUser* u = *i;
+ results.push_back("211 "+user->nick+" "+u->nick+"["+u->ident+"@"+(c == 'l' ? u->dhost : u->GetIPString())+"] "+ConvToStr(u->eh.getSendQSize())+" "+ConvToStr(u->cmds_out)+" "+ConvToStr(u->bytes_out)+" "+ConvToStr(u->cmds_in)+" "+ConvToStr(u->bytes_in)+" "+ConvToStr(ServerInstance->Time() - u->age));
+ }
+}
+
+void CommandStats::DoStats(char statschar, User* user, string_list &results)
+{
+ bool isPublic = ServerInstance->Config->UserStats.find(statschar) != std::string::npos;
+ bool isRemoteOper = IS_REMOTE(user) && (user->IsOper());
+ bool isLocalOperWithPrivs = IS_LOCAL(user) && user->HasPrivPermission("servers/auspex");
+
+ if (!isPublic && !isRemoteOper && !isLocalOperWithPrivs)
+ {
+ ServerInstance->SNO->WriteToSnoMask('t',
+ "%s '%c' denied for %s (%s@%s)",
+ (IS_LOCAL(user) ? "Stats" : "Remote stats"),
+ statschar, user->nick.c_str(), user->ident.c_str(), user->host.c_str());
+ results.push_back("481 " + user->nick + " :Permission Denied - STATS " + statschar + " requires the servers/auspex priv.");
+ return;
+ }
+
+ ModResult MOD_RESULT;
+ FIRST_MOD_RESULT(OnStats, MOD_RESULT, (statschar, user, results));
+ if (MOD_RESULT == MOD_RES_DENY)
+ {
+ results.push_back("219 "+user->nick+" "+statschar+" :End of /STATS report");
+ ServerInstance->SNO->WriteToSnoMask('t',"%s '%c' requested by %s (%s@%s)",
+ (IS_LOCAL(user) ? "Stats" : "Remote stats"), statschar, user->nick.c_str(), user->ident.c_str(), user->host.c_str());
+ return;
+ }
+
+ switch (statschar)
+ {
+ /* stats p (show listening ports) */
+ case 'p':
+ {
+ for (std::vector<ListenSocket*>::const_iterator i = ServerInstance->ports.begin(); i != ServerInstance->ports.end(); ++i)
+ {
+ ListenSocket* ls = *i;
+ std::string ip = ls->bind_addr;
+ if (ip.empty())
+ ip.assign("*");
+ std::string type = ls->bind_tag->getString("type", "clients");
+ std::string hook = ls->bind_tag->getString("ssl", "plaintext");
+
+ results.push_back("249 "+user->nick+" :"+ ip + ":"+ConvToStr(ls->bind_port)+
+ " (" + type + ", " + hook + ")");
+ }
+ }
+ break;
+
+ /* These stats symbols must be handled by a linking module */
+ case 'n':
+ case 'c':
+ break;
+
+ case 'i':
+ {
+ for (ServerConfig::ClassVector::const_iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); ++i)
+ {
+ ConnectClass* c = *i;
+ std::stringstream res;
+ res << "215 " << user->nick << " I " << c->name << ' ';
+ if (c->type == CC_ALLOW)
+ res << '+';
+ if (c->type == CC_DENY)
+ res << '-';
+
+ if (c->type == CC_NAMED)
+ res << '*';
+ else
+ res << c->host;
+
+ res << ' ' << c->config->getString("port", "*") << ' ';
+
+ res << c->GetRecvqMax() << ' ' << c->GetSendqSoftMax() << ' ' << c->GetSendqHardMax()
+ << ' ' << c->GetCommandRate() << ' ' << c->GetPenaltyThreshold();
+ if (c->fakelag)
+ res << '*';
+ results.push_back(res.str());
+ }
+ }
+ break;
+
+ case 'Y':
+ {
+ int idx = 0;
+ for (ServerConfig::ClassVector::const_iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++)
+ {
+ ConnectClass* c = *i;
+ results.push_back("215 "+user->nick+" i NOMATCH * "+c->GetHost()+" "+ConvToStr(c->limit ? c->limit : SocketEngine::GetMaxFds())+" "+ConvToStr(idx)+" "+ServerInstance->Config->ServerName+" *");
+ results.push_back("218 "+user->nick+" Y "+ConvToStr(idx)+" "+ConvToStr(c->GetPingTime())+" 0 "+ConvToStr(c->GetSendqHardMax())+" :"+
+ ConvToStr(c->GetRecvqMax())+" "+ConvToStr(c->GetRegTimeout()));
+ idx++;
+ }
+ }
+ break;
+
+ case 'P':
+ {
+ unsigned int idx = 0;
+ const UserManager::OperList& opers = ServerInstance->Users->all_opers;
+ for (UserManager::OperList::const_iterator i = opers.begin(); i != opers.end(); ++i)
+ {
+ User* oper = *i;
+ if (!oper->server->IsULine())
+ {
+ LocalUser* lu = IS_LOCAL(oper);
+ results.push_back("249 " + user->nick + " :" + oper->nick + " (" + oper->ident + "@" + oper->dhost + ") Idle: " +
+ (lu ? ConvToStr(ServerInstance->Time() - lu->idle_lastmsg) + " secs" : "unavailable"));
+ idx++;
+ }
+ }
+ results.push_back("249 "+user->nick+" :"+ConvToStr(idx)+" OPER(s)");
+ }
+ break;
+
+ case 'k':
+ ServerInstance->XLines->InvokeStats("K",216,user,results);
+ break;
+ case 'g':
+ ServerInstance->XLines->InvokeStats("G",223,user,results);
+ break;
+ case 'q':
+ ServerInstance->XLines->InvokeStats("Q",217,user,results);
+ break;
+ case 'Z':
+ ServerInstance->XLines->InvokeStats("Z",223,user,results);
+ break;
+ case 'e':
+ ServerInstance->XLines->InvokeStats("E",223,user,results);
+ break;
+ case 'E':
+ {
+ const SocketEngine::Statistics& stats = SocketEngine::GetStats();
+ results.push_back("249 "+user->nick+" :Total events: "+ConvToStr(stats.TotalEvents));
+ results.push_back("249 "+user->nick+" :Read events: "+ConvToStr(stats.ReadEvents));
+ results.push_back("249 "+user->nick+" :Write events: "+ConvToStr(stats.WriteEvents));
+ results.push_back("249 "+user->nick+" :Error events: "+ConvToStr(stats.ErrorEvents));
+ break;
+ }
+
+ /* stats m (list number of times each command has been used, plus bytecount) */
+ case 'm':
+ {
+ const CommandParser::CommandMap& commands = ServerInstance->Parser.GetCommands();
+ for (CommandParser::CommandMap::const_iterator i = commands.begin(); i != commands.end(); ++i)
+ {
+ if (i->second->use_count)
+ {
+ /* RPL_STATSCOMMANDS */
+ results.push_back("212 "+user->nick+" "+i->second->name+" "+ConvToStr(i->second->use_count));
+ }
+ }
+ }
+ break;
+
+ /* stats z (debug and memory info) */
+ case 'z':
+ {
+ results.push_back("249 "+user->nick+" :Users: "+ConvToStr(ServerInstance->Users->GetUsers().size()));
+ results.push_back("249 "+user->nick+" :Channels: "+ConvToStr(ServerInstance->GetChans().size()));
+ results.push_back("249 "+user->nick+" :Commands: "+ConvToStr(ServerInstance->Parser.GetCommands().size()));
+
+ float kbitpersec_in, kbitpersec_out, kbitpersec_total;
+ char kbitpersec_in_s[30], kbitpersec_out_s[30], kbitpersec_total_s[30];
+
+ SocketEngine::GetStats().GetBandwidth(kbitpersec_in, kbitpersec_out, kbitpersec_total);
+
+ snprintf(kbitpersec_total_s, 30, "%03.5f", kbitpersec_total);
+ snprintf(kbitpersec_out_s, 30, "%03.5f", kbitpersec_out);
+ snprintf(kbitpersec_in_s, 30, "%03.5f", kbitpersec_in);
+
+ results.push_back("249 "+user->nick+" :Bandwidth total: "+ConvToStr(kbitpersec_total_s)+" kilobits/sec");
+ results.push_back("249 "+user->nick+" :Bandwidth out: "+ConvToStr(kbitpersec_out_s)+" kilobits/sec");
+ results.push_back("249 "+user->nick+" :Bandwidth in: "+ConvToStr(kbitpersec_in_s)+" kilobits/sec");
+
+#ifndef _WIN32
+ /* Moved this down here so all the not-windows stuff (look w00tie, I didn't say win32!) is in one ifndef.
+ * Also cuts out some identical code in both branches of the ifndef. -- Om
+ */
+ rusage R;
+
+ /* Not sure why we were doing '0' with a RUSAGE_SELF comment rather than just using RUSAGE_SELF -- Om */
+ if (!getrusage(RUSAGE_SELF,&R)) /* RUSAGE_SELF */
+ {
+ results.push_back("249 "+user->nick+" :Total allocation: "+ConvToStr(R.ru_maxrss)+"K");
+ results.push_back("249 "+user->nick+" :Signals: "+ConvToStr(R.ru_nsignals));
+ results.push_back("249 "+user->nick+" :Page faults: "+ConvToStr(R.ru_majflt));
+ results.push_back("249 "+user->nick+" :Swaps: "+ConvToStr(R.ru_nswap));
+ results.push_back("249 "+user->nick+" :Context Switches: Voluntary; "+ConvToStr(R.ru_nvcsw)+" Involuntary; "+ConvToStr(R.ru_nivcsw));
+
+ char percent[30];
+
+ float n_elapsed = (ServerInstance->Time() - ServerInstance->stats.LastSampled.tv_sec) * 1000000
+ + (ServerInstance->Time_ns() - ServerInstance->stats.LastSampled.tv_nsec) / 1000;
+ float n_eaten = ((R.ru_utime.tv_sec - ServerInstance->stats.LastCPU.tv_sec) * 1000000 + R.ru_utime.tv_usec - ServerInstance->stats.LastCPU.tv_usec);
+ float per = (n_eaten / n_elapsed) * 100;
+
+ snprintf(percent, 30, "%03.5f%%", per);
+ results.push_back("249 "+user->nick+" :CPU Use (now): "+percent);
+
+ n_elapsed = ServerInstance->Time() - ServerInstance->startup_time;
+ n_eaten = (float)R.ru_utime.tv_sec + R.ru_utime.tv_usec / 100000.0;
+ per = (n_eaten / n_elapsed) * 100;
+ snprintf(percent, 30, "%03.5f%%", per);
+ results.push_back("249 "+user->nick+" :CPU Use (total): "+percent);
+ }
+#else
+ PROCESS_MEMORY_COUNTERS MemCounters;
+ if (GetProcessMemoryInfo(GetCurrentProcess(), &MemCounters, sizeof(MemCounters)))
+ {
+ results.push_back("249 "+user->nick+" :Total allocation: "+ConvToStr((MemCounters.WorkingSetSize + MemCounters.PagefileUsage) / 1024)+"K");
+ results.push_back("249 "+user->nick+" :Pagefile usage: "+ConvToStr(MemCounters.PagefileUsage / 1024)+"K");
+ results.push_back("249 "+user->nick+" :Page faults: "+ConvToStr(MemCounters.PageFaultCount));
+ }
+
+ FILETIME CreationTime;
+ FILETIME ExitTime;
+ FILETIME KernelTime;
+ FILETIME UserTime;
+ LARGE_INTEGER ThisSample;
+ if(GetProcessTimes(GetCurrentProcess(), &CreationTime, &ExitTime, &KernelTime, &UserTime) &&
+ QueryPerformanceCounter(&ThisSample))
+ {
+ KernelTime.dwHighDateTime += UserTime.dwHighDateTime;
+ KernelTime.dwLowDateTime += UserTime.dwLowDateTime;
+ double n_eaten = (double)( ( (uint64_t)(KernelTime.dwHighDateTime - ServerInstance->stats.LastCPU.dwHighDateTime) << 32 ) + (uint64_t)(KernelTime.dwLowDateTime - ServerInstance->stats.LastCPU.dwLowDateTime) )/100000;
+ double n_elapsed = (double)(ThisSample.QuadPart - ServerInstance->stats.LastSampled.QuadPart) / ServerInstance->stats.QPFrequency.QuadPart;
+ double per = (n_eaten/n_elapsed);
+
+ char percent[30];
+
+ snprintf(percent, 30, "%03.5f%%", per);
+ results.push_back("249 "+user->nick+" :CPU Use (now): "+percent);
+
+ n_elapsed = ServerInstance->Time() - ServerInstance->startup_time;
+ n_eaten = (double)(( (uint64_t)(KernelTime.dwHighDateTime) << 32 ) + (uint64_t)(KernelTime.dwLowDateTime))/100000;
+ per = (n_eaten / n_elapsed);
+ snprintf(percent, 30, "%03.5f%%", per);
+ results.push_back("249 "+user->nick+" :CPU Use (total): "+percent);
+ }
+#endif
+ }
+ break;
+
+ case 'T':
+ {
+ results.push_back("249 "+user->nick+" :accepts "+ConvToStr(ServerInstance->stats.Accept)+" refused "+ConvToStr(ServerInstance->stats.Refused));
+ results.push_back("249 "+user->nick+" :unknown commands "+ConvToStr(ServerInstance->stats.Unknown));
+ results.push_back("249 "+user->nick+" :nick collisions "+ConvToStr(ServerInstance->stats.Collisions));
+ results.push_back("249 "+user->nick+" :dns requests "+ConvToStr(ServerInstance->stats.DnsGood+ServerInstance->stats.DnsBad)+" succeeded "+ConvToStr(ServerInstance->stats.DnsGood)+" failed "+ConvToStr(ServerInstance->stats.DnsBad));
+ results.push_back("249 "+user->nick+" :connection count "+ConvToStr(ServerInstance->stats.Connects));
+ results.push_back(InspIRCd::Format("249 %s :bytes sent %5.2fK recv %5.2fK", user->nick.c_str(),
+ ServerInstance->stats.Sent / 1024.0, ServerInstance->stats.Recv / 1024.0));
+ }
+ break;
+
+ /* stats o */
+ case 'o':
+ {
+ ConfigTagList tags = ServerInstance->Config->ConfTags("oper");
+ for(ConfigIter i = tags.first; i != tags.second; ++i)
+ {
+ ConfigTag* tag = i->second;
+ results.push_back("243 "+user->nick+" O "+tag->getString("host")+" * "+
+ tag->getString("name") + " " + tag->getString("type")+" 0");
+ }
+ }
+ break;
+ case 'O':
+ {
+ for (ServerConfig::OperIndex::const_iterator i = ServerInstance->Config->OperTypes.begin(); i != ServerInstance->Config->OperTypes.end(); ++i)
+ {
+ OperInfo* tag = i->second;
+ tag->init();
+ std::string umodes;
+ std::string cmodes;
+ for(char c='A'; c <= 'z'; c++)
+ {
+ ModeHandler* mh = ServerInstance->Modes->FindMode(c, MODETYPE_USER);
+ if (mh && mh->NeedsOper() && tag->AllowedUserModes[c - 'A'])
+ umodes.push_back(c);
+ mh = ServerInstance->Modes->FindMode(c, MODETYPE_CHANNEL);
+ if (mh && mh->NeedsOper() && tag->AllowedChanModes[c - 'A'])
+ cmodes.push_back(c);
+ }
+ results.push_back("243 "+user->nick+" O "+tag->name.c_str() + " " + umodes + " " + cmodes);
+ }
+ }
+ break;
+
+ /* stats l (show user I/O stats) */
+ case 'l':
+ /* stats L (show user I/O stats with IP addresses) */
+ case 'L':
+ GenerateStatsLl(user, results, statschar);
+ break;
+
+ /* stats u (show server uptime) */
+ case 'u':
+ {
+ unsigned int up = static_cast<unsigned int>(ServerInstance->Time() - ServerInstance->startup_time);
+ results.push_back(InspIRCd::Format("242 %s :Server up %u days, %.2u:%.2u:%.2u", user->nick.c_str(),
+ up / 86400, (up / 3600) % 24, (up / 60) % 60, up % 60));
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ results.push_back("219 "+user->nick+" "+statschar+" :End of /STATS report");
+ ServerInstance->SNO->WriteToSnoMask('t',"%s '%c' requested by %s (%s@%s)",
+ (IS_LOCAL(user) ? "Stats" : "Remote stats"), statschar, user->nick.c_str(), user->ident.c_str(), user->host.c_str());
+ return;
+}
+
+CmdResult CommandStats::Handle (const std::vector<std::string>& parameters, User *user)
+{
+ if (parameters.size() > 1 && parameters[1] != ServerInstance->Config->ServerName)
+ return CMD_SUCCESS;
+ string_list values;
+ char search = parameters[0][0];
+ DoStats(search, user, values);
+
+ const std::string p = ":" + ServerInstance->Config->ServerName + " ";
+ for (size_t i = 0; i < values.size(); i++)
+ user->SendText(p + values[i]);
+
+ return CMD_SUCCESS;
+}
+
+COMMAND_INIT(CommandStats)
diff --git a/src/coremods/core_stub.cpp b/src/coremods/core_stub.cpp
new file mode 100644
index 000000000..bb6590261
--- /dev/null
+++ b/src/coremods/core_stub.cpp
@@ -0,0 +1,156 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com>
+ * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+
+
+/** Handle /CONNECT.
+ */
+class CommandConnect : public Command
+{
+ public:
+ /** Constructor for connect.
+ */
+ CommandConnect(Module* parent)
+ : Command(parent, "CONNECT", 1)
+ {
+ flags_needed = 'o';
+ syntax = "<servername>";
+ }
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user)
+ {
+ /*
+ * This is handled by the server linking module, if necessary. Do not remove this stub.
+ */
+ user->WriteServ( "NOTICE %s :Look into loading a linking module (like m_spanningtree) if you want this to do anything useful.", user->nick.c_str());
+ return CMD_SUCCESS;
+ }
+};
+
+/** Handle /LINKS.
+ */
+class CommandLinks : public Command
+{
+ public:
+ /** Constructor for links.
+ */
+ CommandLinks(Module* parent)
+ : Command(parent, "LINKS", 0, 0)
+ {
+ }
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user)
+ {
+ user->WriteNumeric(RPL_LINKS, "%s %s :0 %s", ServerInstance->Config->ServerName.c_str(),ServerInstance->Config->ServerName.c_str(),ServerInstance->Config->ServerDesc.c_str());
+ user->WriteNumeric(RPL_ENDOFLINKS, "* :End of /LINKS list.");
+ return CMD_SUCCESS;
+ }
+};
+
+/** Handle /SERVER.
+ */
+class CommandServer : public Command
+{
+ public:
+ /** Constructor for server.
+ */
+ CommandServer(Module* parent)
+ : Command(parent, "SERVER")
+ {
+ works_before_reg = true;
+ }
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user)
+ {
+ if (user->registered == REG_ALL)
+ {
+ user->WriteNumeric(ERR_ALREADYREGISTERED, ":You are already registered. (Perhaps your IRC client does not have a /SERVER command).");
+ }
+ else
+ {
+ user->WriteNumeric(ERR_NOTREGISTERED, ":You may not register as a server (servers have separate ports from clients, change your config)");
+ }
+ return CMD_FAILURE;
+ }
+};
+
+/** Handle /SQUIT.
+ */
+class CommandSquit : public Command
+{
+ public:
+ /** Constructor for squit.
+ */
+ CommandSquit(Module* parent)
+ : Command(parent, "SQUIT", 1, 2)
+ {
+ flags_needed = 'o';
+ syntax = "<servername>";
+ }
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user)
+ {
+ user->WriteServ("NOTICE %s :Look into loading a linking module (like m_spanningtree) if you want this to do anything useful.", user->nick.c_str());
+ return CMD_FAILURE;
+ }
+};
+
+class CoreModStub : public Module
+{
+ CommandConnect cmdconnect;
+ CommandLinks cmdlinks;
+ CommandServer cmdserver;
+ CommandSquit cmdsquit;
+
+ public:
+ CoreModStub()
+ : cmdconnect(this), cmdlinks(this), cmdserver(this), cmdsquit(this)
+ {
+ }
+
+ Version GetVersion()
+ {
+ return Version("Provides the stub commands CONNECT, LINKS, SERVER and SQUIT", VF_VENDOR|VF_CORE);
+ }
+};
+
+MODULE_INIT(CoreModStub)
diff --git a/src/commands/cmd_away.cpp b/src/coremods/core_user/cmd_away.cpp
index fa3f7fae9..adc6e6c18 100644
--- a/src/commands/cmd_away.cpp
+++ b/src/coremods/core_user/cmd_away.cpp
@@ -19,26 +19,13 @@
#include "inspircd.h"
+#include "core_user.h"
-/** Handle /AWAY. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandAway : public Command
+CommandAway::CommandAway(Module* parent)
+ : Command(parent, "AWAY", 0, 0)
{
- public:
- /** Constructor for away.
- */
- CommandAway ( Module* parent) : Command(parent,"AWAY",0,0) { syntax = "[<message>]"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
+ syntax = "[<message>]";
+}
/** Handle /AWAY
*/
@@ -56,7 +43,7 @@ CmdResult CommandAway::Handle (const std::vector<std::string>& parameters, User
user->awaytime = ServerInstance->Time();
user->awaymsg.assign(parameters[0], 0, ServerInstance->Config->Limits.MaxAway);
- user->WriteNumeric(RPL_NOWAWAY, "%s :You have been marked as being away",user->nick.c_str());
+ user->WriteNumeric(RPL_NOWAWAY, ":You have been marked as being away");
}
else
{
@@ -66,10 +53,13 @@ CmdResult CommandAway::Handle (const std::vector<std::string>& parameters, User
return CMD_FAILURE;
user->awaymsg.clear();
- user->WriteNumeric(RPL_UNAWAY, "%s :You are no longer marked as being away",user->nick.c_str());
+ user->WriteNumeric(RPL_UNAWAY, ":You are no longer marked as being away");
}
return CMD_SUCCESS;
}
-COMMAND_INIT(CommandAway)
+RouteDescriptor CommandAway::GetRouting(User* user, const std::vector<std::string>& parameters)
+{
+ return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST);
+}
diff --git a/src/commands/cmd_nick.cpp b/src/coremods/core_user/cmd_nick.cpp
index a079e59d0..a62e1c207 100644
--- a/src/commands/cmd_nick.cpp
+++ b/src/coremods/core_user/cmd_nick.cpp
@@ -21,44 +21,33 @@
#include "inspircd.h"
+#include "core_user.h"
-/** Handle /NICK. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandNick : public Command
+CommandNick::CommandNick(Module* parent)
+ : SplitCommand(parent, "NICK", 1, 1)
{
- public:
- /** Constructor for nick.
- */
- CommandNick ( Module* parent) : Command(parent,"NICK", 1, 1) { works_before_reg = true; syntax = "<newnick>"; Penalty = 0; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
+ works_before_reg = true;
+ syntax = "<newnick>";
+ Penalty = 0;
+}
/** Handle nick changes from users.
* NOTE: If you are used to ircds based on ircd2.8, and are looking
* for the client introduction code in here, youre in the wrong place.
* You need to look in the spanningtree module for this!
*/
-CmdResult CommandNick::Handle (const std::vector<std::string>& parameters, User *user)
+CmdResult CommandNick::HandleLocal(const std::vector<std::string>& parameters, LocalUser* user)
{
std::string oldnick = user->nick;
std::string newnick = parameters[0];
// anything except the initial NICK gets a flood penalty
- if (user->registered == REG_ALL && IS_LOCAL(user))
- IS_LOCAL(user)->CommandFloodPenalty += 4000;
+ if (user->registered == REG_ALL)
+ user->CommandFloodPenalty += 4000;
if (newnick.empty())
{
- user->WriteNumeric(432, "%s * :Erroneous Nickname", oldnick.c_str());
+ user->WriteNumeric(ERR_ERRONEUSNICKNAME, "* :Erroneous Nickname");
return CMD_FAILURE;
}
@@ -66,33 +55,42 @@ CmdResult CommandNick::Handle (const std::vector<std::string>& parameters, User
{
newnick = user->uuid;
}
- else if (!ServerInstance->IsNick(newnick.c_str(), ServerInstance->Config->Limits.NickMax))
+ else if (!ServerInstance->IsNick(newnick))
{
- user->WriteNumeric(432, "%s %s :Erroneous Nickname", user->nick.c_str(),newnick.c_str());
+ user->WriteNumeric(ERR_ERRONEUSNICKNAME, "%s :Erroneous Nickname", newnick.c_str());
return CMD_FAILURE;
}
- if (!user->ChangeNick(newnick, false))
+ ModResult MOD_RESULT;
+ FIRST_MOD_RESULT(OnUserPreNick, MOD_RESULT, (user, newnick));
+
+ // If a module denied the change, abort now
+ if (MOD_RESULT == MOD_RES_DENY)
return CMD_FAILURE;
- if (user->registered < REG_NICKUSER)
+ // Disallow the nick change if <security:restrictbannedusers> is on and there is a ban matching this user in
+ // one of the channels they are on
+ if (ServerInstance->Config->RestrictBannedUsers)
{
- user->registered = (user->registered | REG_NICK);
- if (user->registered == REG_NICKUSER)
+ for (User::ChanList::iterator i = user->chans.begin(); i != user->chans.end(); ++i)
{
- /* user is registered now, bit 0 = USER command, bit 1 = sent a NICK command */
- ModResult MOD_RESULT;
- FIRST_MOD_RESULT(OnUserRegister, MOD_RESULT, (IS_LOCAL(user)));
- if (MOD_RESULT == MOD_RES_DENY)
+ Channel* chan = (*i)->chan;
+ if (chan->GetPrefixValue(user) < VOICE_VALUE && chan->IsBanned(user))
+ {
+ user->WriteNumeric(ERR_CANNOTSENDTOCHAN, "%s :Cannot send to channel (you're banned)", chan->name.c_str());
return CMD_FAILURE;
-
- // return early to not penalize new users
- return CMD_SUCCESS;
+ }
}
}
- return CMD_SUCCESS;
-}
+ if (!user->ChangeNick(newnick))
+ return CMD_FAILURE;
+ if (user->registered < REG_NICKUSER)
+ {
+ user->registered = (user->registered | REG_NICK);
+ return CommandUser::CheckRegister(user);
+ }
-COMMAND_INIT(CommandNick)
+ return CMD_SUCCESS;
+}
diff --git a/src/coremods/core_user/cmd_part.cpp b/src/coremods/core_user/cmd_part.cpp
new file mode 100644
index 000000000..9f82c15a5
--- /dev/null
+++ b/src/coremods/core_user/cmd_part.cpp
@@ -0,0 +1,63 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "core_user.h"
+
+CommandPart::CommandPart(Module* parent)
+ : Command(parent, "PART", 1, 2)
+{
+ Penalty = 5;
+ syntax = "<channel>{,<channel>} [<reason>]";
+}
+
+CmdResult CommandPart::Handle (const std::vector<std::string>& parameters, User *user)
+{
+ std::string reason;
+ if (parameters.size() > 1)
+ {
+ if (IS_LOCAL(user))
+ msgwrap.Wrap(parameters[1], reason);
+ else
+ reason = parameters[1];
+ }
+
+ if (CommandParser::LoopCall(user, this, parameters, 0))
+ return CMD_SUCCESS;
+
+ Channel* c = ServerInstance->FindChan(parameters[0]);
+
+ if (c)
+ {
+ c->PartUser(user, reason);
+ }
+ else
+ {
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", parameters[0].c_str());
+ return CMD_FAILURE;
+ }
+
+ return CMD_SUCCESS;
+}
+
+RouteDescriptor CommandPart::GetRouting(User* user, const std::vector<std::string>& parameters)
+{
+ return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST);
+}
diff --git a/src/coremods/core_user/cmd_quit.cpp b/src/coremods/core_user/cmd_quit.cpp
new file mode 100644
index 000000000..c4e127dd8
--- /dev/null
+++ b/src/coremods/core_user/cmd_quit.cpp
@@ -0,0 +1,50 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "core_user.h"
+
+CommandQuit::CommandQuit(Module* parent)
+ : Command(parent, "QUIT", 0, 1)
+{
+ works_before_reg = true;
+ syntax = "[<message>]";
+}
+
+CmdResult CommandQuit::Handle (const std::vector<std::string>& parameters, User *user)
+{
+ std::string quitmsg;
+ if (parameters.empty())
+ quitmsg = "Client exited";
+ else if (IS_LOCAL(user))
+ msgwrap.Wrap(parameters[0], quitmsg);
+ else
+ quitmsg = parameters[0];
+
+ std::string* operquit = ServerInstance->OperQuit.get(user);
+ ServerInstance->Users->QuitUser(user, quitmsg, operquit);
+
+ return CMD_SUCCESS;
+}
+
+RouteDescriptor CommandQuit::GetRouting(User* user, const std::vector<std::string>& parameters)
+{
+ return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST);
+}
diff --git a/src/commands/cmd_user.cpp b/src/coremods/core_user/cmd_user.cpp
index 305d0847f..d593d7f4b 100644
--- a/src/commands/cmd_user.cpp
+++ b/src/coremods/core_user/cmd_user.cpp
@@ -19,39 +19,28 @@
#include "inspircd.h"
+#include "core_user.h"
-/** Handle /USER. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandUser : public SplitCommand
+CommandUser::CommandUser(Module* parent)
+ : SplitCommand(parent, "USER", 4, 4)
{
- public:
- /** Constructor for user.
- */
- CommandUser ( Module* parent) : SplitCommand(parent,"USER",4,4) { works_before_reg = true; Penalty = 0; syntax = "<username> <localhost> <remotehost> <GECOS>"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult HandleLocal(const std::vector<std::string>& parameters, LocalUser *user);
-};
+ works_before_reg = true;
+ Penalty = 0;
+ syntax = "<username> <localhost> <remotehost> <GECOS>";
+}
CmdResult CommandUser::HandleLocal(const std::vector<std::string>& parameters, LocalUser *user)
{
/* A user may only send the USER command once */
if (!(user->registered & REG_USER))
{
- if (!ServerInstance->IsIdent(parameters[0].c_str()))
+ if (!ServerInstance->IsIdent(parameters[0]))
{
/*
* RFC says we must use this numeric, so we do. Let's make it a little more nub friendly though. :)
* -- Craig, and then w00t.
*/
- user->WriteNumeric(461, "%s USER :Your username is not valid",user->nick.c_str());
+ user->WriteNumeric(ERR_NEEDMOREPARAMS, "USER :Your username is not valid");
return CMD_FAILURE;
}
else
@@ -61,30 +50,32 @@ CmdResult CommandUser::HandleLocal(const std::vector<std::string>& parameters, L
* ~ character, and +1 for null termination, therefore we can safely use up to
* IDENTMAX here.
*/
- user->ChangeIdent(parameters[0].c_str());
+ user->ChangeIdent(parameters[0]);
user->fullname.assign(parameters[3].empty() ? "No info" : parameters[3], 0, ServerInstance->Config->Limits.MaxGecos);
user->registered = (user->registered | REG_USER);
}
}
else
{
- user->WriteNumeric(462, "%s :You may not reregister", user->nick.c_str());
+ user->WriteNumeric(ERR_ALREADYREGISTERED, ":You may not reregister");
return CMD_FAILURE;
}
/* parameters 2 and 3 are local and remote hosts, and are ignored */
+ return CheckRegister(user);
+}
+
+CmdResult CommandUser::CheckRegister(LocalUser* user)
+{
+ // If the user is registered, return CMD_SUCCESS/CMD_FAILURE depending on what modules say, otherwise just
+ // return CMD_SUCCESS without doing anything, knowing the other handler will call us again
if (user->registered == REG_NICKUSER)
{
ModResult MOD_RESULT;
-
- /* user is registered now, bit 0 = USER command, bit 1 = sent a NICK command */
FIRST_MOD_RESULT(OnUserRegister, MOD_RESULT, (user));
if (MOD_RESULT == MOD_RES_DENY)
return CMD_FAILURE;
-
}
return CMD_SUCCESS;
}
-
-COMMAND_INIT(CommandUser)
diff --git a/src/coremods/core_user/core_user.cpp b/src/coremods/core_user/core_user.cpp
new file mode 100644
index 000000000..103880a6e
--- /dev/null
+++ b/src/coremods/core_user/core_user.cpp
@@ -0,0 +1,191 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "core_user.h"
+
+class CommandMode : public Command
+{
+ public:
+ /** Constructor for mode.
+ */
+ CommandMode(Module* parent)
+ : Command(parent, "MODE", 1)
+ {
+ syntax = "<target> <modes> {<mode-parameters>}";
+ }
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user)
+ {
+ ServerInstance->Modes->Process(parameters, user, (IS_LOCAL(user) ? ModeParser::MODE_NONE : ModeParser::MODE_LOCALONLY));
+ return CMD_SUCCESS;
+ }
+
+ RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
+ {
+ return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST);
+ }
+};
+
+/** Handle /PASS.
+ */
+class CommandPass : public SplitCommand
+{
+ public:
+ /** Constructor for pass.
+ */
+ CommandPass(Module* parent)
+ : SplitCommand(parent, "PASS", 1, 1)
+ {
+ works_before_reg = true;
+ Penalty = 0;
+ syntax = "<password>";
+ }
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult HandleLocal(const std::vector<std::string>& parameters, LocalUser *user)
+ {
+ // Check to make sure they haven't registered -- Fix by FCS
+ if (user->registered == REG_ALL)
+ {
+ user->WriteNumeric(ERR_ALREADYREGISTERED, ":You may not reregister");
+ return CMD_FAILURE;
+ }
+ user->password = parameters[0];
+
+ return CMD_SUCCESS;
+ }
+};
+
+/** Handle /PING.
+ */
+class CommandPing : public Command
+{
+ public:
+ /** Constructor for ping.
+ */
+ CommandPing(Module* parent)
+ : Command(parent, "PING", 1, 2)
+ {
+ Penalty = 0;
+ syntax = "<servername> [:<servername>]";
+ }
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user)
+ {
+ user->WriteServ("PONG %s :%s", ServerInstance->Config->ServerName.c_str(), parameters[0].c_str());
+ return CMD_SUCCESS;
+ }
+};
+
+/** Handle /PONG.
+ */
+class CommandPong : public Command
+{
+ public:
+ /** Constructor for pong.
+ */
+ CommandPong(Module* parent)
+ : Command(parent, "PONG", 0, 1)
+ {
+ Penalty = 0;
+ syntax = "<ping-text>";
+ }
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user)
+ {
+ // set the user as alive so they survive to next ping
+ if (IS_LOCAL(user))
+ IS_LOCAL(user)->lastping = 1;
+ return CMD_SUCCESS;
+ }
+};
+
+void MessageWrapper::Wrap(const std::string& message, std::string& out)
+{
+ // If there is a fixed message, it is stored in prefix. Otherwise prefix contains
+ // only the prefix, so append the message and the suffix
+ out.assign(prefix);
+ if (!fixed)
+ out.append(message).append(suffix);
+}
+
+void MessageWrapper::ReadConfig(const char* prefixname, const char* suffixname, const char* fixedname)
+{
+ ConfigTag* tag = ServerInstance->Config->ConfValue("options");
+ prefix = tag->getString(fixedname);
+ fixed = (!prefix.empty());
+ if (!fixed)
+ {
+ prefix = tag->getString(prefixname);
+ suffix = tag->getString(suffixname);
+ }
+}
+
+class CoreModUser : public Module
+{
+ CommandAway cmdaway;
+ CommandMode cmdmode;
+ CommandNick cmdnick;
+ CommandPart cmdpart;
+ CommandPass cmdpass;
+ CommandPing cmdping;
+ CommandPong cmdpong;
+ CommandQuit cmdquit;
+ CommandUser cmduser;
+
+ public:
+ CoreModUser()
+ : cmdaway(this), cmdmode(this), cmdnick(this), cmdpart(this), cmdpass(this), cmdping(this)
+ , cmdpong(this), cmdquit(this), cmduser(this)
+ {
+ }
+
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
+ {
+ cmdpart.msgwrap.ReadConfig("prefixpart", "suffixpart", "fixedpart");
+ cmdquit.msgwrap.ReadConfig("prefixquit", "suffixquit", "fixedquit");
+ }
+
+ Version GetVersion() CXX11_OVERRIDE
+ {
+ return Version("Provides the AWAY, MODE, NICK, PART, PASS, PING, PONG, QUIT and USER commands", VF_VENDOR|VF_CORE);
+ }
+};
+
+MODULE_INIT(CoreModUser)
diff --git a/src/coremods/core_user/core_user.h b/src/coremods/core_user/core_user.h
new file mode 100644
index 000000000..a529e0ccf
--- /dev/null
+++ b/src/coremods/core_user/core_user.h
@@ -0,0 +1,147 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#pragma once
+
+#include "inspircd.h"
+
+class MessageWrapper
+{
+ std::string prefix;
+ std::string suffix;
+ bool fixed;
+
+ public:
+ /**
+ * Wrap the given message according to the config rules
+ * @param message The message to wrap
+ * @param out String where the result is placed
+ */
+ void Wrap(const std::string& message, std::string& out);
+
+ /**
+ * Read the settings from the given config keys (options block)
+ * @param prefixname Name of the config key to read the prefix from
+ * @param suffixname Name of the config key to read the suffix from
+ * @param fixedname Name of the config key to read the fixed string string from.
+ * If this key has a non-empty value, all messages will be replaced with it.
+ */
+ void ReadConfig(const char* prefixname, const char* suffixname, const char* fixedname);
+};
+
+/** Handle /AWAY.
+ */
+class CommandAway : public Command
+{
+ public:
+ /** Constructor for away.
+ */
+ CommandAway(Module* parent);
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User *user);
+ RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters);
+};
+
+/** Handle /NICK.
+ */
+class CommandNick : public SplitCommand
+{
+ public:
+ /** Constructor for nick.
+ */
+ CommandNick(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult HandleLocal(const std::vector<std::string>& parameters, LocalUser* user);
+};
+
+/** Handle /PART.
+ */
+class CommandPart : public Command
+{
+ public:
+ MessageWrapper msgwrap;
+
+ /** Constructor for part.
+ */
+ CommandPart(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User *user);
+ RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters);
+};
+
+/** Handle /QUIT.
+ */
+class CommandQuit : public Command
+{
+ public:
+ MessageWrapper msgwrap;
+
+ /** Constructor for quit.
+ */
+ CommandQuit(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User*user);
+
+ RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters);
+};
+
+/** Handle /USER.
+ */
+class CommandUser : public SplitCommand
+{
+ public:
+ /** Constructor for user.
+ */
+ CommandUser(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult HandleLocal(const std::vector<std::string>& parameters, LocalUser *user);
+
+ /** Run the OnUserRegister hook if the user has sent both NICK and USER. Called after an unregistered user
+ * successfully executes the USER or the NICK command.
+ * @param user User to inspect and possibly pass to the OnUserRegister hook
+ * @return CMD_FAILURE if OnUserRegister was called and it returned MOD_RES_DENY, CMD_SUCCESS in every other case
+ * (i.e. if the hook wasn't fired because the user still needs to send NICK/USER or if it was fired and finished with
+ * a non-MOD_RES_DENY result).
+ */
+ static CmdResult CheckRegister(LocalUser* user);
+};
diff --git a/src/commands/cmd_userhost.cpp b/src/coremods/core_userhost.cpp
index 1065f9a35..a67824194 100644
--- a/src/commands/cmd_userhost.cpp
+++ b/src/coremods/core_userhost.cpp
@@ -20,10 +20,7 @@
#include "inspircd.h"
-/** Handle /USERHOST. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
+/** Handle /USERHOST.
*/
class CommandUserhost : public Command
{
@@ -34,8 +31,7 @@ class CommandUserhost : public Command
syntax = "<nick> [<nick> ...]";
}
/** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
+ * @param parameters The parameters to the command
* @param user The user issuing the command
* @return A value from CmdResult to indicate command success or failure.
*/
@@ -44,6 +40,8 @@ class CommandUserhost : public Command
CmdResult CommandUserhost::Handle (const std::vector<std::string>& parameters, User *user)
{
+ const bool has_privs = user->HasPrivPermission("users/auspex");
+
std::string retbuf = "302 " + user->nick + " :";
for (unsigned int i = 0; i < parameters.size(); i++)
@@ -52,30 +50,17 @@ CmdResult CommandUserhost::Handle (const std::vector<std::string>& parameters, U
if ((u) && (u->registered == REG_ALL))
{
- retbuf = retbuf + u->nick;
-
- if (IS_OPER(u))
- retbuf = retbuf + "*";
-
- retbuf = retbuf + "=";
-
- if (IS_AWAY(u))
- retbuf += "-";
- else
- retbuf += "+";
-
- retbuf = retbuf + u->ident + "@";
+ retbuf += u->nick;
- if (user->HasPrivPermission("users/auspex"))
- {
- retbuf = retbuf + u->host;
- }
- else
- {
- retbuf = retbuf + u->dhost;
- }
+ if (u->IsOper())
+ retbuf += '*';
- retbuf = retbuf + " ";
+ retbuf += '=';
+ retbuf += (u->IsAway() ? '-' : '+');
+ retbuf += u->ident;
+ retbuf += '@';
+ retbuf += (((u == user) || (has_privs)) ? u->host : u->dhost);
+ retbuf += ' ';
}
}
diff --git a/src/commands/cmd_wallops.cpp b/src/coremods/core_wallops.cpp
index 198997a95..0210df8ee 100644
--- a/src/commands/cmd_wallops.cpp
+++ b/src/coremods/core_wallops.cpp
@@ -20,24 +20,34 @@
#include "inspircd.h"
-/** Handle /WALLOPS. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
+/** Handle /WALLOPS.
*/
class CommandWallops : public Command
{
+ SimpleUserModeHandler wallopsmode;
+
public:
/** Constructor for wallops.
*/
- CommandWallops ( Module* parent) : Command(parent,"WALLOPS",1,1) { flags_needed = 'o'; syntax = "<any-text>"; }
+ CommandWallops(Module* parent)
+ : Command(parent, "WALLOPS", 1, 1)
+ , wallopsmode(parent, "wallops", 'w')
+ {
+ flags_needed = 'o';
+ syntax = "<any-text>";
+ }
+
/** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
+ * @param parameters The parameters to the command
* @param user The user issuing the command
* @return A value from CmdResult to indicate command success or failure.
*/
CmdResult Handle(const std::vector<std::string>& parameters, User *user);
+
+ RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
+ {
+ return ROUTE_BROADCAST;
+ }
};
CmdResult CommandWallops::Handle (const std::vector<std::string>& parameters, User *user)
@@ -45,14 +55,14 @@ CmdResult CommandWallops::Handle (const std::vector<std::string>& parameters, Us
std::string wallop("WALLOPS :");
wallop.append(parameters[0]);
- for (LocalUserList::const_iterator i = ServerInstance->Users->local_users.begin(); i != ServerInstance->Users->local_users.end(); i++)
+ const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers();
+ for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i)
{
User* t = *i;
- if (t->IsModeSet('w'))
- user->WriteTo(t,wallop);
+ if (t->IsModeSet(wallopsmode))
+ t->WriteFrom(user, wallop);
}
- FOREACH_MOD(I_OnWallops,OnWallops(user,parameters[0]));
return CMD_SUCCESS;
}
diff --git a/src/commands/cmd_who.cpp b/src/coremods/core_who.cpp
index 2b3242211..18a63ff3c 100644
--- a/src/commands/cmd_who.cpp
+++ b/src/coremods/core_who.cpp
@@ -20,10 +20,7 @@
#include "inspircd.h"
-/** Handle /WHO. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
+/** Handle /WHO.
*/
class CommandWho : public Command
{
@@ -39,17 +36,36 @@ class CommandWho : public Command
bool opt_local;
bool opt_far;
bool opt_time;
+ ChanModeReference secretmode;
+ ChanModeReference privatemode;
+ UserModeReference invisiblemode;
+
+ Membership* get_first_visible_channel(User* u)
+ {
+ for (User::ChanList::iterator i = u->chans.begin(); i != u->chans.end(); ++i)
+ {
+ Membership* memb = *i;
+ if (!memb->chan->IsModeSet(secretmode))
+ return memb;
+ }
+ return NULL;
+ }
public:
/** Constructor for who.
*/
- CommandWho ( Module* parent) : Command(parent,"WHO", 1) {
+ CommandWho(Module* parent)
+ : Command(parent, "WHO", 1)
+ , secretmode(parent, "secret")
+ , privatemode(parent, "private")
+ , invisiblemode(parent, "invisible")
+ {
syntax = "<server>|<nickname>|<channel>|<realname>|<host>|0 [ohurmMiaplf]";
}
- void SendWhoLine(User* user, const std::vector<std::string>& parms, const std::string &initial, Channel* ch, User* u, std::vector<std::string> &whoresults);
+
+ void SendWhoLine(User* user, const std::vector<std::string>& parms, const std::string& initial, Membership* memb, User* u, std::vector<std::string>& whoresults);
/** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
+ * @param parameters The parameters to the command
* @param user The user issuing the command
* @return A value from CmdResult to indicate command success or failure.
*/
@@ -57,19 +73,6 @@ class CommandWho : public Command
bool whomatch(User* cuser, User* user, const char* matchtext);
};
-
-static Channel* get_first_visible_channel(User *u)
-{
- UCListIter i = u->chans.begin();
- while (i != u->chans.end())
- {
- Channel* c = *i++;
- if (!c->IsModeSet('s'))
- return c;
- }
- return NULL;
-}
-
bool CommandWho::whomatch(User* cuser, User* user, const char* matchtext)
{
bool match = false;
@@ -138,7 +141,7 @@ bool CommandWho::whomatch(User* cuser, User* user, const char* matchtext)
match = InspIRCd::Match(user->awaymsg, matchtext);
else if (opt_time)
{
- long seconds = ServerInstance->Duration(matchtext);
+ long seconds = InspIRCd::Duration(matchtext);
// Okay, so time matching, we want all users connected `seconds' ago
if (user->age >= ServerInstance->Time() - seconds)
@@ -160,7 +163,7 @@ bool CommandWho::whomatch(User* cuser, User* user, const char* matchtext)
/* Don't allow server name matches if HideWhoisServer is enabled, unless the command user has the priv */
if (!match && (ServerInstance->Config->HideWhoisServer.empty() || cuser->HasPrivPermission("users/auspex")))
- match = InspIRCd::Match(user->server, matchtext);
+ match = InspIRCd::Match(user->server->GetName(), matchtext);
return match;
}
@@ -180,28 +183,28 @@ bool CommandWho::CanView(Channel* chan, User* user)
if (user->HasPrivPermission("users/auspex"))
return true;
/* Cant see inside a +s or a +p channel unless we are a member (see above) */
- else if (!chan->IsModeSet('s') && !chan->IsModeSet('p'))
+ else if (!chan->IsModeSet(secretmode) && !chan->IsModeSet(privatemode))
return true;
return false;
}
-void CommandWho::SendWhoLine(User* user, const std::vector<std::string>& parms, const std::string &initial, Channel* ch, User* u, std::vector<std::string> &whoresults)
+void CommandWho::SendWhoLine(User* user, const std::vector<std::string>& parms, const std::string& initial, Membership* memb, User* u, std::vector<std::string>& whoresults)
{
- if (!ch)
- ch = get_first_visible_channel(u);
+ if (!memb)
+ memb = get_first_visible_channel(u);
- std::string wholine = initial + (ch ? ch->name : "*") + " " + u->ident + " " +
+ std::string wholine = initial + (memb ? memb->chan->name : "*") + " " + u->ident + " " +
(opt_showrealhost ? u->host : u->dhost) + " ";
if (!ServerInstance->Config->HideWhoisServer.empty() && !user->HasPrivPermission("servers/auspex"))
wholine.append(ServerInstance->Config->HideWhoisServer);
else
- wholine.append(u->server);
-
+ wholine.append(u->server->GetName());
+
wholine.append(" " + u->nick + " ");
/* away? */
- if (IS_AWAY(u))
+ if (u->IsAway())
{
wholine.append("G");
}
@@ -211,17 +214,21 @@ void CommandWho::SendWhoLine(User* user, const std::vector<std::string>& parms,
}
/* oper? */
- if (IS_OPER(u))
+ if (u->IsOper())
{
wholine.push_back('*');
}
- if (ch)
- wholine.append(ch->GetPrefixChar(u));
+ if (memb)
+ {
+ char prefix = memb->GetPrefixChar();
+ if (prefix)
+ wholine.push_back(prefix);
+ }
wholine.append(" :0 " + u->fullname);
- FOREACH_MOD(I_OnSendWhoLine, OnSendWhoLine(user, parms, u, wholine));
+ FOREACH_MOD(OnSendWhoLine, (user, parms, u, memb, wholine));
if (!wholine.empty())
whoresults.push_back(wholine);
@@ -249,33 +256,17 @@ CmdResult CommandWho::Handle (const std::vector<std::string>& parameters, User *
opt_far = false;
opt_time = false;
- Channel *ch = NULL;
std::vector<std::string> whoresults;
std::string initial = "352 " + user->nick + " ";
- char matchtext[MAXBUF];
- bool usingwildcards = false;
-
/* Change '0' into '*' so the wildcard matcher can grok it */
- if (parameters[0] == "0")
- strlcpy(matchtext, "*", MAXBUF);
- else
- strlcpy(matchtext, parameters[0].c_str(), MAXBUF);
+ std::string matchtext = ((parameters[0] == "0") ? "*" : parameters[0]);
- for (const char* check = matchtext; *check; check++)
- {
- if (*check == '*' || *check == '?' || *check == '.')
- {
- usingwildcards = true;
- break;
- }
- }
+ // WHO flags count as a wildcard
+ bool usingwildcards = ((parameters.size() > 1) || (matchtext.find_first_of("*?.") != std::string::npos));
if (parameters.size() > 1)
{
- /* Fix for bug #444, WHO flags count as a wildcard */
- usingwildcards = true;
-
for (std::string::const_iterator iter = parameters[1].begin(); iter != parameters[1].end(); ++iter)
{
switch (*iter)
@@ -325,7 +316,7 @@ CmdResult CommandWho::Handle (const std::vector<std::string>& parameters, User *
/* who on a channel? */
- ch = ServerInstance->FindChan(matchtext);
+ Channel* ch = ServerInstance->FindChan(matchtext);
if (ch)
{
@@ -334,23 +325,22 @@ CmdResult CommandWho::Handle (const std::vector<std::string>& parameters, User *
bool inside = ch->HasUser(user);
/* who on a channel. */
- const UserMembList *cu = ch->GetUsers();
-
- for (UserMembCIter i = cu->begin(); i != cu->end(); i++)
+ const Channel::MemberMap& cu = ch->GetUsers();
+ for (Channel::MemberMap::const_iterator i = cu.begin(); i != cu.end(); ++i)
{
/* None of this applies if we WHO ourselves */
if (user != i->first)
{
/* opers only, please */
- if (opt_viewopersonly && !IS_OPER(i->first))
+ if (opt_viewopersonly && !i->first->IsOper())
continue;
/* If we're not inside the channel, hide +i users */
- if (i->first->IsModeSet('i') && !inside && !user->HasPrivPermission("users/auspex"))
+ if (i->first->IsModeSet(invisiblemode) && !inside && !user->HasPrivPermission("users/auspex"))
continue;
}
- SendWhoLine(user, parameters, initial, ch, i->first, whoresults);
+ SendWhoLine(user, parameters, initial, i->second, i->first, whoresults);
}
}
}
@@ -360,15 +350,16 @@ CmdResult CommandWho::Handle (const std::vector<std::string>& parameters, User *
if (opt_viewopersonly)
{
/* Showing only opers */
- for (std::list<User*>::iterator i = ServerInstance->Users->all_opers.begin(); i != ServerInstance->Users->all_opers.end(); i++)
+ const UserManager::OperList& opers = ServerInstance->Users->all_opers;
+ for (UserManager::OperList::const_iterator i = opers.begin(); i != opers.end(); ++i)
{
User* oper = *i;
- if (whomatch(user, oper, matchtext))
+ if (whomatch(user, oper, matchtext.c_str()))
{
if (!user->SharesChannelWith(oper))
{
- if (usingwildcards && (oper->IsModeSet('i')) && (!user->HasPrivPermission("users/auspex")))
+ if (usingwildcards && (oper->IsModeSet(invisiblemode)) && (!user->HasPrivPermission("users/auspex")))
continue;
}
@@ -378,13 +369,14 @@ CmdResult CommandWho::Handle (const std::vector<std::string>& parameters, User *
}
else
{
- for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
+ const user_hash& users = ServerInstance->Users->GetUsers();
+ for (user_hash::const_iterator i = users.begin(); i != users.end(); ++i)
{
- if (whomatch(user, i->second, matchtext))
+ if (whomatch(user, i->second, matchtext.c_str()))
{
if (!user->SharesChannelWith(i->second))
{
- if (usingwildcards && (i->second->IsModeSet('i')) && (!user->HasPrivPermission("users/auspex")))
+ if (usingwildcards && (i->second->IsModeSet(invisiblemode)) && (!user->HasPrivPermission("users/auspex")))
continue;
}
@@ -396,7 +388,7 @@ CmdResult CommandWho::Handle (const std::vector<std::string>& parameters, User *
/* Send the results out */
for (std::vector<std::string>::const_iterator n = whoresults.begin(); n != whoresults.end(); n++)
user->WriteServ(*n);
- user->WriteNumeric(315, "%s %s :End of /WHO list.",user->nick.c_str(), *parameters[0].c_str() ? parameters[0].c_str() : "*");
+ user->WriteNumeric(RPL_ENDOFWHO, "%s :End of /WHO list.", *parameters[0].c_str() ? parameters[0].c_str() : "*");
// Penalize the user a bit for large queries
// (add one unit of penalty per 200 results)
diff --git a/src/coremods/core_whois.cpp b/src/coremods/core_whois.cpp
new file mode 100644
index 000000000..8fce7d339
--- /dev/null
+++ b/src/coremods/core_whois.cpp
@@ -0,0 +1,244 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
+ * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+
+/** Handle /WHOIS.
+ */
+class CommandWhois : public SplitCommand
+{
+ ChanModeReference secretmode;
+ ChanModeReference privatemode;
+ UserModeReference snomaskmode;
+
+ void SplitChanList(User* source, User* dest, const std::string& cl);
+ void DoWhois(User* user, User* dest, unsigned long signon, unsigned long idle);
+ std::string ChannelList(User* source, User* dest, bool spy);
+
+ public:
+ /** Constructor for whois.
+ */
+ CommandWhois(Module* parent)
+ : SplitCommand(parent, "WHOIS", 1)
+ , secretmode(parent, "secret")
+ , privatemode(parent, "private")
+ , snomaskmode(parent, "snomask")
+ {
+ Penalty = 2;
+ syntax = "<nick>{,<nick>}";
+ }
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult HandleLocal(const std::vector<std::string>& parameters, LocalUser* user);
+ CmdResult HandleRemote(const std::vector<std::string>& parameters, RemoteUser* target);
+};
+
+std::string CommandWhois::ChannelList(User* source, User* dest, bool spy)
+{
+ std::string list;
+
+ for (User::ChanList::iterator i = dest->chans.begin(); i != dest->chans.end(); i++)
+ {
+ Membership* memb = *i;
+ Channel* c = memb->chan;
+ /* If the target is the sender, neither +p nor +s is set, or
+ * the channel contains the user, it is not a spy channel
+ */
+ if (spy != (source == dest || !(c->IsModeSet(privatemode) || c->IsModeSet(secretmode)) || c->HasUser(source)))
+ {
+ char prefix = memb->GetPrefixChar();
+ if (prefix)
+ list.push_back(prefix);
+ list.append(c->name).push_back(' ');
+ }
+ }
+
+ return list;
+}
+
+void CommandWhois::SplitChanList(User* source, User* dest, const std::string& cl)
+{
+ std::string line;
+ std::ostringstream prefix;
+ std::string::size_type start, pos;
+
+ prefix << dest->nick << " :";
+ line = prefix.str();
+ int namelen = ServerInstance->Config->ServerName.length() + 6;
+
+ for (start = 0; (pos = cl.find(' ', start)) != std::string::npos; start = pos+1)
+ {
+ if (line.length() + namelen + pos - start > 510)
+ {
+ ServerInstance->SendWhoisLine(source, dest, 319, line);
+ line = prefix.str();
+ }
+
+ line.append(cl.substr(start, pos - start + 1));
+ }
+
+ if (line.length() != prefix.str().length())
+ {
+ ServerInstance->SendWhoisLine(source, dest, 319, line);
+ }
+}
+
+void CommandWhois::DoWhois(User* user, User* dest, unsigned long signon, unsigned long idle)
+{
+ ServerInstance->SendWhoisLine(user, dest, 311, "%s %s %s * :%s", dest->nick.c_str(), dest->ident.c_str(), dest->dhost.c_str(), dest->fullname.c_str());
+ if (user == dest || user->HasPrivPermission("users/auspex"))
+ {
+ ServerInstance->SendWhoisLine(user, dest, 378, "%s :is connecting from %s@%s %s", dest->nick.c_str(), dest->ident.c_str(), dest->host.c_str(), dest->GetIPString().c_str());
+ }
+
+ std::string cl = ChannelList(user, dest, false);
+ const ServerConfig::OperSpyWhoisState state = user->HasPrivPermission("users/auspex") ? ServerInstance->Config->OperSpyWhois : ServerConfig::SPYWHOIS_NONE;
+
+ if (state == ServerConfig::SPYWHOIS_SINGLEMSG)
+ cl.append(ChannelList(user, dest, true));
+
+ SplitChanList(user, dest, cl);
+
+ if (state == ServerConfig::SPYWHOIS_SPLITMSG)
+ {
+ std::string scl = ChannelList(user, dest, true);
+ if (scl.length())
+ {
+ ServerInstance->SendWhoisLine(user, dest, 336, "%s :is on private/secret channels:", dest->nick.c_str());
+ SplitChanList(user, dest, scl);
+ }
+ }
+ if (user != dest && !ServerInstance->Config->HideWhoisServer.empty() && !user->HasPrivPermission("servers/auspex"))
+ {
+ ServerInstance->SendWhoisLine(user, dest, 312, "%s %s :%s", dest->nick.c_str(), ServerInstance->Config->HideWhoisServer.c_str(), ServerInstance->Config->Network.c_str());
+ }
+ else
+ {
+ ServerInstance->SendWhoisLine(user, dest, 312, "%s %s :%s", dest->nick.c_str(), dest->server->GetName().c_str(), dest->server->GetDesc().c_str());
+ }
+
+ if (dest->IsAway())
+ {
+ ServerInstance->SendWhoisLine(user, dest, 301, "%s :%s", dest->nick.c_str(), dest->awaymsg.c_str());
+ }
+
+ if (dest->IsOper())
+ {
+ if (ServerInstance->Config->GenericOper)
+ ServerInstance->SendWhoisLine(user, dest, 313, "%s :is an IRC operator", dest->nick.c_str());
+ else
+ ServerInstance->SendWhoisLine(user, dest, 313, "%s :is %s %s on %s", dest->nick.c_str(), (strchr("AEIOUaeiou",dest->oper->name[0]) ? "an" : "a"),dest->oper->name.c_str(), ServerInstance->Config->Network.c_str());
+ }
+
+ if (user == dest || user->HasPrivPermission("users/auspex"))
+ {
+ if (dest->IsModeSet(snomaskmode))
+ {
+ ServerInstance->SendWhoisLine(user, dest, 379, "%s :is using modes +%s %s", dest->nick.c_str(), dest->FormatModes(), snomaskmode->GetUserParameter(dest).c_str());
+ }
+ else
+ {
+ ServerInstance->SendWhoisLine(user, dest, 379, "%s :is using modes +%s", dest->nick.c_str(), dest->FormatModes());
+ }
+ }
+
+ FOREACH_MOD(OnWhois, (user,dest));
+
+ /*
+ * We only send these if we've been provided them. That is, if hidewhois is turned off, and user is local, or
+ * if remote whois is queried, too. This is to keep the user hidden, and also since you can't reliably tell remote time. -- w00t
+ */
+ if ((idle) || (signon))
+ {
+ ServerInstance->SendWhoisLine(user, dest, 317, "%s %lu %lu :seconds idle, signon time", dest->nick.c_str(), idle, signon);
+ }
+
+ ServerInstance->SendWhoisLine(user, dest, 318, "%s :End of /WHOIS list.", dest->nick.c_str());
+}
+
+CmdResult CommandWhois::HandleRemote(const std::vector<std::string>& parameters, RemoteUser* target)
+{
+ if (parameters.size() < 2)
+ return CMD_FAILURE;
+
+ User* user = ServerInstance->FindUUID(parameters[0]);
+ if (!user)
+ return CMD_FAILURE;
+
+ unsigned long idle = ConvToInt(parameters.back());
+ DoWhois(user, target, target->signon, idle);
+
+ return CMD_SUCCESS;
+}
+
+CmdResult CommandWhois::HandleLocal(const std::vector<std::string>& parameters, LocalUser* user)
+{
+ User *dest;
+ int userindex = 0;
+ unsigned long idle = 0, signon = 0;
+
+ if (CommandParser::LoopCall(user, this, parameters, 0))
+ return CMD_SUCCESS;
+
+ /*
+ * If 2 paramters are specified (/whois nick nick), ignore the first one like spanningtree
+ * does, and use the second one, otherwise, use the only paramter. -- djGrrr
+ */
+ if (parameters.size() > 1)
+ userindex = 1;
+
+ dest = ServerInstance->FindNickOnly(parameters[userindex]);
+
+ if ((dest) && (dest->registered == REG_ALL))
+ {
+ /*
+ * Okay. Umpteenth attempt at doing this, so let's re-comment...
+ * For local users (/w localuser), we show idletime if hidewhois is disabled
+ * For local users (/w localuser localuser), we always show idletime, hence parameters.size() > 1 check.
+ * For remote users (/w remoteuser), we do NOT show idletime
+ * For remote users (/w remoteuser remoteuser), spanningtree will handle calling do_whois, so we can ignore this case.
+ * Thanks to djGrrr for not being impatient while I have a crap day coding. :p -- w00t
+ */
+ LocalUser* localuser = IS_LOCAL(dest);
+ if (localuser && (ServerInstance->Config->HideWhoisServer.empty() || parameters.size() > 1))
+ {
+ idle = abs((long)((localuser->idle_lastmsg)-ServerInstance->Time()));
+ signon = dest->signon;
+ }
+
+ DoWhois(user,dest,signon,idle);
+ }
+ else
+ {
+ /* no such nick/channel */
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", !parameters[userindex].empty() ? parameters[userindex].c_str() : "*");
+ user->WriteNumeric(RPL_ENDOFWHOIS, "%s :End of /WHOIS list.", !parameters[userindex].empty() ? parameters[userindex].c_str() : "*");
+ return CMD_FAILURE;
+ }
+
+ return CMD_SUCCESS;
+}
+
+COMMAND_INIT(CommandWhois)
diff --git a/src/coremods/core_whowas.cpp b/src/coremods/core_whowas.cpp
new file mode 100644
index 000000000..d73fdf491
--- /dev/null
+++ b/src/coremods/core_whowas.cpp
@@ -0,0 +1,291 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
+ * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc>
+ * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "commands/cmd_whowas.h"
+
+CommandWhowas::CommandWhowas( Module* parent)
+ : Command(parent, "WHOWAS", 1)
+{
+ syntax = "<nick>{,<nick>}";
+ Penalty = 2;
+}
+
+CmdResult CommandWhowas::Handle (const std::vector<std::string>& parameters, User* user)
+{
+ /* if whowas disabled in config */
+ if (!manager.IsEnabled())
+ {
+ user->WriteNumeric(ERR_UNKNOWNCOMMAND, "%s :This command has been disabled.", name.c_str());
+ return CMD_FAILURE;
+ }
+
+ const WhoWas::Nick* const nick = manager.FindNick(parameters[0]);
+ if (!nick)
+ {
+ user->WriteNumeric(ERR_WASNOSUCHNICK, "%s :There was no such nickname", parameters[0].c_str());
+ }
+ else
+ {
+ const WhoWas::Nick::List& list = nick->entries;
+ if (!list.empty())
+ {
+ for (WhoWas::Nick::List::const_iterator i = list.begin(); i != list.end(); ++i)
+ {
+ WhoWas::Entry* u = *i;
+
+ user->WriteNumeric(RPL_WHOWASUSER, "%s %s %s * :%s", parameters[0].c_str(),
+ u->ident.c_str(),u->dhost.c_str(),u->gecos.c_str());
+
+ if (user->HasPrivPermission("users/auspex"))
+ user->WriteNumeric(RPL_WHOWASIP, "%s :was connecting from *@%s",
+ parameters[0].c_str(), u->host.c_str());
+
+ std::string signon = InspIRCd::TimeString(u->signon);
+ bool hide_server = (!ServerInstance->Config->HideWhoisServer.empty() && !user->HasPrivPermission("servers/auspex"));
+ user->WriteNumeric(RPL_WHOISSERVER, "%s %s :%s", parameters[0].c_str(), (hide_server ? ServerInstance->Config->HideWhoisServer.c_str() : u->server.c_str()), signon.c_str());
+ }
+ }
+ }
+
+ user->WriteNumeric(RPL_ENDOFWHOWAS, "%s :End of WHOWAS", parameters[0].c_str());
+ return CMD_SUCCESS;
+}
+
+WhoWas::Manager::Manager()
+ : GroupSize(0), MaxGroups(0), MaxKeep(0)
+{
+}
+
+const WhoWas::Nick* WhoWas::Manager::FindNick(const std::string& nickname) const
+{
+ whowas_users::const_iterator it = whowas.find(nickname);
+ if (it == whowas.end())
+ return NULL;
+
+ const Nick* nick = it->second;
+ if (nick->entries.empty())
+ return NULL;
+ return nick;
+}
+
+WhoWas::Manager::Stats WhoWas::Manager::GetStats() const
+{
+ size_t entrycount = 0;
+ for (whowas_users::const_iterator i = whowas.begin(); i != whowas.end(); ++i)
+ {
+ WhoWas::Nick::List& list = i->second->entries;
+ entrycount += list.size();
+ }
+
+ Stats stats;
+ stats.entrycount = entrycount;
+ return stats;
+}
+
+void WhoWas::Manager::Add(User* user)
+{
+ if (!IsEnabled())
+ return;
+
+ // Insert nick if it doesn't exist
+ // 'first' will point to the newly inserted element or to the existing element with an equivalent key
+ std::pair<whowas_users::iterator, bool> ret = whowas.insert(std::make_pair(user->nick, static_cast<WhoWas::Nick*>(NULL)));
+
+ if (ret.second) // If inserted
+ {
+ // This nick is new, create a list for it and add the first record to it
+ WhoWas::Nick* nick = new WhoWas::Nick(ret.first->first);
+ nick->entries.push_back(new Entry(user));
+ ret.first->second = nick;
+
+ // Add this nick to the fifo too
+ whowas_fifo.push_back(nick);
+
+ if (whowas.size() > this->MaxGroups)
+ {
+ // Too many nicks, remove the nick which was inserted the longest time ago from both the map and the fifo
+ nick = whowas_fifo.front();
+ whowas_fifo.pop_front();
+ whowas.erase(nick->nick);
+ delete nick;
+ }
+ }
+ else
+ {
+ // We've met this nick before, add a new record to the list
+ WhoWas::Nick::List& list = ret.first->second->entries;
+ list.push_back(new Entry(user));
+
+ // If there are too many records for this nick, remove the oldest (front)
+ if (list.size() > this->GroupSize)
+ {
+ delete list.front();
+ list.pop_front();
+ }
+ }
+}
+
+/* on rehash, refactor maps according to new conf values */
+void WhoWas::Manager::Prune()
+{
+ time_t min = ServerInstance->Time() - this->MaxKeep;
+
+ /* first cut the list to new size (maxgroups) and also prune entries that are timed out. */
+ while (!whowas_fifo.empty())
+ {
+ WhoWas::Nick* nick = whowas_fifo.front();
+ if ((whowas_fifo.size() > this->MaxGroups) || (nick->addtime < min))
+ {
+ /* hopefully redundant integrity check, but added while debugging r6216 */
+ if (!whowas.erase(nick->nick))
+ {
+ /* this should never happen, if it does maps are corrupt */
+ ServerInstance->Logs->Log("WHOWAS", LOG_DEFAULT, "BUG: Whowas maps got corrupted! (1)");
+ return;
+ }
+
+ whowas_fifo.pop_front();
+ delete nick;
+ }
+ else
+ break;
+ }
+
+ /* Then cut the whowas sets to new size (groupsize) */
+ for (whowas_users::iterator i = whowas.begin(); i != whowas.end(); ++i)
+ {
+ WhoWas::Nick::List& list = i->second->entries;
+ while (list.size() > this->GroupSize)
+ {
+ delete list.front();
+ list.pop_front();
+ }
+ }
+}
+
+/* call maintain once an hour to remove expired nicks */
+void WhoWas::Manager::Maintain()
+{
+ time_t min = ServerInstance->Time() - this->MaxKeep;
+ for (whowas_users::iterator i = whowas.begin(); i != whowas.end(); ++i)
+ {
+ WhoWas::Nick::List& list = i->second->entries;
+ while (!list.empty() && list.front()->signon < min)
+ {
+ delete list.front();
+ list.pop_front();
+ }
+ }
+}
+
+WhoWas::Manager::~Manager()
+{
+ for (whowas_users::iterator i = whowas.begin(); i != whowas.end(); ++i)
+ {
+ WhoWas::Nick* nick = i->second;
+ delete nick;
+ }
+}
+
+bool WhoWas::Manager::IsEnabled() const
+{
+ return ((GroupSize != 0) && (MaxGroups != 0));
+}
+
+void WhoWas::Manager::UpdateConfig(unsigned int NewGroupSize, unsigned int NewMaxGroups, unsigned int NewMaxKeep)
+{
+ if ((NewGroupSize == GroupSize) && (NewMaxGroups == MaxGroups) && (NewMaxKeep == MaxKeep))
+ return;
+
+ GroupSize = NewGroupSize;
+ MaxGroups = NewMaxGroups;
+ MaxKeep = NewMaxKeep;
+ Prune();
+}
+
+WhoWas::Entry::Entry(User* user)
+ : host(user->host)
+ , dhost(user->dhost)
+ , ident(user->ident)
+ , server(user->server->GetName())
+ , gecos(user->fullname)
+ , signon(user->signon)
+{
+}
+
+WhoWas::Nick::Nick(const std::string& nickname)
+ : addtime(ServerInstance->Time())
+ , nick(nickname)
+{
+}
+
+WhoWas::Nick::~Nick()
+{
+ stdalgo::delete_all(entries);
+}
+
+class ModuleWhoWas : public Module
+{
+ CommandWhowas cmd;
+
+ public:
+ ModuleWhoWas() : cmd(this)
+ {
+ }
+
+ void OnGarbageCollect()
+ {
+ // Remove all entries older than MaxKeep
+ cmd.manager.Maintain();
+ }
+
+ void OnUserQuit(User* user, const std::string& message, const std::string& oper_message)
+ {
+ cmd.manager.Add(user);
+ }
+
+ ModResult OnStats(char symbol, User* user, string_list &results)
+ {
+ if (symbol == 'z')
+ results.push_back("249 "+user->nick+" :Whowas entries: "+ConvToStr(cmd.manager.GetStats().entrycount));
+
+ return MOD_RES_PASSTHRU;
+ }
+
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
+ {
+ ConfigTag* tag = ServerInstance->Config->ConfValue("whowas");
+ unsigned int NewGroupSize = tag->getInt("groupsize", 10, 0, 10000);
+ unsigned int NewMaxGroups = tag->getInt("maxgroups", 10240, 0, 1000000);
+ unsigned int NewMaxKeep = tag->getDuration("maxkeep", 3600, 3600);
+
+ cmd.manager.UpdateConfig(NewGroupSize, NewMaxGroups, NewMaxKeep);
+ }
+
+ Version GetVersion()
+ {
+ return Version("WHOWAS", VF_VENDOR);
+ }
+};
+
+MODULE_INIT(ModuleWhoWas)
diff --git a/src/commands/cmd_eline.cpp b/src/coremods/core_xline/cmd_eline.cpp
index ca39f9061..26b49894b 100644
--- a/src/commands/cmd_eline.cpp
+++ b/src/coremods/core_xline/cmd_eline.cpp
@@ -20,26 +20,14 @@
#include "inspircd.h"
#include "xline.h"
+#include "core_xline.h"
-/** Handle /ELINE. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandEline : public Command
+CommandEline::CommandEline(Module* parent)
+ : Command(parent, "ELINE", 1, 3)
{
- public:
- /** Constructor for eline.
- */
- CommandEline ( Module* parent) : Command(parent,"ELINE",1,3) { flags_needed = 'o'; syntax = "<ident@host> [<duration> :<reason>]"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
+ flags_needed = 'o';
+ syntax = "<ident@host> [<duration> :<reason>]";
+}
/** Handle /ELINE
*/
@@ -60,17 +48,17 @@ CmdResult CommandEline::Handle (const std::vector<std::string>& parameters, User
else
ih = ServerInstance->XLines->IdentSplit(target);
- if (ih.first.empty())
- {
- user->WriteServ("NOTICE %s :*** Target not found", user->nick.c_str());
- return CMD_FAILURE;
- }
-
- if (ServerInstance->HostMatchesEveryone(ih.first+"@"+ih.second,user))
+ if (ih.first.empty())
+ {
+ user->WriteNotice("*** Target not found");
return CMD_FAILURE;
+ }
- long duration = ServerInstance->Duration(parameters[1].c_str());
+ InsaneBan::IPHostMatcher matcher;
+ if (InsaneBan::MatchesEveryone(ih.first+"@"+ih.second, matcher, user, "E", "hostmasks"))
+ return CMD_FAILURE;
+ unsigned long duration = InspIRCd::Duration(parameters[1]);
ELine* el = new ELine(ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), ih.first.c_str(), ih.second.c_str());
if (ServerInstance->XLines->AddLine(el, user))
{
@@ -81,7 +69,7 @@ CmdResult CommandEline::Handle (const std::vector<std::string>& parameters, User
else
{
time_t c_requires_crap = duration + ServerInstance->Time();
- std::string timestr = ServerInstance->TimeString(c_requires_crap);
+ std::string timestr = InspIRCd::TimeString(c_requires_crap);
ServerInstance->SNO->WriteToSnoMask('x',"%s added timed E-line for %s, expires on %s: %s",user->nick.c_str(),target.c_str(),
timestr.c_str(), parameters[2].c_str());
}
@@ -89,7 +77,7 @@ CmdResult CommandEline::Handle (const std::vector<std::string>& parameters, User
else
{
delete el;
- user->WriteServ("NOTICE %s :*** E-Line for %s already exists",user->nick.c_str(),target.c_str());
+ user->WriteNotice("*** E-Line for " + target + " already exists");
}
}
else
@@ -100,11 +88,9 @@ CmdResult CommandEline::Handle (const std::vector<std::string>& parameters, User
}
else
{
- user->WriteServ("NOTICE %s :*** E-Line %s not found in list, try /stats e.",user->nick.c_str(),target.c_str());
+ user->WriteNotice("*** E-Line " + target + " not found in list, try /stats e");
}
}
return CMD_SUCCESS;
}
-
-COMMAND_INIT(CommandEline)
diff --git a/src/commands/cmd_gline.cpp b/src/coremods/core_xline/cmd_gline.cpp
index 6505b7464..3f042c366 100644
--- a/src/commands/cmd_gline.cpp
+++ b/src/coremods/core_xline/cmd_gline.cpp
@@ -20,27 +20,15 @@
#include "inspircd.h"
#include "xline.h"
+#include "core_xline.h"
-/** Handle /GLINE. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandGline : public Command
+CommandGline::CommandGline(Module* parent)
+ : Command(parent, "GLINE", 1, 3)
{
- public:
- /** Constructor for gline.
- */
- CommandGline (Module* parent) : Command(parent,"GLINE",1,3) { flags_needed = 'o'; Penalty = 0; syntax = "<ident@host> [<duration> :<reason>]"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
-
+ flags_needed = 'o';
+ Penalty = 0;
+ syntax = "<ident@host> [<duration> :<reason>]";
+}
/** Handle /GLINE
*/
@@ -63,20 +51,21 @@ CmdResult CommandGline::Handle (const std::vector<std::string>& parameters, User
if (ih.first.empty())
{
- user->WriteServ("NOTICE %s :*** Target not found", user->nick.c_str());
+ user->WriteNotice("*** Target not found");
return CMD_FAILURE;
}
- if (ServerInstance->HostMatchesEveryone(ih.first+"@"+ih.second,user))
+ InsaneBan::IPHostMatcher matcher;
+ if (InsaneBan::MatchesEveryone(ih.first+"@"+ih.second, matcher, user, "G", "hostmasks"))
return CMD_FAILURE;
else if (target.find('!') != std::string::npos)
{
- user->WriteServ("NOTICE %s :*** G-Line cannot operate on nick!user@host masks",user->nick.c_str());
+ user->WriteNotice("*** G-Line cannot operate on nick!user@host masks");
return CMD_FAILURE;
}
- long duration = ServerInstance->Duration(parameters[1].c_str());
+ unsigned long duration = InspIRCd::Duration(parameters[1]);
GLine* gl = new GLine(ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), ih.first.c_str(), ih.second.c_str());
if (ServerInstance->XLines->AddLine(gl, user))
{
@@ -87,7 +76,7 @@ CmdResult CommandGline::Handle (const std::vector<std::string>& parameters, User
else
{
time_t c_requires_crap = duration + ServerInstance->Time();
- std::string timestr = ServerInstance->TimeString(c_requires_crap);
+ std::string timestr = InspIRCd::TimeString(c_requires_crap);
ServerInstance->SNO->WriteToSnoMask('x',"%s added timed G-line for %s, expires on %s: %s",user->nick.c_str(),target.c_str(),
timestr.c_str(), parameters[2].c_str());
}
@@ -97,7 +86,7 @@ CmdResult CommandGline::Handle (const std::vector<std::string>& parameters, User
else
{
delete gl;
- user->WriteServ("NOTICE %s :*** G-Line for %s already exists",user->nick.c_str(),target.c_str());
+ user->WriteNotice("** G-Line for " + target + " already exists");
}
}
@@ -109,11 +98,9 @@ CmdResult CommandGline::Handle (const std::vector<std::string>& parameters, User
}
else
{
- user->WriteServ("NOTICE %s :*** G-line %s not found in list, try /stats g.",user->nick.c_str(),target.c_str());
+ user->WriteNotice("*** G-Line " + target + " not found in list, try /stats g.");
}
}
return CMD_SUCCESS;
}
-
-COMMAND_INIT(CommandGline)
diff --git a/src/commands/cmd_kline.cpp b/src/coremods/core_xline/cmd_kline.cpp
index ce3642f91..50ab88398 100644
--- a/src/commands/cmd_kline.cpp
+++ b/src/coremods/core_xline/cmd_kline.cpp
@@ -20,27 +20,15 @@
#include "inspircd.h"
#include "xline.h"
+#include "core_xline.h"
-/** Handle /KLINE. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandKline : public Command
+CommandKline::CommandKline(Module* parent)
+ : Command(parent, "KLINE", 1, 3)
{
- public:
- /** Constructor for kline.
- */
- CommandKline ( Module* parent) : Command(parent,"KLINE",1,3) { flags_needed = 'o'; Penalty = 0; syntax = "<ident@host> [<duration> :<reason>]"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
-
+ flags_needed = 'o';
+ Penalty = 0;
+ syntax = "<ident@host> [<duration> :<reason>]";
+}
/** Handle /KLINE
*/
@@ -63,20 +51,21 @@ CmdResult CommandKline::Handle (const std::vector<std::string>& parameters, User
if (ih.first.empty())
{
- user->WriteServ("NOTICE %s :*** Target not found", user->nick.c_str());
+ user->WriteNotice("*** Target not found");
return CMD_FAILURE;
}
- if (ServerInstance->HostMatchesEveryone(ih.first+"@"+ih.second,user))
+ InsaneBan::IPHostMatcher matcher;
+ if (InsaneBan::MatchesEveryone(ih.first+"@"+ih.second, matcher, user, "K", "hostmasks"))
return CMD_FAILURE;
if (target.find('!') != std::string::npos)
{
- user->WriteServ("NOTICE %s :*** K-Line cannot operate on nick!user@host masks",user->nick.c_str());
+ user->WriteNotice("*** K-Line cannot operate on nick!user@host masks");
return CMD_FAILURE;
}
- long duration = ServerInstance->Duration(parameters[1].c_str());
+ unsigned long duration = InspIRCd::Duration(parameters[1]);
KLine* kl = new KLine(ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), ih.first.c_str(), ih.second.c_str());
if (ServerInstance->XLines->AddLine(kl,user))
{
@@ -87,7 +76,7 @@ CmdResult CommandKline::Handle (const std::vector<std::string>& parameters, User
else
{
time_t c_requires_crap = duration + ServerInstance->Time();
- std::string timestr = ServerInstance->TimeString(c_requires_crap);
+ std::string timestr = InspIRCd::TimeString(c_requires_crap);
ServerInstance->SNO->WriteToSnoMask('x',"%s added timed K-line for %s, expires on %s: %s",user->nick.c_str(),target.c_str(),
timestr.c_str(), parameters[2].c_str());
}
@@ -97,7 +86,7 @@ CmdResult CommandKline::Handle (const std::vector<std::string>& parameters, User
else
{
delete kl;
- user->WriteServ("NOTICE %s :*** K-Line for %s already exists",user->nick.c_str(),target.c_str());
+ user->WriteNotice("*** K-Line for " + target + " already exists");
}
}
else
@@ -108,11 +97,9 @@ CmdResult CommandKline::Handle (const std::vector<std::string>& parameters, User
}
else
{
- user->WriteServ("NOTICE %s :*** K-Line %s not found in list, try /stats k.",user->nick.c_str(),target.c_str());
+ user->WriteNotice("*** K-Line " + target + " not found in list, try /stats k.");
}
}
return CMD_SUCCESS;
}
-
-COMMAND_INIT(CommandKline)
diff --git a/src/commands/cmd_qline.cpp b/src/coremods/core_xline/cmd_qline.cpp
index 3118798e6..955efeaf0 100644
--- a/src/commands/cmd_qline.cpp
+++ b/src/coremods/core_xline/cmd_qline.cpp
@@ -21,38 +21,31 @@
#include "inspircd.h"
#include "xline.h"
+#include "core_xline.h"
-/** Handle /QLINE. */
-class CommandQline : public Command
+CommandQline::CommandQline(Module* parent)
+ : Command(parent, "QLINE", 1, 3)
{
- public:
- /** Constructor for qline.
- */
- CommandQline ( Module* parent) : Command(parent,"QLINE",1,3) { flags_needed = 'o'; Penalty = 0; syntax = "<nick> [<duration> :<reason>]"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to the command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
-
+ flags_needed = 'o';
+ Penalty = 0;
+ syntax = "<nick> [<duration> :<reason>]";
+}
CmdResult CommandQline::Handle (const std::vector<std::string>& parameters, User *user)
{
if (parameters.size() >= 3)
{
- if (ServerInstance->NickMatchesEveryone(parameters[0],user))
+ NickMatcher matcher;
+ if (InsaneBan::MatchesEveryone(parameters[0], matcher, user, "Q", "nickmasks"))
return CMD_FAILURE;
if (parameters[0].find('@') != std::string::npos || parameters[0].find('!') != std::string::npos || parameters[0].find('.') != std::string::npos)
{
- user->WriteServ("NOTICE %s :*** A Q-Line only bans a nick pattern, not a nick!user@host pattern.",user->nick.c_str());
+ user->WriteNotice("*** A Q-Line only bans a nick pattern, not a nick!user@host pattern.");
return CMD_FAILURE;
}
- long duration = ServerInstance->Duration(parameters[1].c_str());
+ unsigned long duration = InspIRCd::Duration(parameters[1]);
QLine* ql = new QLine(ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), parameters[0].c_str());
if (ServerInstance->XLines->AddLine(ql,user))
{
@@ -63,7 +56,7 @@ CmdResult CommandQline::Handle (const std::vector<std::string>& parameters, User
else
{
time_t c_requires_crap = duration + ServerInstance->Time();
- std::string timestr = ServerInstance->TimeString(c_requires_crap);
+ std::string timestr = InspIRCd::TimeString(c_requires_crap);
ServerInstance->SNO->WriteToSnoMask('x',"%s added timed Q-line for %s, expires on %s: %s",user->nick.c_str(),parameters[0].c_str(),
timestr.c_str(), parameters[2].c_str());
}
@@ -72,7 +65,7 @@ CmdResult CommandQline::Handle (const std::vector<std::string>& parameters, User
else
{
delete ql;
- user->WriteServ("NOTICE %s :*** Q-Line for %s already exists",user->nick.c_str(),parameters[0].c_str());
+ user->WriteNotice("*** Q-Line for " + parameters[0] + " already exists");
}
}
else
@@ -83,7 +76,7 @@ CmdResult CommandQline::Handle (const std::vector<std::string>& parameters, User
}
else
{
- user->WriteServ("NOTICE %s :*** Q-Line %s not found in list, try /stats q.",user->nick.c_str(),parameters[0].c_str());
+ user->WriteNotice("*** Q-Line " + parameters[0] + " not found in list, try /stats q.");
return CMD_FAILURE;
}
}
@@ -91,5 +84,7 @@ CmdResult CommandQline::Handle (const std::vector<std::string>& parameters, User
return CMD_SUCCESS;
}
-
-COMMAND_INIT(CommandQline)
+bool CommandQline::NickMatcher::Check(User* user, const std::string& nick) const
+{
+ return InspIRCd::Match(user->nick, nick);
+}
diff --git a/src/commands/cmd_zline.cpp b/src/coremods/core_xline/cmd_zline.cpp
index 91d9c6255..859be1004 100644
--- a/src/commands/cmd_zline.cpp
+++ b/src/coremods/core_xline/cmd_zline.cpp
@@ -21,25 +21,15 @@
#include "inspircd.h"
#include "xline.h"
-/** Handle /ZLINE. These command handlers can be reloaded by the core,
- * and handle basic RFC1459 commands. Commands within modules work
- * the same way, however, they can be fully unloaded, where these
- * may not.
- */
-class CommandZline : public Command
+#include "core_xline.h"
+
+CommandZline::CommandZline(Module* parent)
+ : Command(parent, "ZLINE", 1, 3)
{
- public:
- /** Constructor for zline.
- */
- CommandZline ( Module* parent) : Command(parent,"ZLINE",1,3) { flags_needed = 'o'; Penalty = 0; syntax = "<ipmask> [<duration> :<reason>]"; }
- /** Handle command.
- * @param parameters The parameters to the comamnd
- * @param pcnt The number of parameters passed to teh command
- * @param user The user issuing the command
- * @return A value from CmdResult to indicate command success or failure.
- */
- CmdResult Handle(const std::vector<std::string>& parameters, User *user);
-};
+ flags_needed = 'o';
+ Penalty = 0;
+ syntax = "<ipmask> [<duration> :<reason>]";
+}
CmdResult CommandZline::Handle (const std::vector<std::string>& parameters, User *user)
{
@@ -49,7 +39,7 @@ CmdResult CommandZline::Handle (const std::vector<std::string>& parameters, User
{
if (target.find('!') != std::string::npos)
{
- user->WriteServ("NOTICE %s :*** You cannot include a nickname in a zline, a zline must ban only an IP mask",user->nick.c_str());
+ user->WriteNotice("*** You cannot include a nickname in a zline, a zline must ban only an IP mask");
return CMD_FAILURE;
}
@@ -69,11 +59,11 @@ CmdResult CommandZline::Handle (const std::vector<std::string>& parameters, User
ipaddr++;
}
- if (ServerInstance->IPMatchesEveryone(ipaddr,user))
+ IPMatcher matcher;
+ if (InsaneBan::MatchesEveryone(ipaddr, matcher, user, "Z", "ipmasks"))
return CMD_FAILURE;
- long duration = ServerInstance->Duration(parameters[1].c_str());
-
+ unsigned long duration = InspIRCd::Duration(parameters[1]);
ZLine* zl = new ZLine(ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), ipaddr);
if (ServerInstance->XLines->AddLine(zl,user))
{
@@ -84,7 +74,7 @@ CmdResult CommandZline::Handle (const std::vector<std::string>& parameters, User
else
{
time_t c_requires_crap = duration + ServerInstance->Time();
- std::string timestr = ServerInstance->TimeString(c_requires_crap);
+ std::string timestr = InspIRCd::TimeString(c_requires_crap);
ServerInstance->SNO->WriteToSnoMask('x',"%s added timed Z-line for %s, expires on %s: %s",user->nick.c_str(),ipaddr,
timestr.c_str(), parameters[2].c_str());
}
@@ -93,7 +83,7 @@ CmdResult CommandZline::Handle (const std::vector<std::string>& parameters, User
else
{
delete zl;
- user->WriteServ("NOTICE %s :*** Z-Line for %s already exists",user->nick.c_str(),ipaddr);
+ user->WriteNotice("*** Z-Line for " + std::string(ipaddr) + " already exists");
}
}
else
@@ -104,7 +94,7 @@ CmdResult CommandZline::Handle (const std::vector<std::string>& parameters, User
}
else
{
- user->WriteServ("NOTICE %s :*** Z-Line %s not found in list, try /stats Z.",user->nick.c_str(),target.c_str());
+ user->WriteNotice("*** Z-Line " + target + " not found in list, try /stats Z.");
return CMD_FAILURE;
}
}
@@ -112,4 +102,7 @@ CmdResult CommandZline::Handle (const std::vector<std::string>& parameters, User
return CMD_SUCCESS;
}
-COMMAND_INIT(CommandZline)
+bool CommandZline::IPMatcher::Check(User* user, const std::string& ip) const
+{
+ return InspIRCd::Match(user->GetIPString(), ip, ascii_case_insensitive_map);
+}
diff --git a/src/coremods/core_xline/core_xline.cpp b/src/coremods/core_xline/core_xline.cpp
new file mode 100644
index 000000000..7fa7da019
--- /dev/null
+++ b/src/coremods/core_xline/core_xline.cpp
@@ -0,0 +1,93 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "xline.h"
+#include "core_xline.h"
+
+bool InsaneBan::MatchesEveryone(const std::string& mask, MatcherBase& test, User* user, const char* bantype, const char* confkey)
+{
+ ConfigTag* insane = ServerInstance->Config->ConfValue("insane");
+
+ if (insane->getBool(confkey))
+ return false;
+
+ float itrigger = insane->getFloat("trigger", 95.5);
+
+ long matches = test.Run(mask);
+
+ if (!matches)
+ return false;
+
+ float percent = ((float)matches / (float)ServerInstance->Users->GetUsers().size()) * 100;
+ if (percent > itrigger)
+ {
+ ServerInstance->SNO->WriteToSnoMask('a', "\2WARNING\2: %s tried to set a %s-line mask of %s, which covers %.2f%% of the network!", user->nick.c_str(), bantype, mask.c_str(), percent);
+ return true;
+ }
+ return false;
+}
+
+bool InsaneBan::IPHostMatcher::Check(User* user, const std::string& mask) const
+{
+ return ((InspIRCd::Match(user->MakeHost(), mask, ascii_case_insensitive_map)) ||
+ (InspIRCd::Match(user->MakeHostIP(), mask, ascii_case_insensitive_map)));
+}
+
+class CoreModXLine : public Module
+{
+ CommandEline cmdeline;
+ CommandGline cmdgline;
+ CommandKline cmdkline;
+ CommandQline cmdqline;
+ CommandZline cmdzline;
+
+ public:
+ CoreModXLine()
+ : cmdeline(this), cmdgline(this), cmdkline(this), cmdqline(this), cmdzline(this)
+ {
+ }
+
+ ModResult OnUserPreNick(LocalUser* user, const std::string& newnick) CXX11_OVERRIDE
+ {
+ // Check Q-Lines (for local nick changes only, remote servers have our Q-Lines to enforce themselves)
+
+ XLine* xline = ServerInstance->XLines->MatchesLine("Q", newnick);
+ if (!xline)
+ return MOD_RES_PASSTHRU; // No match
+
+ // A Q-Line matched the new nick, tell opers if the user is registered
+ if (user->registered == REG_ALL)
+ {
+ ServerInstance->SNO->WriteGlobalSno('a', "Q-Lined nickname %s from %s: %s",
+ newnick.c_str(), user->GetFullRealHost().c_str(), xline->reason.c_str());
+ }
+
+ // Send a numeric because if we deny then the core doesn't reply anything
+ user->WriteNumeric(ERR_ERRONEUSNICKNAME, "%s :Invalid nickname: %s", newnick.c_str(), xline->reason.c_str());
+ return MOD_RES_DENY;
+ }
+
+ Version GetVersion() CXX11_OVERRIDE
+ {
+ return Version("Provides the ELINE, GLINE, KLINE, QLINE, and ZLINE commands", VF_VENDOR|VF_CORE);
+ }
+};
+
+MODULE_INIT(CoreModXLine)
diff --git a/src/coremods/core_xline/core_xline.h b/src/coremods/core_xline/core_xline.h
new file mode 100644
index 000000000..d4ad498a0
--- /dev/null
+++ b/src/coremods/core_xline/core_xline.h
@@ -0,0 +1,164 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#pragma once
+
+#include "inspircd.h"
+
+class InsaneBan
+{
+ public:
+ class MatcherBase
+ {
+ public:
+ virtual long Run(const std::string& mask) = 0;
+ };
+
+ template <typename T>
+ class Matcher : public MatcherBase
+ {
+ public:
+ long Run(const std::string& mask)
+ {
+ long matches = 0;
+ const T* c = static_cast<T*>(this);
+ const user_hash& users = ServerInstance->Users->GetUsers();
+ for (user_hash::const_iterator i = users.begin(); i != users.end(); ++i)
+ {
+ if (c->Check(i->second, mask))
+ matches++;
+ }
+ return matches;
+ }
+ };
+
+ class IPHostMatcher : public Matcher<IPHostMatcher>
+ {
+ public:
+ bool Check(User* user, const std::string& mask) const;
+ };
+
+ /** Check if the given mask matches too many users according to the config, send an announcement if yes
+ * @param mask A mask to match against
+ * @param test The test that determines if a user matches the mask or not
+ * @param user A user whose nick will be included in the announcement if one is made
+ * @param bantype Type of the ban being set, will be used in the announcement if one is made
+ * @param confkey Name of the config key (inside the insane tag) which if false disables any checking
+ * @return True if the given mask matches too many users, false if not
+ */
+ static bool MatchesEveryone(const std::string& mask, MatcherBase& test, User* user, const char* bantype, const char* confkey);
+};
+
+/** Handle /ELINE.
+ */
+class CommandEline : public Command
+{
+ public:
+ /** Constructor for eline.
+ */
+ CommandEline(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user);
+};
+
+/** Handle /GLINE.
+ */
+class CommandGline : public Command
+{
+ public:
+ /** Constructor for gline.
+ */
+ CommandGline(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user);
+};
+
+/** Handle /KLINE.
+ */
+class CommandKline : public Command
+{
+ public:
+ /** Constructor for kline.
+ */
+ CommandKline(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user);
+};
+
+/** Handle /QLINE.
+ */
+class CommandQline : public Command
+{
+ class NickMatcher : public InsaneBan::Matcher<NickMatcher>
+ {
+ public:
+ bool Check(User* user, const std::string& mask) const;
+ };
+
+ public:
+ /** Constructor for qline.
+ */
+ CommandQline(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param pcnt The number of parameters passed to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user);
+};
+
+/** Handle /ZLINE.
+ */
+class CommandZline : public Command
+{
+ class IPMatcher : public InsaneBan::Matcher<IPMatcher>
+ {
+ public:
+ bool Check(User* user, const std::string& mask) const;
+ };
+
+ public:
+ /** Constructor for zline.
+ */
+ CommandZline(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user);
+};
diff --git a/src/cull_list.cpp b/src/cull_list.cpp
index 956ed3494..5cbe3aef3 100644
--- a/src/cull_list.cpp
+++ b/src/cull_list.cpp
@@ -46,14 +46,14 @@ void CullList::Apply()
classbase* c = list[i];
if (gone.insert(c).second)
{
- ServerInstance->Logs->Log("CULLLIST", DEBUG, "Deleting %s @%p", typeid(*c).name(),
+ ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "Deleting %s @%p", typeid(*c).name(),
(void*)c);
c->cull();
queue.push_back(c);
}
else
{
- ServerInstance->Logs->Log("CULLLIST",DEBUG, "WARNING: Object @%p culled twice!",
+ ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "WARNING: Object @%p culled twice!",
(void*)c);
}
}
@@ -65,7 +65,7 @@ void CullList::Apply()
}
if (list.size())
{
- ServerInstance->Logs->Log("CULLLIST",DEBUG, "WARNING: Objects added to cull list in a destructor");
+ ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "WARNING: Objects added to cull list in a destructor");
Apply();
}
}
diff --git a/src/dns.cpp b/src/dns.cpp
deleted file mode 100644
index 63bde0ecc..000000000
--- a/src/dns.cpp
+++ /dev/null
@@ -1,1110 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2012 William Pitcock <nenolod@dereferenced.org>
- * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2006, 2009 Robin Burchell <robin+git@viroteck.net>
- * Copyright (C) 2007, 2009 Dennis Friis <peavey@inspircd.org>
- * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
- * Copyright (C) 2005-2007 Craig Edwards <craigedwards@brainbox.cc>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-/* $Core */
-
-/*
-dns.cpp - Nonblocking DNS functions.
-Very very loosely based on the firedns library,
-Copyright (C) 2002 Ian Gulliver. This file is no
-longer anything like firedns, there are many major
-differences between this code and the original.
-Please do not assume that firedns works like this,
-looks like this, walks like this or tastes like this.
-*/
-
-#ifndef _WIN32
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <errno.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#else
-#include "inspircd_win32wrapper.h"
-#endif
-
-#include "inspircd.h"
-#include "socketengine.h"
-#include "configreader.h"
-#include "socket.h"
-
-#define DN_COMP_BITMASK 0xC000 /* highest 6 bits in a DN label header */
-
-/** Masks to mask off the responses we get from the DNSRequest methods
- */
-enum QueryInfo
-{
- ERROR_MASK = 0x10000 /* Result is an error */
-};
-
-/** Flags which can be ORed into a request or reply for different meanings
- */
-enum QueryFlags
-{
- FLAGS_MASK_RD = 0x01, /* Recursive */
- FLAGS_MASK_TC = 0x02,
- FLAGS_MASK_AA = 0x04, /* Authoritative */
- FLAGS_MASK_OPCODE = 0x78,
- FLAGS_MASK_QR = 0x80,
- FLAGS_MASK_RCODE = 0x0F, /* Request */
- FLAGS_MASK_Z = 0x70,
- FLAGS_MASK_RA = 0x80
-};
-
-
-/** Represents a dns resource record (rr)
- */
-struct ResourceRecord
-{
- QueryType type; /* Record type */
- unsigned int rr_class; /* Record class */
- unsigned long ttl; /* Time to live */
- unsigned int rdlength; /* Record length */
-};
-
-/** Represents a dns request/reply header, and its payload as opaque data.
- */
-class DNSHeader
-{
- public:
- unsigned char id[2]; /* Request id */
- unsigned int flags1; /* Flags */
- unsigned int flags2; /* Flags */
- unsigned int qdcount;
- unsigned int ancount; /* Answer count */
- unsigned int nscount; /* Nameserver count */
- unsigned int arcount;
- unsigned char payload[512]; /* Packet payload */
-};
-
-class DNSRequest
-{
- public:
- unsigned char id[2]; /* Request id */
- unsigned char* res; /* Result processing buffer */
- unsigned int rr_class; /* Request class */
- QueryType type; /* Request type */
- DNS* dnsobj; /* DNS caller (where we get our FD from) */
- unsigned long ttl; /* Time to live */
- std::string orig; /* Original requested name/ip */
-
- DNSRequest(DNS* dns, int id, const std::string &original);
- ~DNSRequest();
- DNSInfo ResultIsReady(DNSHeader &h, unsigned length);
- int SendRequests(const DNSHeader *header, const int length, QueryType qt);
-};
-
-class CacheTimer : public Timer
-{
- private:
- DNS* dns;
- public:
- CacheTimer(DNS* thisdns)
- : Timer(3600, ServerInstance->Time(), true), dns(thisdns) { }
-
- virtual void Tick(time_t)
- {
- dns->PruneCache();
- }
-};
-
-class RequestTimeout : public Timer
-{
- DNSRequest* watch;
- int watchid;
- public:
- RequestTimeout(unsigned long n, DNSRequest* watching, int id) : Timer(n, ServerInstance->Time()), watch(watching), watchid(id)
- {
- }
- ~RequestTimeout()
- {
- if (ServerInstance->Res)
- Tick(0);
- }
-
- void Tick(time_t)
- {
- if (ServerInstance->Res->requests[watchid] == watch)
- {
- /* Still exists, whack it */
- if (ServerInstance->Res->Classes[watchid])
- {
- ServerInstance->Res->Classes[watchid]->OnError(RESOLVER_TIMEOUT, "Request timed out");
- delete ServerInstance->Res->Classes[watchid];
- ServerInstance->Res->Classes[watchid] = NULL;
- }
- ServerInstance->Res->requests[watchid] = NULL;
- delete watch;
- }
- }
-};
-
-CachedQuery::CachedQuery(const std::string &res, unsigned int ttl) : data(res)
-{
- expires = ServerInstance->Time() + ttl;
-}
-
-int CachedQuery::CalcTTLRemaining()
-{
- int n = expires - ServerInstance->Time();
- return (n < 0 ? 0 : n);
-}
-
-/* Allocate the processing buffer */
-DNSRequest::DNSRequest(DNS* dns, int rid, const std::string &original) : dnsobj(dns)
-{
- /* hardening against overflow here: make our work buffer twice the theoretical
- * maximum size so that hostile input doesn't screw us over.
- */
- res = new unsigned char[sizeof(DNSHeader) * 2];
- *res = 0;
- orig = original;
- RequestTimeout* RT = new RequestTimeout(ServerInstance->Config->dns_timeout ? ServerInstance->Config->dns_timeout : 5, this, rid);
- ServerInstance->Timers->AddTimer(RT); /* The timer manager frees this */
-}
-
-/* Deallocate the processing buffer */
-DNSRequest::~DNSRequest()
-{
- delete[] res;
-}
-
-/** Fill a ResourceRecord class based on raw data input */
-inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
-{
- rr->type = (QueryType)((input[0] << 8) + input[1]);
- rr->rr_class = (input[2] << 8) + input[3];
- rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
- rr->rdlength = (input[8] << 8) + input[9];
-}
-
-/** Fill a DNSHeader class based on raw data input of a given length */
-inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
-{
- header->id[0] = input[0];
- header->id[1] = input[1];
- header->flags1 = input[2];
- header->flags2 = input[3];
- header->qdcount = (input[4] << 8) + input[5];
- header->ancount = (input[6] << 8) + input[7];
- header->nscount = (input[8] << 8) + input[9];
- header->arcount = (input[10] << 8) + input[11];
- memcpy(header->payload,&input[12],length);
-}
-
-/** Empty a DNSHeader class out into raw data, ready for transmission */
-inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
-{
- output[0] = header->id[0];
- output[1] = header->id[1];
- output[2] = header->flags1;
- output[3] = header->flags2;
- output[4] = header->qdcount >> 8;
- output[5] = header->qdcount & 0xFF;
- output[6] = header->ancount >> 8;
- output[7] = header->ancount & 0xFF;
- output[8] = header->nscount >> 8;
- output[9] = header->nscount & 0xFF;
- output[10] = header->arcount >> 8;
- output[11] = header->arcount & 0xFF;
- memcpy(&output[12],header->payload,length);
-}
-
-/** Send requests we have previously built down the UDP socket */
-int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
-{
- ServerInstance->Logs->Log("RESOLVER", DEBUG,"DNSRequest::SendRequests");
-
- unsigned char payload[sizeof(DNSHeader)];
-
- this->rr_class = 1;
- this->type = qt;
-
- DNS::EmptyHeader(payload,header,length);
-
- if (ServerInstance->SE->SendTo(dnsobj, payload, length + 12, 0, &(dnsobj->myserver.sa), sa_size(dnsobj->myserver)) != length+12)
- return -1;
-
- ServerInstance->Logs->Log("RESOLVER",DEBUG,"Sent OK");
- return 0;
-}
-
-/** Add a query with a predefined header, and allocate an ID for it. */
-DNSRequest* DNS::AddQuery(DNSHeader *header, int &id, const char* original)
-{
- /* Is the DNS connection down? */
- if (this->GetFd() == -1)
- return NULL;
-
- /* Create an id */
- unsigned int tries = 0;
- do {
- id = ServerInstance->GenRandomInt(DNS::MAX_REQUEST_ID);
- if (++tries == DNS::MAX_REQUEST_ID*5)
- {
- // If we couldn't find an empty slot this many times, do a sequential scan as a last
- // resort. If an empty slot is found that way, go on, otherwise throw an exception
- id = -1;
- for (int i = 0; i < DNS::MAX_REQUEST_ID; i++)
- {
- if (!requests[i])
- {
- id = i;
- break;
- }
- }
-
- if (id == -1)
- throw ModuleException("DNS: All ids are in use");
-
- break;
- }
- } while (requests[id]);
-
- DNSRequest* req = new DNSRequest(this, id, original);
-
- header->id[0] = req->id[0] = id >> 8;
- header->id[1] = req->id[1] = id & 0xFF;
- header->flags1 = FLAGS_MASK_RD;
- header->flags2 = 0;
- header->qdcount = 1;
- header->ancount = 0;
- header->nscount = 0;
- header->arcount = 0;
-
- /* At this point we already know the id doesnt exist,
- * so there needs to be no second check for the ::end()
- */
- requests[id] = req;
-
- /* According to the C++ spec, new never returns NULL. */
- return req;
-}
-
-int DNS::ClearCache()
-{
- /* This ensures the buckets are reset to sane levels */
- int rv = this->cache->size();
- delete this->cache;
- this->cache = new dnscache();
- return rv;
-}
-
-int DNS::PruneCache()
-{
- int n = 0;
- dnscache* newcache = new dnscache();
- for (dnscache::iterator i = this->cache->begin(); i != this->cache->end(); i++)
- /* Dont include expired items (theres no point) */
- if (i->second.CalcTTLRemaining())
- newcache->insert(*i);
- else
- n++;
-
- delete this->cache;
- this->cache = newcache;
- return n;
-}
-
-void DNS::Rehash()
-{
- if (this->GetFd() > -1)
- {
- ServerInstance->SE->DelFd(this);
- ServerInstance->SE->Shutdown(this, 2);
- ServerInstance->SE->Close(this);
- this->SetFd(-1);
-
- /* Rehash the cache */
- this->PruneCache();
- }
- else
- {
- /* Create initial dns cache */
- this->cache = new dnscache();
- }
-
- irc::sockets::aptosa(ServerInstance->Config->DNSServer, DNS::QUERY_PORT, myserver);
-
- /* Initialize mastersocket */
- int s = socket(myserver.sa.sa_family, SOCK_DGRAM, 0);
- this->SetFd(s);
-
- /* Have we got a socket and is it nonblocking? */
- if (this->GetFd() != -1)
- {
- ServerInstance->SE->SetReuse(s);
- ServerInstance->SE->NonBlocking(s);
- irc::sockets::sockaddrs bindto;
- memset(&bindto, 0, sizeof(bindto));
- bindto.sa.sa_family = myserver.sa.sa_family;
- if (ServerInstance->SE->Bind(this->GetFd(), bindto) < 0)
- {
- /* Failed to bind */
- ServerInstance->Logs->Log("RESOLVER",SPARSE,"Error binding dns socket - hostnames will NOT resolve");
- ServerInstance->SE->Shutdown(this, 2);
- ServerInstance->SE->Close(this);
- this->SetFd(-1);
- }
- else if (!ServerInstance->SE->AddFd(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE))
- {
- ServerInstance->Logs->Log("RESOLVER",SPARSE,"Internal error starting DNS - hostnames will NOT resolve.");
- ServerInstance->SE->Shutdown(this, 2);
- ServerInstance->SE->Close(this);
- this->SetFd(-1);
- }
- }
- else
- {
- ServerInstance->Logs->Log("RESOLVER",SPARSE,"Error creating DNS socket - hostnames will NOT resolve");
- }
-}
-
-/** Initialise the DNS UDP socket so that we can send requests */
-DNS::DNS()
-{
- ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::DNS");
- /* Clear the Resolver class table */
- memset(Classes,0,sizeof(Classes));
-
- /* Clear the requests class table */
- memset(requests,0,sizeof(requests));
-
- /* DNS::Rehash() sets this to a valid ptr
- */
- this->cache = NULL;
-
- /* Again, DNS::Rehash() sets this to a
- * valid value
- */
- this->SetFd(-1);
-
- /* Actually read the settings
- */
- this->Rehash();
-
- this->PruneTimer = new CacheTimer(this);
-
- ServerInstance->Timers->AddTimer(this->PruneTimer);
-}
-
-/** Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
-int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
-{
- short payloadpos = 0;
- const char* tempchr, *tempchr2 = name;
- unsigned short length;
-
- /* split name up into labels, create query */
- while ((tempchr = strchr(tempchr2,'.')) != NULL)
- {
- length = tempchr - tempchr2;
- if (payloadpos + length + 1 > 507)
- return -1;
- payload[payloadpos++] = length;
- memcpy(&payload[payloadpos],tempchr2,length);
- payloadpos += length;
- tempchr2 = &tempchr[1];
- }
- length = strlen(tempchr2);
- if (length)
- {
- if (payloadpos + length + 2 > 507)
- return -1;
- payload[payloadpos++] = length;
- memcpy(&payload[payloadpos],tempchr2,length);
- payloadpos += length;
- payload[payloadpos++] = 0;
- }
- if (payloadpos > 508)
- return -1;
- length = htons(rr);
- memcpy(&payload[payloadpos],&length,2);
- length = htons(rr_class);
- memcpy(&payload[payloadpos + 2],&length,2);
- return payloadpos + 4;
-}
-
-/** Start lookup of an hostname to an IP address */
-int DNS::GetIP(const char *name)
-{
- DNSHeader h;
- int id;
- int length;
-
- if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
- return -1;
-
- DNSRequest* req = this->AddQuery(&h, id, name);
-
- if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
- return -1;
-
- return id;
-}
-
-/** Start lookup of an hostname to an IPv6 address */
-int DNS::GetIP6(const char *name)
-{
- DNSHeader h;
- int id;
- int length;
-
- if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
- return -1;
-
- DNSRequest* req = this->AddQuery(&h, id, name);
-
- if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
- return -1;
-
- return id;
-}
-
-/** Start lookup of a cname to another name */
-int DNS::GetCName(const char *alias)
-{
- DNSHeader h;
- int id;
- int length;
-
- if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
- return -1;
-
- DNSRequest* req = this->AddQuery(&h, id, alias);
-
- if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
- return -1;
-
- return id;
-}
-
-/** Start lookup of an IP address to a hostname */
-int DNS::GetNameForce(const char *ip, ForceProtocol fp)
-{
- char query[128];
- DNSHeader h;
- int id;
- int length;
-
- if (fp == PROTOCOL_IPV6)
- {
- in6_addr i;
- if (inet_pton(AF_INET6, ip, &i) > 0)
- {
- DNS::MakeIP6Int(query, &i);
- }
- else
- {
- ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce IPv6 bad format for '%s'", ip);
- /* Invalid IP address */
- return -1;
- }
- }
- else
- {
- in_addr i;
- if (inet_aton(ip, &i))
- {
- unsigned char* c = (unsigned char*)&i.s_addr;
- sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
- }
- else
- {
- ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce IPv4 bad format for '%s'", ip);
- /* Invalid IP address */
- return -1;
- }
- }
-
- length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload);
- if (length == -1)
- {
- ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce can't query '%s' using '%s' because it's too long", ip, query);
- return -1;
- }
-
- DNSRequest* req = this->AddQuery(&h, id, ip);
-
- if (!req)
- {
- ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce can't add query (resolver down?)");
- return -1;
- }
-
- if (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1)
- {
- ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce can't send (firewall?)");
- return -1;
- }
-
- return id;
-}
-
-/** Build an ipv6 reverse domain from an in6_addr
- */
-void DNS::MakeIP6Int(char* query, const in6_addr *ip)
-{
- const char* hex = "0123456789abcdef";
- for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
- {
- if (index % 2)
- /* low nibble */
- *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
- else
- /* high nibble */
- *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
- *query++ = '.'; /* Seperator */
- }
- strcpy(query,"ip6.arpa"); /* Suffix the string */
-}
-
-/** Return the next id which is ready, and the result attached to it */
-DNSResult DNS::GetResult()
-{
- /* Fetch dns query response and decide where it belongs */
- DNSHeader header;
- DNSRequest *req;
- unsigned char buffer[sizeof(DNSHeader)];
- irc::sockets::sockaddrs from;
- memset(&from, 0, sizeof(from));
- socklen_t x = sizeof(from);
-
- int length = ServerInstance->SE->RecvFrom(this, (char*)buffer, sizeof(DNSHeader), 0, &from.sa, &x);
-
- /* Did we get the whole header? */
- if (length < 12)
- {
- ServerInstance->Logs->Log("RESOLVER",DEBUG,"GetResult didn't get a full packet (len=%d)", length);
- /* Nope - something screwed up. */
- return DNSResult(-1,"",0,"");
- }
-
- /* Check wether the reply came from a different DNS
- * server to the one we sent it to, or the source-port
- * is not 53.
- * A user could in theory still spoof dns packets anyway
- * but this is less trivial than just sending garbage
- * to the server, which is possible without this check.
- *
- * -- Thanks jilles for pointing this one out.
- */
- if (from != myserver)
- {
- std::string server1 = from.str();
- std::string server2 = myserver.str();
- ServerInstance->Logs->Log("RESOLVER",DEBUG,"Got a result from the wrong server! Bad NAT or DNS forging attempt? '%s' != '%s'",
- server1.c_str(), server2.c_str());
- return DNSResult(-1,"",0,"");
- }
-
- /* Put the read header info into a header class */
- DNS::FillHeader(&header,buffer,length - 12);
-
- /* Get the id of this request.
- * Its a 16 bit value stored in two char's,
- * so we use logic shifts to create the value.
- */
- unsigned long this_id = header.id[1] + (header.id[0] << 8);
-
- /* Do we have a pending request matching this id? */
- if (!requests[this_id])
- {
- /* Somehow we got a DNS response for a request we never made... */
- ServerInstance->Logs->Log("RESOLVER",DEBUG,"Hmm, got a result that we didn't ask for (id=%lx). Ignoring.", this_id);
- return DNSResult(-1,"",0,"");
- }
- else
- {
- /* Remove the query from the list of pending queries */
- req = requests[this_id];
- requests[this_id] = NULL;
- }
-
- /* Inform the DNSRequest class that it has a result to be read.
- * When its finished it will return a DNSInfo which is a pair of
- * unsigned char* resource record data, and an error message.
- */
- DNSInfo data = req->ResultIsReady(header, length);
- std::string resultstr;
-
- /* Check if we got a result, if we didnt, its an error */
- if (data.first == NULL)
- {
- /* An error.
- * Mask the ID with the value of ERROR_MASK, so that
- * the dns_deal_with_classes() function knows that its
- * an error response and needs to be treated uniquely.
- * Put the error message in the second field.
- */
- std::string ro = req->orig;
- delete req;
- return DNSResult(this_id | ERROR_MASK, data.second, 0, ro);
- }
- else
- {
- unsigned long ttl = req->ttl;
- char formatted[128];
-
- /* Forward lookups come back as binary data. We must format them into ascii */
- switch (req->type)
- {
- case DNS_QUERY_A:
- snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
- resultstr = formatted;
- break;
-
- case DNS_QUERY_AAAA:
- {
- inet_ntop(AF_INET6, data.first, formatted, sizeof(formatted));
- char* c = strstr(formatted,":0:");
- if (c != NULL)
- {
- memmove(c+1,c+2,strlen(c+2) + 1);
- c += 2;
- while (memcmp(c,"0:",2) == 0)
- memmove(c,c+2,strlen(c+2) + 1);
- if (memcmp(c,"0",2) == 0)
- *c = 0;
- if (memcmp(formatted,"0::",3) == 0)
- memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
- }
- resultstr = formatted;
-
- /* Special case. Sending ::1 around between servers
- * and to clients is dangerous, because the : on the
- * start makes the client or server interpret the IP
- * as the last parameter on the line with a value ":1".
- */
- if (*formatted == ':')
- resultstr.insert(0, "0");
- }
- break;
-
- case DNS_QUERY_CNAME:
- /* Identical handling to PTR */
-
- case DNS_QUERY_PTR:
- /* Reverse lookups just come back as char* */
- resultstr = std::string((const char*)data.first);
- break;
-
- default:
- break;
- }
-
- /* Build the reply with the id and hostname/ip in it */
- std::string ro = req->orig;
- delete req;
- return DNSResult(this_id,resultstr,ttl,ro);
- }
-}
-
-/** A result is ready, process it */
-DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, unsigned length)
-{
- unsigned i = 0, o;
- int q = 0;
- int curanswer;
- ResourceRecord rr;
- unsigned short ptr;
-
- /* This is just to keep _FORTIFY_SOURCE happy */
- rr.type = DNS_QUERY_NONE;
- rr.rdlength = 0;
- rr.ttl = 1; /* GCC is a whiney bastard -- see the XXX below. */
- rr.rr_class = 0; /* Same for VC++ */
-
- if (!(header.flags1 & FLAGS_MASK_QR))
- return std::make_pair((unsigned char*)NULL,"Not a query result");
-
- if (header.flags1 & FLAGS_MASK_OPCODE)
- return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
-
- if (header.flags2 & FLAGS_MASK_RCODE)
- return std::make_pair((unsigned char*)NULL,"Domain name not found");
-
- if (header.ancount < 1)
- return std::make_pair((unsigned char*)NULL,"No resource records returned");
-
- /* Subtract the length of the header from the length of the packet */
- length -= 12;
-
- while ((unsigned int)q < header.qdcount && i < length)
- {
- if (header.payload[i] > 63)
- {
- i += 6;
- q++;
- }
- else
- {
- if (header.payload[i] == 0)
- {
- q++;
- i += 5;
- }
- else i += header.payload[i] + 1;
- }
- }
- curanswer = 0;
- while ((unsigned)curanswer < header.ancount)
- {
- q = 0;
- while (q == 0 && i < length)
- {
- if (header.payload[i] > 63)
- {
- i += 2;
- q = 1;
- }
- else
- {
- if (header.payload[i] == 0)
- {
- i++;
- q = 1;
- }
- else i += header.payload[i] + 1; /* skip length and label */
- }
- }
- if (static_cast<int>(length - i) < 10)
- return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
-
- /* XXX: We actually initialise 'rr' here including its ttl field */
- DNS::FillResourceRecord(&rr,&header.payload[i]);
-
- i += 10;
- ServerInstance->Logs->Log("RESOLVER",DEBUG,"Resolver: rr.type is %d and this.type is %d rr.class %d this.class %d", rr.type, this->type, rr.rr_class, this->rr_class);
- if (rr.type != this->type)
- {
- curanswer++;
- i += rr.rdlength;
- continue;
- }
- if (rr.rr_class != this->rr_class)
- {
- curanswer++;
- i += rr.rdlength;
- continue;
- }
- break;
- }
- if ((unsigned int)curanswer == header.ancount)
- return std::make_pair((unsigned char*)NULL,"No A, AAAA or PTR type answers (" + ConvToStr(header.ancount) + " answers)");
-
- if (i + rr.rdlength > (unsigned int)length)
- return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
-
- if (rr.rdlength > 1023)
- return std::make_pair((unsigned char*)NULL,"Resource record too large");
-
- this->ttl = rr.ttl;
-
- switch (rr.type)
- {
- /*
- * CNAME and PTR are compressed. We need to decompress them.
- */
- case DNS_QUERY_CNAME:
- case DNS_QUERY_PTR:
- {
- unsigned short lowest_pos = length;
- o = 0;
- q = 0;
- while (q == 0 && i < length && o + 256 < 1023)
- {
- /* DN label found (byte over 63) */
- if (header.payload[i] > 63)
- {
- memcpy(&ptr,&header.payload[i],2);
-
- i = ntohs(ptr);
-
- /* check that highest two bits are set. if not, we've been had */
- if ((i & DN_COMP_BITMASK) != DN_COMP_BITMASK)
- return std::make_pair((unsigned char *) NULL, "DN label decompression header is bogus");
-
- /* mask away the two highest bits. */
- i &= ~DN_COMP_BITMASK;
-
- /* and decrease length by 12 bytes. */
- i -= 12;
-
- if (i >= lowest_pos)
- return std::make_pair((unsigned char *) NULL, "Invalid decompression pointer");
- lowest_pos = i;
- }
- else
- {
- if (header.payload[i] == 0)
- {
- q = 1;
- }
- else
- {
- res[o] = 0;
- if (o != 0)
- res[o++] = '.';
-
- if (o + header.payload[i] > sizeof(DNSHeader))
- return std::make_pair((unsigned char *) NULL, "DN label decompression is impossible -- malformed/hostile packet?");
-
- memcpy(&res[o], &header.payload[i + 1], header.payload[i]);
- o += header.payload[i];
- i += header.payload[i] + 1;
- }
- }
- }
- res[o] = 0;
- }
- break;
- case DNS_QUERY_AAAA:
- if (rr.rdlength != sizeof(struct in6_addr))
- return std::make_pair((unsigned char *) NULL, "rr.rdlength is larger than 16 bytes for an ipv6 entry -- malformed/hostile packet?");
-
- memcpy(res,&header.payload[i],rr.rdlength);
- res[rr.rdlength] = 0;
- break;
- case DNS_QUERY_A:
- if (rr.rdlength != sizeof(struct in_addr))
- return std::make_pair((unsigned char *) NULL, "rr.rdlength is larger than 4 bytes for an ipv4 entry -- malformed/hostile packet?");
-
- memcpy(res,&header.payload[i],rr.rdlength);
- res[rr.rdlength] = 0;
- break;
- default:
- return std::make_pair((unsigned char *) NULL, "don't know how to handle undefined type (" + ConvToStr(rr.type) + ") -- rejecting");
- break;
- }
- return std::make_pair(res,"No error");
-}
-
-/** Close the master socket */
-DNS::~DNS()
-{
- ServerInstance->SE->Shutdown(this, 2);
- ServerInstance->SE->Close(this);
- ServerInstance->Timers->DelTimer(this->PruneTimer);
- if (cache)
- delete cache;
-}
-
-CachedQuery* DNS::GetCache(const std::string &source)
-{
- dnscache::iterator x = cache->find(source.c_str());
- if (x != cache->end())
- return &(x->second);
- else
- return NULL;
-}
-
-void DNS::DelCache(const std::string &source)
-{
- cache->erase(source.c_str());
-}
-
-void Resolver::TriggerCachedResult()
-{
- if (CQ)
- OnLookupComplete(CQ->data, time_left, true);
-}
-
-/** High level abstraction of dns used by application at large */
-Resolver::Resolver(const std::string &source, QueryType qt, bool &cached, Module* creator) : Creator(creator), input(source), querytype(qt)
-{
- ServerInstance->Logs->Log("RESOLVER",DEBUG,"Resolver::Resolver");
- cached = false;
-
- CQ = ServerInstance->Res->GetCache(source);
- if (CQ)
- {
- time_left = CQ->CalcTTLRemaining();
- if (!time_left)
- {
- ServerInstance->Res->DelCache(source);
- }
- else
- {
- cached = true;
- return;
- }
- }
-
- switch (querytype)
- {
- case DNS_QUERY_A:
- this->myid = ServerInstance->Res->GetIP(source.c_str());
- break;
-
- case DNS_QUERY_PTR4:
- querytype = DNS_QUERY_PTR;
- this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
- break;
-
- case DNS_QUERY_PTR6:
- querytype = DNS_QUERY_PTR;
- this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
- break;
-
- case DNS_QUERY_AAAA:
- this->myid = ServerInstance->Res->GetIP6(source.c_str());
- break;
-
- case DNS_QUERY_CNAME:
- this->myid = ServerInstance->Res->GetCName(source.c_str());
- break;
-
- default:
- ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS request with unknown query type %d", querytype);
- this->myid = -1;
- break;
- }
- if (this->myid == -1)
- {
- throw ModuleException("Resolver: Couldn't get an id to make a request");
- }
- else
- {
- ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS request id %d", this->myid);
- }
-}
-
-/** Called when an error occurs */
-void Resolver::OnError(ResolverError, const std::string&)
-{
- /* Nothing in here */
-}
-
-/** Destroy a resolver */
-Resolver::~Resolver()
-{
- /* Nothing here (yet) either */
-}
-
-/** Get the request id associated with this class */
-int Resolver::GetId()
-{
- return this->myid;
-}
-
-Module* Resolver::GetCreator()
-{
- return this->Creator;
-}
-
-/** Process a socket read event */
-void DNS::HandleEvent(EventType, int)
-{
- /* Fetch the id and result of the next available packet */
- DNSResult res(0,"",0,"");
- res.id = 0;
- ServerInstance->Logs->Log("RESOLVER",DEBUG,"Handle DNS event");
-
- res = this->GetResult();
-
- ServerInstance->Logs->Log("RESOLVER",DEBUG,"Result id %d", res.id);
-
- /* Is there a usable request id? */
- if (res.id != -1)
- {
- /* Its an error reply */
- if (res.id & ERROR_MASK)
- {
- /* Mask off the error bit */
- res.id -= ERROR_MASK;
- /* Marshall the error to the correct class */
- if (Classes[res.id])
- {
- if (ServerInstance && ServerInstance->stats)
- ServerInstance->stats->statsDnsBad++;
- Classes[res.id]->OnError(RESOLVER_NXDOMAIN, res.result);
- delete Classes[res.id];
- Classes[res.id] = NULL;
- }
- return;
- }
- else
- {
- /* It is a non-error result, marshall the result to the correct class */
- if (Classes[res.id])
- {
- if (ServerInstance && ServerInstance->stats)
- ServerInstance->stats->statsDnsGood++;
-
- if (!this->GetCache(res.original.c_str()))
- this->cache->insert(std::make_pair(res.original.c_str(), CachedQuery(res.result, res.ttl)));
-
- Classes[res.id]->OnLookupComplete(res.result, res.ttl, false);
- delete Classes[res.id];
- Classes[res.id] = NULL;
- }
- }
-
- if (ServerInstance && ServerInstance->stats)
- ServerInstance->stats->statsDns++;
- }
-}
-
-/** Add a derived Resolver to the working set */
-bool DNS::AddResolverClass(Resolver* r)
-{
- ServerInstance->Logs->Log("RESOLVER",DEBUG,"AddResolverClass 0x%08lx", (unsigned long)r);
- /* Check the pointers validity and the id's validity */
- if ((r) && (r->GetId() > -1))
- {
- /* Check the slot isnt already occupied -
- * This should NEVER happen unless we have
- * a severely broken DNS server somewhere
- */
- if (!Classes[r->GetId()])
- {
- /* Set up the pointer to the class */
- Classes[r->GetId()] = r;
- return true;
- }
- }
-
- /* Pointer or id not valid, or duplicate id.
- * Free the item and return
- */
- delete r;
- return false;
-}
-
-void DNS::CleanResolvers(Module* module)
-{
- for (int i = 0; i < MAX_REQUEST_ID; i++)
- {
- if (Classes[i])
- {
- if (Classes[i]->GetCreator() == module)
- {
- Classes[i]->OnError(RESOLVER_FORCEUNLOAD, "Parent module is unloading");
- delete Classes[i];
- Classes[i] = NULL;
- }
- }
- }
-}
diff --git a/src/dynamic.cpp b/src/dynamic.cpp
index 3a6a151cb..9984f4dbe 100644
--- a/src/dynamic.cpp
+++ b/src/dynamic.cpp
@@ -22,7 +22,7 @@
#include "inspircd.h"
-#include "dynamic.h"
+
#ifndef _WIN32
#include <dlfcn.h>
#else
diff --git a/src/filelogger.cpp b/src/filelogger.cpp
index 0575256d0..5786758da 100644
--- a/src/filelogger.cpp
+++ b/src/filelogger.cpp
@@ -19,15 +19,10 @@
*/
-/* $Core */
-
#include "inspircd.h"
#include <fstream>
-#include "socketengine.h"
-#include "filelogger.h"
-FileLogStream::FileLogStream(int loglevel, FileWriter *fw)
- : LogStream(loglevel), f(fw)
+FileLogStream::FileLogStream(LogLevel loglevel, FileWriter *fw) : LogStream(loglevel), f(fw)
{
ServerInstance->Logs->AddLoggerRef(f);
}
@@ -38,9 +33,9 @@ FileLogStream::~FileLogStream()
ServerInstance->Logs->DelLoggerRef(f);
}
-void FileLogStream::OnLog(int loglevel, const std::string &type, const std::string &text)
+void FileLogStream::OnLog(LogLevel loglevel, const std::string &type, const std::string &text)
{
- static char TIMESTR[26];
+ static std::string TIMESTR;
static time_t LAST = 0;
if (loglevel < this->loglvl)
@@ -50,14 +45,9 @@ void FileLogStream::OnLog(int loglevel, const std::string &type, const std::stri
if (ServerInstance->Time() != LAST)
{
- time_t local = ServerInstance->Time();
- struct tm *timeinfo = localtime(&local);
-
- strlcpy(TIMESTR,asctime(timeinfo),26);
- TIMESTR[24] = ':';
+ TIMESTR = InspIRCd::TimeString(ServerInstance->Time());
LAST = ServerInstance->Time();
}
- std::string out = std::string(TIMESTR) + " " + text.c_str() + "\n";
- this->f->WriteLogLine(out);
+ this->f->WriteLogLine(TIMESTR + " " + type + ": " + text + "\n");
}
diff --git a/src/fileutils.cpp b/src/fileutils.cpp
new file mode 100644
index 000000000..731e4ea01
--- /dev/null
+++ b/src/fileutils.cpp
@@ -0,0 +1,102 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2013 Peter Powell <petpow@saberuk.com>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+
+#include <fstream>
+
+FileReader::FileReader(const std::string& filename)
+{
+ Load(filename);
+}
+
+void FileReader::Load(const std::string& filename)
+{
+ // If the file is stored in the file cache then we used that version instead.
+ ConfigFileCache::const_iterator it = ServerInstance->Config->Files.find(filename);
+ if (it != ServerInstance->Config->Files.end())
+ {
+ this->lines = it->second;
+ }
+ else
+ {
+ const std::string realName = ServerInstance->Config->Paths.PrependConfig(filename);
+ lines.clear();
+
+ std::ifstream stream(realName.c_str());
+ if (!stream.is_open())
+ throw CoreException(filename + " does not exist or is not readable!");
+
+ std::string line;
+ while (std::getline(stream, line))
+ {
+ lines.push_back(line);
+ totalSize += line.size() + 2;
+ }
+
+ stream.close();
+ }
+}
+
+std::string FileReader::GetString() const
+{
+ std::string buffer;
+ for (file_cache::const_iterator it = this->lines.begin(); it != this->lines.end(); ++it)
+ {
+ buffer.append(*it);
+ buffer.append("\r\n");
+ }
+ return buffer;
+}
+
+std::string FileSystem::ExpandPath(const std::string& base, const std::string& fragment)
+{
+ // The fragment is an absolute path, don't modify it.
+ if (fragment[0] == '/' || FileSystem::StartsWithWindowsDriveLetter(fragment))
+ return fragment;
+
+ return base + '/' + fragment;
+}
+
+bool FileSystem::FileExists(const std::string& file)
+{
+ struct stat sb;
+ if (stat(file.c_str(), &sb) == -1)
+ return false;
+
+ if ((sb.st_mode & S_IFDIR) > 0)
+ return false;
+
+ return !access(file.c_str(), F_OK);
+}
+
+std::string FileSystem::GetFileName(const std::string& name)
+{
+#ifdef _WIN32
+ size_t pos = name.find_last_of("\\/");
+#else
+ size_t pos = name.rfind('/');
+#endif
+ return pos == std::string::npos ? name : name.substr(++pos);
+}
+
+bool FileSystem::StartsWithWindowsDriveLetter(const std::string& path)
+{
+ return (path.length() > 2 && isalpha(path[0]) && path[1] == ':');
+}
diff --git a/src/hashcomp.cpp b/src/hashcomp.cpp
index 3fb7f84fb..895b500ae 100644
--- a/src/hashcomp.cpp
+++ b/src/hashcomp.cpp
@@ -20,11 +20,7 @@
*/
-/* $Core */
-
#include "inspircd.h"
-#include "hashcomp.h"
-#include "hash_map.h"
/******************************************************
*
@@ -35,7 +31,7 @@
* scene spend a lot of time debating (arguing) about
* the best way to write hash functions to hash irc
* nicknames, channels etc.
- * We are lucky as C++ developers as hash_map does
+ * We are lucky as C++ developers as unordered_map does
* a lot of this for us. It does intellegent memory
* requests, bucketing, search functions, insertion
* and deletion etc. All we have to do is write some
@@ -51,101 +47,109 @@
*
******************************************************/
-/** A mapping of uppercase to lowercase, including scandinavian
- * 'oddities' as specified by RFC1459, e.g. { -> [, and | -> \
- */
-unsigned const char rfc_case_insensitive_map[256] = {
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 0-19 */
- 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, /* 20-39 */
- 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, /* 40-59 */
- 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, /* 60-79 */
- 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 94, 95, 96, 97, 98, 99, /* 80-99 */
- 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, /* 100-119 */
- 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, /* 120-139 */
- 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, /* 140-159 */
- 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, /* 160-179 */
- 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, /* 180-199 */
- 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, /* 200-219 */
- 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, /* 220-239 */
- 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 /* 240-255 */
-};
-/** Case insensitive map, ASCII rules.
- * That is;
- * [ != {, but A == a.
+/**
+ * A case insensitive mapping of characters from upper case to lower case for
+ * the ASCII character set.
*/
unsigned const char ascii_case_insensitive_map[256] = {
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 0-19 */
- 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, /* 20-39 */
- 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, /* 40-59 */
- 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, /* 60-79 */
- 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, /* 80-99 */
- 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, /* 100-119 */
- 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, /* 120-139 */
- 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, /* 140-159 */
- 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, /* 160-179 */
- 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, /* 180-199 */
- 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, /* 200-219 */
- 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, /* 220-239 */
- 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 /* 240-255 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // 0-9
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 10-19
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, // 20-29
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, // 30-39
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, // 40-49
+ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, // 50-59
+ 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, // 60-69
+ 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, // 70-79
+ 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, // 80-89
+ 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, // 90-99
+ 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, // 100-109
+ 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, // 110-119
+ 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, // 120-129
+ 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, // 130-139
+ 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, // 140-149
+ 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, // 150-159
+ 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, // 160-169
+ 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, // 170-179
+ 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, // 180-189
+ 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, // 190-199
+ 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, // 200-209
+ 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, // 210-219
+ 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, // 220-229
+ 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, // 230-249
+ 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, // 240-249
+ 250, 251, 252, 253, 254, 255, // 250-255
};
-/** Case sensitive map.
- * Can technically also be used for ASCII case sensitive comparisons, as [ != {, etc.
+
+
+/**
+ * A case insensitive mapping of characters from upper case to lower case for
+ * the character set of RFC 1459. This is identical to ASCII with the small
+ * exception of {}| being considered to be the lower case equivalents of the
+ * characters []\ respectively.
*/
-unsigned const char rfc_case_sensitive_map[256] = {
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
- 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
- 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
- 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100,
- 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
- 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140,
- 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160,
- 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
- 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200,
- 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220,
- 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240,
- 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
+unsigned const char rfc_case_insensitive_map[256] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // 0-9
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 10-19
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, // 20-29
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, // 30-39
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, // 40-49
+ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, // 50-59
+ 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, // 60-69
+ 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, // 70-79
+ 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, // 80-89
+ 122, 123, 124, 125, 94, 95, 96, 97, 98, 99, // 90-99
+ 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, // 100-109
+ 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, // 110-119
+ 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, // 120-129
+ 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, // 130-139
+ 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, // 140-149
+ 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, // 150-159
+ 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, // 160-169
+ 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, // 170-179
+ 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, // 180-189
+ 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, // 190-199
+ 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, // 200-209
+ 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, // 210-219
+ 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, // 220-229
+ 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, // 230-239
+ 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, // 240-249
+ 250, 251, 252, 253, 254, 255, // 250-255
};
-/* convert a string to lowercase. Note following special circumstances
- * taken from RFC 1459. Many "official" server branches still hold to this
- * rule so i will too;
- *
- * Because of IRC's scandanavian origin, the characters {}| are
- * considered to be the lower case equivalents of the characters []\,
- * respectively. This is a critical issue when determining the
- * equivalence of two nicknames.
+/**
+ * A case sensitive mapping of characters from upper case to lower case for the
+ * character set of RFC 1459. This is identical to ASCII.
*/
-void nspace::strlower(char *n)
-{
- if (n)
- {
- for (char* t = n; *t; t++)
- *t = national_case_insensitive_map[(unsigned char)*t];
- }
-}
-
-#ifdef HASHMAP_DEPRECATED
- size_t CoreExport nspace::insensitive::operator()(const std::string &s) const
-#else
- size_t nspace::hash<std::string>::operator()(const std::string &s) const
-#endif
-
-{
- /* XXX: NO DATA COPIES! :)
- * The hash function here is practically
- * a copy of the one in STL's hash_fun.h,
- * only with *x replaced with national_case_insensitive_map[*x].
- * This avoids a copy to use hash<const char*>
- */
- register size_t t = 0;
- for (std::string::const_iterator x = s.begin(); x != s.end(); ++x) /* ++x not x++, as its faster */
- t = 5 * t + national_case_insensitive_map[(unsigned char)*x];
- return t;
-}
-
+unsigned const char rfc_case_sensitive_map[256] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // 0-9
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 10-19
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, // 20-29
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, // 30-39
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, // 40-49
+ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, // 50-59
+ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, // 60-69
+ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 70-79
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, // 80-89
+ 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, // 90-99
+ 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, // 100-109
+ 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, // 110-119
+ 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, // 120-129
+ 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, // 130-139
+ 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, // 140-149
+ 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, // 150-159
+ 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, // 160-169
+ 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, // 170-179
+ 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, // 180-189
+ 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, // 190-199
+ 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, // 200-209
+ 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, // 210-219
+ 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, // 220-229
+ 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, // 230-239
+ 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, // 240-249
+ 250, 251, 252, 253, 254, 255, // 250-255
+};
size_t CoreExport irc::hash::operator()(const irc::string &s) const
{
@@ -165,6 +169,39 @@ bool irc::StrHashComp::operator()(const std::string& s1, const std::string& s2)
return (national_case_insensitive_map[*n1] == national_case_insensitive_map[*n2]);
}
+bool irc::insensitive_swo::operator()(const std::string& a, const std::string& b) const
+{
+ const unsigned char* charmap = national_case_insensitive_map;
+ std::string::size_type asize = a.size();
+ std::string::size_type bsize = b.size();
+ std::string::size_type maxsize = std::min(asize, bsize);
+
+ for (std::string::size_type i = 0; i < maxsize; i++)
+ {
+ unsigned char A = charmap[(unsigned char)a[i]];
+ unsigned char B = charmap[(unsigned char)b[i]];
+ if (A > B)
+ return false;
+ else if (A < B)
+ return true;
+ }
+ return (asize < bsize);
+}
+
+size_t irc::insensitive::operator()(const std::string &s) const
+{
+ /* XXX: NO DATA COPIES! :)
+ * The hash function here is practically
+ * a copy of the one in STL's hash_fun.h,
+ * only with *x replaced with national_case_insensitive_map[*x].
+ * This avoids a copy to use hash<const char*>
+ */
+ register size_t t = 0;
+ for (std::string::const_iterator x = s.begin(); x != s.end(); ++x) /* ++x not x++, as its faster */
+ t = 5 * t + national_case_insensitive_map[(unsigned char)*x];
+ return t;
+}
+
/******************************************************
*
* This is the implementation of our special irc::string
@@ -217,60 +254,30 @@ const char* irc::irc_char_traits::find(const char* s1, int n, char c)
return (n >= 0) ? s1 : NULL;
}
-irc::tokenstream::tokenstream(const std::string &source) : tokens(source), last_pushed(false)
-{
- /* Record starting position and current position */
- last_starting_position = tokens.begin();
- n = tokens.begin();
-}
-
-irc::tokenstream::~tokenstream()
+irc::tokenstream::tokenstream(const std::string &source) : spacesepstream(source)
{
}
bool irc::tokenstream::GetToken(std::string &token)
{
- std::string::iterator lsp = last_starting_position;
-
- while (n != tokens.end())
- {
- /** Skip multi space, converting " " into " "
- */
- while ((n+1 != tokens.end()) && (*n == ' ') && (*(n+1) == ' '))
- n++;
+ bool first = !pos;
- if ((last_pushed) && (*n == ':'))
- {
- /* If we find a token thats not the first and starts with :,
- * this is the last token on the line
- */
- std::string::iterator curr = ++n;
- n = tokens.end();
- token = std::string(curr, tokens.end());
- return true;
- }
-
- last_pushed = false;
+ if (!spacesepstream::GetToken(token))
+ return false;
- if ((*n == ' ') || (n+1 == tokens.end()))
+ /* This is the last parameter */
+ if (token[0] == ':' && !first)
+ {
+ token = token.substr(1);
+ if (!StreamEnd())
{
- /* If we find a space, or end of string, this is the end of a token.
- */
- last_starting_position = n+1;
- last_pushed = *n == ' ';
-
- std::string strip(lsp, n+1 == tokens.end() ? n+1 : n++);
- while ((strip.length()) && (strip.find_last_of(' ') == strip.length() - 1))
- strip.erase(strip.end() - 1);
-
- token = strip;
- return !token.empty();
+ token += ' ';
+ token += GetRemaining();
}
-
- n++;
+ pos = tokens.length() + 1;
}
- token.clear();
- return false;
+
+ return true;
}
bool irc::tokenstream::GetToken(irc::string &token)
@@ -297,85 +304,50 @@ bool irc::tokenstream::GetToken(long &token)
return returnval;
}
-irc::sepstream::sepstream(const std::string &source, char seperator) : tokens(source), sep(seperator)
+irc::sepstream::sepstream(const std::string& source, char separator, bool allowempty)
+ : tokens(source), sep(separator), pos(0), allow_empty(allowempty)
{
- last_starting_position = tokens.begin();
- n = tokens.begin();
}
bool irc::sepstream::GetToken(std::string &token)
{
- std::string::iterator lsp = last_starting_position;
+ if (this->StreamEnd())
+ {
+ token.clear();
+ return false;
+ }
- while (n != tokens.end())
+ if (!this->allow_empty)
{
- if ((*n == sep) || (n+1 == tokens.end()))
+ this->pos = this->tokens.find_first_not_of(this->sep, this->pos);
+ if (this->pos == std::string::npos)
{
- last_starting_position = n+1;
- token = std::string(lsp, n+1 == tokens.end() ? n+1 : n++);
-
- while ((token.length()) && (token.find_last_of(sep) == token.length() - 1))
- token.erase(token.end() - 1);
-
- if (token.empty())
- n++;
-
- return n == tokens.end() ? false : true;
+ this->pos = this->tokens.length() + 1;
+ token.clear();
+ return false;
}
-
- n++;
}
- token.clear();
- return false;
-}
-
-const std::string irc::sepstream::GetRemaining()
-{
- return std::string(n, tokens.end());
-}
+ size_t p = this->tokens.find(this->sep, this->pos);
+ if (p == std::string::npos)
+ p = this->tokens.length();
-bool irc::sepstream::StreamEnd()
-{
- return ((n + 1) == tokens.end());
-}
+ token = this->tokens.substr(this->pos, p - this->pos);
+ this->pos = p + 1;
-irc::sepstream::~sepstream()
-{
+ return true;
}
-std::string irc::hex(const unsigned char *raw, size_t rawsz)
+const std::string irc::sepstream::GetRemaining()
{
- if (!rawsz)
- return "";
-
- /* EWW! This used to be using sprintf, which is WAY inefficient. -Special */
-
- const char *hex = "0123456789abcdef";
- static char hexbuf[MAXBUF];
-
- size_t i, j;
- for (i = 0, j = 0; j < rawsz; ++j)
- {
- hexbuf[i++] = hex[raw[j] / 16];
- hexbuf[i++] = hex[raw[j] % 16];
- }
- hexbuf[i] = 0;
-
- return hexbuf;
+ return !this->StreamEnd() ? this->tokens.substr(this->pos) : "";
}
-CoreExport const char* irc::Spacify(const char* n)
+bool irc::sepstream::StreamEnd()
{
- static char x[MAXBUF];
- strlcpy(x,n,MAXBUF);
- for (char* y = x; *y; y++)
- if (*y == '_')
- *y = ' ';
- return x;
+ return this->pos > this->tokens.length();
}
-
irc::modestacker::modestacker(bool add) : adding(add)
{
sequence.clear();
@@ -441,38 +413,15 @@ int irc::modestacker::GetStackedLine(std::vector<std::string> &result, int max_l
return n;
}
-irc::stringjoiner::stringjoiner(const std::string &seperator, const std::vector<std::string> &sequence, int begin, int end)
+std::string irc::stringjoiner(const std::vector<std::string>& sequence, char separator)
{
- if (end < begin)
- return; // nothing to do here
-
- for (int v = begin; v < end; v++)
- joined.append(sequence[v]).append(seperator);
- joined.append(sequence[end]);
-}
-
-irc::stringjoiner::stringjoiner(const std::string &seperator, const std::deque<std::string> &sequence, int begin, int end)
-{
- if (end < begin)
- return; // nothing to do here
-
- for (int v = begin; v < end; v++)
- joined.append(sequence[v]).append(seperator);
- joined.append(sequence[end]);
-}
-
-irc::stringjoiner::stringjoiner(const std::string &seperator, const char* const* sequence, int begin, int end)
-{
- if (end < begin)
- return; // nothing to do here
-
- for (int v = begin; v < end; v++)
- joined.append(sequence[v]).append(seperator);
- joined.append(sequence[end]);
-}
+ std::string joined;
+ if (sequence.empty())
+ return joined; // nothing to do here
-std::string& irc::stringjoiner::GetJoined()
-{
+ for (std::vector<std::string>::const_iterator i = sequence.begin(); i != sequence.end(); ++i)
+ joined.append(*i).push_back(separator);
+ joined.erase(joined.end()-1);
return joined;
}
@@ -549,25 +498,3 @@ long irc::portparser::GetToken()
return atoi(x.c_str());
}
}
-
-/*const std::basic_string& SearchAndReplace(std::string& text, const std::string& pattern, const std::string& replace)
-{
- std::string replacement;
- if ((!pattern.empty()) && (!text.empty()))
- {
- for (std::string::size_type n = 0; n != text.length(); ++n)
- {
- if (text.length() >= pattern.length() && text.substr(n, pattern.length()) == pattern)
- {
- replacement.append(replace);
- n = n + pattern.length() - 1;
- }
- else
- {
- replacement += text[n];
- }
- }
- }
- text = replacement;
- return text;
-}*/
diff --git a/src/helperfuncs.cpp b/src/helperfuncs.cpp
index 439320c1e..7b2a29f77 100644
--- a/src/helperfuncs.cpp
+++ b/src/helperfuncs.cpp
@@ -22,8 +22,6 @@
*/
-/* $Core */
-
#ifdef _WIN32
#define _CRT_RAND_S
#include <stdlib.h>
@@ -34,66 +32,26 @@
#include "exitcodes.h"
#include <iostream>
-std::string InspIRCd::GetServerDescription(const std::string& servername)
-{
- std::string description;
-
- FOREACH_MOD(I_OnGetServerDescription,OnGetServerDescription(servername,description));
-
- if (!description.empty())
- {
- return description;
- }
- else
- {
- // not a remote server that can be found, it must be me.
- return Config->ServerDesc;
- }
-}
-
/* Find a user record by nickname and return a pointer to it */
User* InspIRCd::FindNick(const std::string &nick)
{
if (!nick.empty() && isdigit(*nick.begin()))
return FindUUID(nick);
- user_hash::iterator iter = this->Users->clientlist->find(nick);
+ user_hash::iterator iter = this->Users->clientlist.find(nick);
- if (iter == this->Users->clientlist->end())
+ if (iter == this->Users->clientlist.end())
/* Couldn't find it */
return NULL;
return iter->second;
}
-User* InspIRCd::FindNick(const char* nick)
-{
- if (isdigit(*nick))
- return FindUUID(nick);
-
- user_hash::iterator iter = this->Users->clientlist->find(nick);
-
- if (iter == this->Users->clientlist->end())
- return NULL;
-
- return iter->second;
-}
-
User* InspIRCd::FindNickOnly(const std::string &nick)
{
- user_hash::iterator iter = this->Users->clientlist->find(nick);
-
- if (iter == this->Users->clientlist->end())
- return NULL;
-
- return iter->second;
-}
-
-User* InspIRCd::FindNickOnly(const char* nick)
-{
- user_hash::iterator iter = this->Users->clientlist->find(nick);
+ user_hash::iterator iter = this->Users->clientlist.find(nick);
- if (iter == this->Users->clientlist->end())
+ if (iter == this->Users->clientlist.end())
return NULL;
return iter->second;
@@ -101,36 +59,20 @@ User* InspIRCd::FindNickOnly(const char* nick)
User *InspIRCd::FindUUID(const std::string &uid)
{
- user_hash::iterator finduuid = this->Users->uuidlist->find(uid);
+ user_hash::iterator finduuid = this->Users->uuidlist.find(uid);
- if (finduuid == this->Users->uuidlist->end())
+ if (finduuid == this->Users->uuidlist.end())
return NULL;
return finduuid->second;
}
-
-User *InspIRCd::FindUUID(const char *uid)
-{
- return FindUUID(std::string(uid));
-}
-
/* find a channel record by channel name and return a pointer to it */
-Channel* InspIRCd::FindChan(const char* chan)
-{
- chan_hash::iterator iter = chanlist->find(chan);
-
- if (iter == chanlist->end())
- /* Couldn't find it */
- return NULL;
-
- return iter->second;
-}
Channel* InspIRCd::FindChan(const std::string &chan)
{
- chan_hash::iterator iter = chanlist->find(chan);
+ chan_hash::iterator iter = chanlist.find(chan);
- if (iter == chanlist->end())
+ if (iter == chanlist.end())
/* Couldn't find it */
return NULL;
@@ -140,13 +82,14 @@ Channel* InspIRCd::FindChan(const std::string &chan)
/* Send an error notice to all users, registered or not */
void InspIRCd::SendError(const std::string &s)
{
- for (LocalUserList::const_iterator i = this->Users->local_users.begin(); i != this->Users->local_users.end(); i++)
+ const UserManager::LocalList& list = Users.GetLocalUsers();
+ for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i)
{
User* u = *i;
if (u->registered == REG_ALL)
{
- u->WriteServ("NOTICE %s :%s",u->nick.c_str(),s.c_str());
- }
+ u->WriteNotice(s);
+ }
else
{
/* Unregistered connections receive ERROR, not a NOTICE */
@@ -155,12 +98,6 @@ void InspIRCd::SendError(const std::string &s)
}
}
-/* return channel count */
-long InspIRCd::ChannelCount()
-{
- return chanlist->size();
-}
-
bool InspIRCd::IsValidMask(const std::string &mask)
{
const char* dest = mask.c_str();
@@ -281,47 +218,35 @@ void InspIRCd::ProcessColors(file_cache& input)
}
/* true for valid channel name, false else */
-bool IsChannelHandler::Call(const char *chname, size_t max)
+bool IsChannelHandler::Call(const std::string& chname)
{
- const char *c = chname + 1;
+ if (chname.empty() || chname.length() > ServerInstance->Config->Limits.ChanMax)
+ return false;
- /* check for no name - don't check for !*chname, as if it is empty, it won't be '#'! */
- if (!chname || *chname != '#')
- {
+ if (chname[0] != '#')
return false;
- }
- while (*c)
+ for (std::string::const_iterator i = chname.begin()+1; i != chname.end(); ++i)
{
- switch (*c)
+ switch (*i)
{
case ' ':
case ',':
case 7:
return false;
}
-
- c++;
- }
-
- size_t len = c - chname;
- /* too long a name - note funky pointer arithmetic here. */
- if (len > max)
- {
- return false;
}
return true;
}
/* true for valid nickname, false else */
-bool IsNickHandler::Call(const char* n, size_t max)
+bool IsNickHandler::Call(const std::string& n)
{
- if (!n || !*n)
+ if (n.empty() || n.length() > ServerInstance->Config->Limits.NickMax)
return false;
- unsigned int p = 0;
- for (const char* i = n; *i; i++, p++)
+ for (std::string::const_iterator i = n.begin(); i != n.end(); ++i)
{
if ((*i >= 'A') && (*i <= '}'))
{
@@ -329,7 +254,7 @@ bool IsNickHandler::Call(const char* n, size_t max)
continue;
}
- if ((((*i >= '0') && (*i <= '9')) || (*i == '-')) && (i > n))
+ if ((((*i >= '0') && (*i <= '9')) || (*i == '-')) && (i != n.begin()))
{
/* "0"-"9", "-" can occur anywhere BUT the first char of a nickname */
continue;
@@ -339,17 +264,16 @@ bool IsNickHandler::Call(const char* n, size_t max)
return false;
}
- /* too long? or not */
- return (p <= max);
+ return true;
}
/* return true for good ident, false else */
-bool IsIdentHandler::Call(const char* n)
+bool IsIdentHandler::Call(const std::string& n)
{
- if (!n || !*n)
+ if (n.empty())
return false;
- for (const char* i = n; *i; i++)
+ for (std::string::const_iterator i = n.begin(); i != n.end(); ++i)
{
if ((*i >= 'A') && (*i <= '}'))
{
@@ -367,7 +291,7 @@ bool IsIdentHandler::Call(const char* n)
return true;
}
-bool IsSIDHandler::Call(const std::string &str)
+bool InspIRCd::IsSID(const std::string &str)
{
/* Returns true if the string given is exactly 3 characters long,
* starts with a digit, and the other two characters are A-Z or digits
@@ -377,35 +301,13 @@ bool IsSIDHandler::Call(const std::string &str)
((str[2] >= 'A' && str[2] <= 'Z') || isdigit(str[2])));
}
-/* open the proper logfile */
-bool InspIRCd::OpenLog(char**, int)
-{
- if (!Config->cmdline.writelog) return true; // Skip opening default log if -nolog
-
- if (Config->cmdline.startup_log.empty())
- Config->cmdline.startup_log = LOG_PATH "/startup.log";
- FILE* startup = fopen(Config->cmdline.startup_log.c_str(), "a+");
-
- if (!startup)
- {
- return false;
- }
-
- FileWriter* fw = new FileWriter(startup);
- FileLogStream *f = new FileLogStream((Config->cmdline.forcedebug ? DEBUG : DEFAULT), fw);
-
- this->Logs->AddLogType("*", f, true);
-
- return true;
-}
-
void InspIRCd::CheckRoot()
{
#ifndef _WIN32
if (geteuid() == 0)
{
std::cout << "ERROR: You are running an irc server as root! DO NOT DO THIS!" << std::endl << std::endl;
- this->Logs->Log("STARTUP",DEFAULT,"Can't start as root");
+ this->Logs->Log("STARTUP", LOG_DEFAULT, "Can't start as root");
Exit(EXIT_STATUS_ROOT);
}
#endif
@@ -419,24 +321,20 @@ void InspIRCd::SendWhoisLine(User* user, User* dest, int numeric, const std::str
FIRST_MOD_RESULT(OnWhoisLine, MOD_RESULT, (user, dest, numeric, copy_text));
if (MOD_RESULT != MOD_RES_DENY)
- user->WriteServ("%d %s", numeric, copy_text.c_str());
+ user->WriteNumeric(numeric, copy_text);
}
void InspIRCd::SendWhoisLine(User* user, User* dest, int numeric, const char* format, ...)
{
- char textbuffer[MAXBUF];
- va_list argsPtr;
- va_start (argsPtr, format);
- vsnprintf(textbuffer, MAXBUF, format, argsPtr);
- va_end(argsPtr);
-
- this->SendWhoisLine(user, dest, numeric, std::string(textbuffer));
+ std::string textbuffer;
+ VAFORMAT(textbuffer, format, format)
+ this->SendWhoisLine(user, dest, numeric, textbuffer);
}
/** Refactored by Brain, Jun 2009. Much faster with some clever O(1) array
* lookups and pointer maths.
*/
-long InspIRCd::Duration(const std::string &str)
+unsigned long InspIRCd::Duration(const std::string &str)
{
unsigned char multiplier = 0;
long total = 0;
@@ -476,31 +374,44 @@ long InspIRCd::Duration(const std::string &str)
return total + subtotal;
}
-bool InspIRCd::ULine(const std::string& sserver)
+const char* InspIRCd::Format(va_list &vaList, const char* formatString)
{
- if (sserver.empty())
- return true;
+ static std::vector<char> formatBuffer(1024);
+
+ while (true)
+ {
+ va_list dst;
+ va_copy(dst, vaList);
+
+ int vsnret = vsnprintf(&formatBuffer[0], formatBuffer.size(), formatString, dst);
+ va_end(dst);
+
+ if (vsnret > 0 && static_cast<unsigned>(vsnret) < formatBuffer.size())
+ {
+ break;
+ }
- return (Config->ulines.find(sserver.c_str()) != Config->ulines.end());
+ formatBuffer.resize(formatBuffer.size() * 2);
+ }
+
+ return &formatBuffer[0];
}
-bool InspIRCd::SilentULine(const std::string& sserver)
+const char* InspIRCd::Format(const char* formatString, ...)
{
- std::map<irc::string,bool>::iterator n = Config->ulines.find(sserver.c_str());
- if (n != Config->ulines.end())
- return n->second;
- else
- return false;
+ const char* ret;
+ VAFORMAT(ret, formatString, formatString);
+ return ret;
}
-std::string InspIRCd::TimeString(time_t curtime)
+std::string InspIRCd::TimeString(time_t curtime, const char* format, bool utc)
{
#ifdef _WIN32
if (curtime < 0)
curtime = 0;
#endif
- struct tm* timeinfo = localtime(&curtime);
+ struct tm* timeinfo = utc ? gmtime(&curtime) : localtime(&curtime);
if (!timeinfo)
{
curtime = 0;
@@ -514,27 +425,15 @@ std::string InspIRCd::TimeString(time_t curtime)
else if (timeinfo->tm_year + 1900 < 1000)
timeinfo->tm_year = 0;
- return std::string(asctime(timeinfo),24);
-}
+ // This is the default format used by asctime without the terminating new line.
+ if (!format)
+ format = "%a %b %d %H:%M:%S %Y";
-// You should only pass a single character to this.
-void InspIRCd::AddExtBanChar(char c)
-{
- std::string &tok = Config->data005;
- std::string::size_type ebpos = tok.find(" EXTBAN=,");
+ char buffer[512];
+ if (!strftime(buffer, sizeof(buffer), format, timeinfo))
+ buffer[0] = '\0';
- if (ebpos == std::string::npos)
- {
- tok.append(" EXTBAN=,");
- tok.push_back(c);
- }
- else
- {
- ebpos += 9;
- while (isalpha(tok[ebpos]) && tok[ebpos] < c)
- ebpos++;
- tok.insert(ebpos, 1, c);
- }
+ return buffer;
}
std::string InspIRCd::GenRandomStr(int length, bool printable)
@@ -588,11 +487,11 @@ ModResult OnCheckExemptionHandler::Call(User* user, Channel* chan, const std::st
std::string::size_type pos = current.find(':');
if (pos == std::string::npos)
continue;
- if (current.substr(0,pos) == restriction)
+ if (!current.compare(0, pos, restriction))
minmode = current[pos+1];
}
- ModeHandler* mh = ServerInstance->Modes->FindMode(minmode, MODETYPE_CHANNEL);
+ PrefixMode* mh = ServerInstance->Modes->FindPrefixMode(minmode);
if (mh && mypfx >= mh->GetPrefixRank())
return MOD_RES_ALLOW;
if (mh || minmode == '*')
diff --git a/src/inspircd.cpp b/src/inspircd.cpp
index 766aeaf8e..403ba5355 100644
--- a/src/inspircd.cpp
+++ b/src/inspircd.cpp
@@ -26,9 +26,7 @@
*/
-/* $Core */
#include "inspircd.h"
-#include "inspircd_version.h"
#include <signal.h>
#ifndef _WIN32
@@ -54,12 +52,7 @@
#include <fstream>
#include <iostream>
#include "xline.h"
-#include "bancache.h"
-#include "socketengine.h"
-#include "socket.h"
-#include "command_parse.h"
#include "exitcodes.h"
-#include "caller.h"
#include "testsuite.h"
InspIRCd* ServerInstance = NULL;
@@ -78,28 +71,26 @@ unsigned const char *national_case_insensitive_map = rfc_case_insensitive_map;
*/
const char* ExitCodes[] =
{
- "No error", /* 0 */
- "DIE command", /* 1 */
- "execv() failed", /* 2 */
- "Internal error", /* 3 */
- "Config file error", /* 4 */
- "Logfile error", /* 5 */
- "POSIX fork failed", /* 6 */
- "Bad commandline parameters", /* 7 */
- "No ports could be bound", /* 8 */
- "Can't write PID file", /* 9 */
- "SocketEngine could not initialize", /* 10 */
- "Refusing to start up as root", /* 11 */
- "Found a <die> tag!", /* 12 */
- "Couldn't load module on startup", /* 13 */
- "Could not create windows forked process", /* 14 */
- "Received SIGTERM", /* 15 */
- "Bad command handler loaded", /* 16 */
- "RegisterServiceCtrlHandler failed", /* 17 */
- "UpdateSCMStatus failed", /* 18 */
- "CreateEvent failed" /* 19 */
+ "No error", // 0
+ "DIE command", // 1
+ "Config file error", // 2
+ "Logfile error", // 3
+ "POSIX fork failed", // 4
+ "Bad commandline parameters", // 5
+ "Can't write PID file", // 6
+ "SocketEngine could not initialize", // 7
+ "Refusing to start up as root", // 8
+ "Couldn't load module on startup", // 9
+ "Received SIGTERM" // 10
};
+#ifdef INSPIRCD_ENABLE_TESTSUITE
+/** True if we have been told to run the testsuite from the commandline,
+ * rather than entering the mainloop.
+ */
+static int do_testsuite = 0;
+#endif
+
template<typename T> static void DeleteZero(T*&n)
{
T* t = n;
@@ -109,21 +100,18 @@ template<typename T> static void DeleteZero(T*&n)
void InspIRCd::Cleanup()
{
+ // Close all listening sockets
for (unsigned int i = 0; i < ports.size(); i++)
{
- /* This calls the constructor and closes the listening socket */
ports[i]->cull();
delete ports[i];
}
ports.clear();
/* Close all client sockets, or the new process inherits them */
- LocalUserList::reverse_iterator i = Users->local_users.rbegin();
- while (i != this->Users->local_users.rend())
- {
- User* u = *i++;
- Users->QuitUser(u, "Server shutdown");
- }
+ const UserManager::LocalList& list = Users.GetLocalUsers();
+ for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i)
+ Users->QuitUser(*i, "Server shutdown");
GlobalCulls.Apply();
Modules->UnloadAll();
@@ -131,98 +119,15 @@ void InspIRCd::Cleanup()
/* Delete objects dynamically allocated in constructor (destructor would be more appropriate, but we're likely exiting) */
/* Must be deleted before modes as it decrements modelines */
if (FakeClient)
+ {
+ delete FakeClient->server;
FakeClient->cull();
- if (Res)
- Res->cull();
+ }
DeleteZero(this->FakeClient);
- DeleteZero(this->Users);
- DeleteZero(this->Modes);
DeleteZero(this->XLines);
- DeleteZero(this->Parser);
- DeleteZero(this->stats);
- DeleteZero(this->Modules);
- DeleteZero(this->BanCache);
- DeleteZero(this->SNO);
DeleteZero(this->Config);
- DeleteZero(this->Res);
- DeleteZero(this->chanlist);
- DeleteZero(this->PI);
- DeleteZero(this->Threads);
- DeleteZero(this->Timers);
- DeleteZero(this->SE);
- /* Close logging */
- this->Logs->CloseLogs();
- DeleteZero(this->Logs);
-}
-
-void InspIRCd::Restart(const std::string &reason)
-{
- /* SendError flushes each client's queue,
- * regardless of writeability state
- */
- this->SendError(reason);
-
- /* Figure out our filename (if theyve renamed it, we're boned) */
- std::string me;
-
- char** argv = Config->cmdline.argv;
-
-#ifdef _WIN32
- char module[MAX_PATH];
- if (GetModuleFileNameA(NULL, module, MAX_PATH))
- me = module;
-#else
- me = argv[0];
-#endif
-
- this->Cleanup();
-
- if (execv(me.c_str(), argv) == -1)
- {
- /* Will raise a SIGABRT if not trapped */
- throw CoreException(std::string("Failed to execv()! error: ") + strerror(errno));
- }
-}
-
-void InspIRCd::ResetMaxBans()
-{
- for (chan_hash::const_iterator i = chanlist->begin(); i != chanlist->end(); i++)
- i->second->ResetMaxBans();
-}
-
-/** Because hash_map doesn't free its buckets when we delete items, we occasionally
- * recreate the hash to free them up.
- * We do this by copying the entries from the old hash to a new hash, causing all
- * empty buckets to be weeded out of the hash.
- * Since this is quite expensive, it's not done very often.
- */
-void InspIRCd::RehashUsersAndChans()
-{
- user_hash* old_users = Users->clientlist;
- Users->clientlist = new user_hash;
- for (user_hash::const_iterator n = old_users->begin(); n != old_users->end(); n++)
- Users->clientlist->insert(*n);
- delete old_users;
-
- user_hash* old_uuid = Users->uuidlist;
- Users->uuidlist = new user_hash;
- for (user_hash::const_iterator n = old_uuid->begin(); n != old_uuid->end(); n++)
- Users->uuidlist->insert(*n);
- delete old_uuid;
-
- chan_hash* old_chans = chanlist;
- chanlist = new chan_hash;
- for (chan_hash::const_iterator n = old_chans->begin(); n != old_chans->end(); n++)
- chanlist->insert(*n);
- delete old_chans;
-
- // Reset the already_sent IDs so we don't wrap it around and drop a message
- LocalUser::already_sent_id = 0;
- for (LocalUserList::const_iterator i = Users->local_users.begin(); i != Users->local_users.end(); i++)
- {
- (**i).already_sent = 0;
- (**i).RemoveExpiredInvites();
- }
+ SocketEngine::Deinit();
+ Logs->CloseLogs();
}
void InspIRCd::SetSignals()
@@ -258,8 +163,8 @@ bool InspIRCd::DaemonSeed()
// Do not use QuickExit here: It will exit with status SIGTERM which would break e.g. daemon scripts
signal(SIGTERM, VoidSignalHandler);
- int childpid;
- if ((childpid = fork ()) < 0)
+ int childpid = fork();
+ if (childpid < 0)
return false;
else if (childpid > 0)
{
@@ -282,13 +187,13 @@ bool InspIRCd::DaemonSeed()
rlimit rl;
if (getrlimit(RLIMIT_CORE, &rl) == -1)
{
- this->Logs->Log("STARTUP",DEFAULT,"Failed to getrlimit()!");
+ this->Logs->Log("STARTUP", LOG_DEFAULT, "Failed to getrlimit()!");
return false;
}
rl.rlim_cur = rl.rlim_max;
if (setrlimit(RLIMIT_CORE, &rl) == -1)
- this->Logs->Log("STARTUP",DEFAULT,"setrlimit() failed, cannot increase coredump size.");
+ this->Logs->Log("STARTUP", LOG_DEFAULT, "setrlimit() failed, cannot increase coredump size.");
return true;
#endif
@@ -299,7 +204,7 @@ void InspIRCd::WritePID(const std::string &filename)
#ifndef _WIN32
std::string fname(filename);
if (fname.empty())
- fname = DATA_PATH "/inspircd.pid";
+ fname = ServerInstance->Config->Paths.PrependData("inspircd.pid");
std::ofstream outfile(fname.c_str());
if (outfile.is_open())
{
@@ -309,89 +214,50 @@ void InspIRCd::WritePID(const std::string &filename)
else
{
std::cout << "Failed to write PID-file '" << fname << "', exiting." << std::endl;
- this->Logs->Log("STARTUP",DEFAULT,"Failed to write PID-file '%s', exiting.",fname.c_str());
+ this->Logs->Log("STARTUP", LOG_DEFAULT, "Failed to write PID-file '%s', exiting.",fname.c_str());
Exit(EXIT_STATUS_PID);
}
#endif
}
InspIRCd::InspIRCd(int argc, char** argv) :
- ConfigFileName(CONFIG_PATH "/inspircd.conf"),
+ ConfigFileName(INSPIRCD_CONFIG_PATH "/inspircd.conf"),
+ PI(&DefaultProtocolInterface),
/* Functor pointer initialisation.
*
* THIS MUST MATCH THE ORDER OF DECLARATION OF THE FUNCTORS, e.g. the methods
* themselves within the class.
*/
- NICKForced("NICKForced", NULL),
- OperQuit("OperQuit", NULL),
+ OperQuit("operquit", NULL),
GenRandom(&HandleGenRandom),
IsChannel(&HandleIsChannel),
- IsSID(&HandleIsSID),
- Rehash(&HandleRehash),
IsNick(&HandleIsNick),
IsIdent(&HandleIsIdent),
- FloodQuitUser(&HandleFloodQuitUser),
OnCheckExemption(&HandleOnCheckExemption)
{
ServerInstance = this;
- Extensions.Register(&NICKForced);
Extensions.Register(&OperQuit);
FailedPortList pl;
+ // Flag variables passed to getopt_long() later
int do_version = 0, do_nofork = 0, do_debug = 0,
- do_nolog = 0, do_root = 0, do_testsuite = 0; /* flag variables */
- int c = 0;
+ do_nolog = 0, do_root = 0;
// Initialize so that if we exit before proper initialization they're not deleted
- this->Logs = 0;
- this->Threads = 0;
- this->PI = 0;
- this->Users = 0;
- this->chanlist = 0;
this->Config = 0;
- this->SNO = 0;
- this->BanCache = 0;
- this->Modules = 0;
- this->stats = 0;
- this->Timers = 0;
- this->Parser = 0;
this->XLines = 0;
- this->Modes = 0;
- this->Res = 0;
this->ConfigThread = NULL;
this->FakeClient = NULL;
UpdateTime();
this->startup_time = TIME.tv_sec;
- // This must be created first, so other parts of Insp can use it while starting up
- this->Logs = new LogManager;
-
- SE = CreateSocketEngine();
-
- this->Threads = new ThreadEngine;
-
- /* Default implementation does nothing */
- this->PI = new ProtocolInterface;
-
- this->s_signal = 0;
-
- // Create base manager classes early, so nothing breaks
- this->Users = new UserManager;
-
- this->Users->clientlist = new user_hash();
- this->Users->uuidlist = new user_hash();
- this->chanlist = new chan_hash();
+ SocketEngine::Init();
this->Config = new ServerConfig;
- this->SNO = new SnomaskManager;
- this->BanCache = new BanCacheManager;
- this->Modules = new ModuleManager();
- this->stats = new serverstats();
- this->Timers = new TimerManager;
- this->Parser = new CommandParser;
+ dynamic_reference_base::reset_all();
this->XLines = new XLineManager;
this->Config->cmdline.argv = argv;
@@ -420,28 +286,26 @@ InspIRCd::InspIRCd(int argc, char** argv) :
struct option longopts[] =
{
{ "nofork", no_argument, &do_nofork, 1 },
- { "logfile", required_argument, NULL, 'f' },
{ "config", required_argument, NULL, 'c' },
{ "debug", no_argument, &do_debug, 1 },
{ "nolog", no_argument, &do_nolog, 1 },
{ "runasroot", no_argument, &do_root, 1 },
{ "version", no_argument, &do_version, 1 },
+#ifdef INSPIRCD_ENABLE_TESTSUITE
{ "testsuite", no_argument, &do_testsuite, 1 },
+#endif
{ 0, 0, 0, 0 }
};
+ int c;
int index;
- while ((c = getopt_long(argc, argv, ":c:f:", longopts, &index)) != -1)
+ while ((c = getopt_long(argc, argv, ":c:", longopts, &index)) != -1)
{
switch (c)
{
- case 'f':
- /* Log filename was set */
- Config->cmdline.startup_log = optarg;
- break;
case 'c':
/* Config filename was set */
- ConfigFileName = optarg;
+ ConfigFileName = ServerInstance->Config->Paths.PrependConfig(optarg);
break;
case 0:
/* getopt_long_only() set an int variable, just keep going */
@@ -451,19 +315,21 @@ InspIRCd::InspIRCd(int argc, char** argv) :
default:
/* Fall through to handle other weird values too */
std::cout << "Unknown parameter '" << argv[optind-1] << "'" << std::endl;
- std::cout << "Usage: " << argv[0] << " [--nofork] [--nolog] [--debug] [--logfile <filename>] " << std::endl <<
- std::string(static_cast<int>(8+strlen(argv[0])), ' ') << "[--runasroot] [--version] [--config <config>] [--testsuite]" << std::endl;
+ std::cout << "Usage: " << argv[0] << " [--nofork] [--nolog] [--debug] [--config <config>]" << std::endl <<
+ std::string(static_cast<int>(8+strlen(argv[0])), ' ') << "[--runasroot] [--version]" << std::endl;
Exit(EXIT_STATUS_ARGV);
break;
}
}
+#ifdef INSPIRCD_ENABLE_TESTSUITE
if (do_testsuite)
do_nofork = do_debug = true;
+#endif
if (do_version)
{
- std::cout << std::endl << VERSION << " r" << REVISION << std::endl;
+ std::cout << std::endl << INSPIRCD_VERSION << " " << INSPIRCD_REVISION << std::endl;
Exit(EXIT_STATUS_NOERROR);
}
@@ -477,28 +343,22 @@ InspIRCd::InspIRCd(int argc, char** argv) :
Config->cmdline.nofork = (do_nofork != 0);
Config->cmdline.forcedebug = (do_debug != 0);
Config->cmdline.writelog = !do_nolog;
- Config->cmdline.TestSuite = (do_testsuite != 0);
if (do_debug)
{
FileWriter* fw = new FileWriter(stdout);
- FileLogStream* fls = new FileLogStream(RAWIO, fw);
+ FileLogStream* fls = new FileLogStream(LOG_RAWIO, fw);
Logs->AddLogTypes("*", fls, true);
}
- else if (!this->OpenLog(argv, argc))
- {
- std::cout << "ERROR: Could not open initial logfile " << Config->cmdline.startup_log << ": " << strerror(errno) << std::endl << std::endl;
- Exit(EXIT_STATUS_LOG);
- }
- if (!ServerConfig::FileExists(ConfigFileName.c_str()))
+ if (!FileSystem::FileExists(ConfigFileName))
{
#ifdef _WIN32
/* Windows can (and defaults to) hide file extensions, so let's play a bit nice for windows users. */
std::string txtconf = this->ConfigFileName;
txtconf.append(".txt");
- if (ServerConfig::FileExists(txtconf.c_str()))
+ if (FileSystem::FileExists(txtconf))
{
ConfigFileName = txtconf;
}
@@ -506,7 +366,7 @@ InspIRCd::InspIRCd(int argc, char** argv) :
#endif
{
std::cout << "ERROR: Cannot open config file: " << ConfigFileName << std::endl << "Exiting..." << std::endl;
- this->Logs->Log("STARTUP",DEFAULT,"Unable to open config file %s", ConfigFileName.c_str());
+ this->Logs->Log("STARTUP", LOG_DEFAULT, "Unable to open config file %s", ConfigFileName.c_str());
Exit(EXIT_STATUS_CONFIG);
}
}
@@ -515,25 +375,23 @@ InspIRCd::InspIRCd(int argc, char** argv) :
std::cout << con_green << "(C) InspIRCd Development Team." << con_reset << std::endl << std::endl;
std::cout << "Developers:" << std::endl;
std::cout << con_green << "\tBrain, FrostyCoolSlug, w00t, Om, Special, peavey" << std::endl;
- std::cout << "\taquanight, psychon, dz, danieldg, jackmcbarn" << std::endl;
+ std::cout << "\taquanight, psychon, dz, danieldg, jackmcbarn" << std::endl;
std::cout << "\tAttila" << con_reset << std::endl << std::endl;
std::cout << "Others:\t\t\t" << con_green << "See /INFO Output" << con_reset << std::endl;
- this->Modes = new ModeParser;
-
#ifndef _WIN32
if (!do_root)
this->CheckRoot();
else
{
- std::cout << "* WARNING * WARNING * WARNING * WARNING * WARNING *" << std::endl
- << "YOU ARE RUNNING INSPIRCD AS ROOT. THIS IS UNSUPPORTED" << std::endl
- << "AND IF YOU ARE HACKED, CRACKED, SPINDLED OR MUTILATED" << std::endl
- << "OR ANYTHING ELSE UNEXPECTED HAPPENS TO YOU OR YOUR" << std::endl
- << "SERVER, THEN IT IS YOUR OWN FAULT. IF YOU DID NOT MEAN" << std::endl
- << "TO START INSPIRCD AS ROOT, HIT CTRL+C NOW AND RESTART" << std::endl
- << "THE PROGRAM AS A NORMAL USER. YOU HAVE BEEN WARNED!" << std::endl << std::endl
- << "InspIRCd starting in 20 seconds, ctrl+c to abort..." << std::endl;
+ std::cout << "* WARNING * WARNING * WARNING * WARNING * WARNING *" << std::endl
+ << "YOU ARE RUNNING INSPIRCD AS ROOT. THIS IS UNSUPPORTED" << std::endl
+ << "AND IF YOU ARE HACKED, CRACKED, SPINDLED OR MUTILATED" << std::endl
+ << "OR ANYTHING ELSE UNEXPECTED HAPPENS TO YOU OR YOUR" << std::endl
+ << "SERVER, THEN IT IS YOUR OWN FAULT. IF YOU DID NOT MEAN" << std::endl
+ << "TO START INSPIRCD AS ROOT, HIT CTRL+C NOW AND RESTART" << std::endl
+ << "THE PROGRAM AS A NORMAL USER. YOU HAVE BEEN WARNED!" << std::endl << std::endl
+ << "InspIRCd starting in 20 seconds, ctrl+c to abort..." << std::endl;
sleep(20);
}
#endif
@@ -545,47 +403,32 @@ InspIRCd::InspIRCd(int argc, char** argv) :
if (!this->DaemonSeed())
{
std::cout << "ERROR: could not go into daemon mode. Shutting down." << std::endl;
- Logs->Log("STARTUP", DEFAULT, "ERROR: could not go into daemon mode. Shutting down.");
+ Logs->Log("STARTUP", LOG_DEFAULT, "ERROR: could not go into daemon mode. Shutting down.");
Exit(EXIT_STATUS_FORK);
}
}
- SE->RecoverFromFork();
+ SocketEngine::RecoverFromFork();
- /* During startup we don't actually initialize this
- * in the thread engine.
+ /* During startup we read the configuration now, not in
+ * a seperate thread
*/
this->Config->Read();
this->Config->Apply(NULL, "");
Logs->OpenFileLogs();
+ ModeParser::InitBuiltinModes();
- this->Res = new DNS();
-
- /*
- * Initialise SID/UID.
- * For an explanation as to exactly how this works, and why it works this way, see GetUID().
- * -- w00t
- */
+ // If we don't have a SID, generate one based on the server name and the server description
if (Config->sid.empty())
- {
- // Generate one
- unsigned int sid = 0;
- char sidstr[4];
+ Config->sid = UIDGenerator::GenerateSID(Config->ServerName, Config->ServerDesc);
- for (const char* x = Config->ServerName.c_str(); *x; ++x)
- sid = 5 * sid + *x;
- for (const char* y = Config->ServerDesc.c_str(); *y; ++y)
- sid = 5 * sid + *y;
- sprintf(sidstr, "%03d", sid % 1000);
+ // Initialize the UID generator with our sid
+ this->UIDGen.init(Config->sid);
- Config->sid = sidstr;
- }
-
- /* set up fake client again this time with the correct uid */
- this->FakeClient = new FakeUser(Config->sid, Config->ServerName);
+ // Create the server user for this server
+ this->FakeClient = new FakeUser(Config->sid, Config->ServerName, Config->ServerDesc);
- // Get XLine to do it's thing.
- this->XLines->CheckELines();
+ // This is needed as all new XLines are marked pending until ApplyLines() is called
this->XLines->ApplyLines();
int bounditems = BindPorts(pl);
@@ -594,8 +437,8 @@ InspIRCd::InspIRCd(int argc, char** argv) :
this->Modules->LoadAll();
- /* Just in case no modules were loaded - fix for bug #101 */
- this->BuildISupport();
+ // Build ISupport as ModuleManager::LoadAll() does not do it
+ this->ISupport.Build();
Config->ApplyDisabledCommands(Config->DisabledCommands);
if (!pl.empty())
@@ -612,7 +455,7 @@ InspIRCd::InspIRCd(int argc, char** argv) :
std::cout << std::endl << "Hint: Try using a public IP instead of blank or *" << std::endl;
}
- std::cout << "InspIRCd is now running as '" << Config->ServerName << "'[" << Config->GetSID() << "] with " << SE->GetMaxFds() << " max open sockets" << std::endl;
+ std::cout << "InspIRCd is now running as '" << Config->ServerName << "'[" << Config->GetSID() << "] with " << SocketEngine::GetMaxFds() << " max open sockets" << std::endl;
#ifndef _WIN32
if (!Config->cmdline.nofork)
@@ -620,7 +463,7 @@ InspIRCd::InspIRCd(int argc, char** argv) :
if (kill(getppid(), SIGTERM) == -1)
{
std::cout << "Error killing parent process: " << strerror(errno) << std::endl;
- Logs->Log("STARTUP", DEFAULT, "Error killing parent process: %s",strerror(errno));
+ Logs->Log("STARTUP", LOG_DEFAULT, "Error killing parent process: %s",strerror(errno));
}
}
@@ -634,7 +477,7 @@ InspIRCd::InspIRCd(int argc, char** argv) :
*
* -- nenolod
*/
- if ((!do_nofork) && (!do_testsuite) && (!Config->cmdline.forcedebug))
+ if ((!do_nofork) && (!Config->cmdline.forcedebug))
{
int fd = open("/dev/null", O_RDWR);
@@ -643,16 +486,16 @@ InspIRCd::InspIRCd(int argc, char** argv) :
fclose(stdout);
if (dup2(fd, STDIN_FILENO) < 0)
- Logs->Log("STARTUP", DEFAULT, "Failed to dup /dev/null to stdin.");
+ Logs->Log("STARTUP", LOG_DEFAULT, "Failed to dup /dev/null to stdin.");
if (dup2(fd, STDOUT_FILENO) < 0)
- Logs->Log("STARTUP", DEFAULT, "Failed to dup /dev/null to stdout.");
+ Logs->Log("STARTUP", LOG_DEFAULT, "Failed to dup /dev/null to stdout.");
if (dup2(fd, STDERR_FILENO) < 0)
- Logs->Log("STARTUP", DEFAULT, "Failed to dup /dev/null to stderr.");
+ Logs->Log("STARTUP", LOG_DEFAULT, "Failed to dup /dev/null to stderr.");
close(fd);
}
else
{
- Logs->Log("STARTUP", DEFAULT,"Keeping pseudo-tty open as we are running in the foreground.");
+ Logs->Log("STARTUP", LOG_DEFAULT, "Keeping pseudo-tty open as we are running in the foreground.");
}
#else
/* Set win32 service as running, if we are running as a service */
@@ -664,10 +507,10 @@ InspIRCd::InspIRCd(int argc, char** argv) :
FreeConsole();
}
- QueryPerformanceFrequency(&stats->QPFrequency);
+ QueryPerformanceFrequency(&stats.QPFrequency);
#endif
- Logs->Log("STARTUP", DEFAULT, "Startup complete as '%s'[%s], %d max open sockets", Config->ServerName.c_str(),Config->GetSID().c_str(), SE->GetMaxFds());
+ Logs->Log("STARTUP", LOG_DEFAULT, "Startup complete as '%s'[%s], %d max open sockets", Config->ServerName.c_str(),Config->GetSID().c_str(), SocketEngine::GetMaxFds());
#ifndef _WIN32
std::string SetUser = Config->ConfValue("security")->getString("runasuser");
@@ -681,7 +524,7 @@ InspIRCd::InspIRCd(int argc, char** argv) :
if (ret == -1)
{
- this->Logs->Log("SETGROUPS", DEFAULT, "setgroups() failed (wtf?): %s", strerror(errno));
+ this->Logs->Log("STARTUP", LOG_DEFAULT, "setgroups() failed (wtf?): %s", strerror(errno));
this->QuickExit(0);
}
@@ -693,7 +536,7 @@ InspIRCd::InspIRCd(int argc, char** argv) :
if (!g)
{
- this->Logs->Log("SETGUID", DEFAULT, "getgrnam(%s) failed (wrong group?): %s", SetGroup.c_str(), strerror(errno));
+ this->Logs->Log("STARTUP", LOG_DEFAULT, "getgrnam(%s) failed (wrong group?): %s", SetGroup.c_str(), strerror(errno));
this->QuickExit(0);
}
@@ -701,7 +544,7 @@ InspIRCd::InspIRCd(int argc, char** argv) :
if (ret == -1)
{
- this->Logs->Log("SETGUID", DEFAULT, "setgid() failed (wrong group?): %s", strerror(errno));
+ this->Logs->Log("STARTUP", LOG_DEFAULT, "setgid() failed (wrong group?): %s", strerror(errno));
this->QuickExit(0);
}
}
@@ -716,7 +559,7 @@ InspIRCd::InspIRCd(int argc, char** argv) :
if (!u)
{
- this->Logs->Log("SETGUID", DEFAULT, "getpwnam(%s) failed (wrong user?): %s", SetUser.c_str(), strerror(errno));
+ this->Logs->Log("STARTUP", LOG_DEFAULT, "getpwnam(%s) failed (wrong user?): %s", SetUser.c_str(), strerror(errno));
this->QuickExit(0);
}
@@ -724,7 +567,7 @@ InspIRCd::InspIRCd(int argc, char** argv) :
if (ret == -1)
{
- this->Logs->Log("SETGUID", DEFAULT, "setuid() failed (wrong user?): %s", strerror(errno));
+ this->Logs->Log("STARTUP", LOG_DEFAULT, "setuid() failed (wrong user?): %s", strerror(errno));
this->QuickExit(0);
}
}
@@ -753,15 +596,17 @@ void InspIRCd::UpdateTime()
#endif
}
-int InspIRCd::Run()
+void InspIRCd::Run()
{
+#ifdef INSPIRCD_ENABLE_TESTSUITE
/* See if we're supposed to be running the test suite rather than entering the mainloop */
- if (Config->cmdline.TestSuite)
+ if (do_testsuite)
{
TestSuite* ts = new TestSuite;
delete ts;
- Exit(0);
+ return;
}
+#endif
UpdateTime();
time_t OLDTIME = TIME.tv_sec;
@@ -776,7 +621,7 @@ int InspIRCd::Run()
if (this->ConfigThread && this->ConfigThread->IsDone())
{
/* Rehash has completed */
- this->Logs->Log("CONFIG",DEBUG,"Detected ConfigThread exiting, tidying up...");
+ this->Logs->Log("CONFIG", LOG_DEBUG, "Detected ConfigThread exiting, tidying up...");
this->ConfigThread->Finish();
@@ -796,18 +641,18 @@ int InspIRCd::Run()
{
#ifndef _WIN32
getrusage(RUSAGE_SELF, &ru);
- stats->LastSampled = TIME;
- stats->LastCPU = ru.ru_utime;
+ stats.LastSampled = TIME;
+ stats.LastCPU = ru.ru_utime;
#else
- if(QueryPerformanceCounter(&stats->LastSampled))
+ if(QueryPerformanceCounter(&stats.LastSampled))
{
FILETIME CreationTime;
FILETIME ExitTime;
FILETIME KernelTime;
FILETIME UserTime;
GetProcessTimes(GetCurrentProcess(), &CreationTime, &ExitTime, &KernelTime, &UserTime);
- stats->LastCPU.dwHighDateTime = KernelTime.dwHighDateTime + UserTime.dwHighDateTime;
- stats->LastCPU.dwLowDateTime = KernelTime.dwLowDateTime + UserTime.dwLowDateTime;
+ stats.LastCPU.dwHighDateTime = KernelTime.dwHighDateTime + UserTime.dwHighDateTime;
+ stats.LastCPU.dwLowDateTime = KernelTime.dwLowDateTime + UserTime.dwLowDateTime;
}
#endif
@@ -820,21 +665,21 @@ int InspIRCd::Run()
{
SNO->WriteToSnoMask('d', "\002EH?!\002 -- Time is jumping FORWARDS! Clock skipped %lu secs.", (unsigned long)TIME.tv_sec - OLDTIME);
}
-
+
OLDTIME = TIME.tv_sec;
if ((TIME.tv_sec % 3600) == 0)
{
- this->RehashUsersAndChans();
- FOREACH_MOD(I_OnGarbageCollect, OnGarbageCollect());
+ Users->GarbageCollect();
+ FOREACH_MOD(OnGarbageCollect, ());
}
- Timers->TickTimers(TIME.tv_sec);
- this->DoBackgroundUserStuff();
+ Timers.TickTimers(TIME.tv_sec);
+ Users->DoBackgroundUserStuff();
if ((TIME.tv_sec % 5) == 0)
{
- FOREACH_MOD(I_OnBackgroundTimer,OnBackgroundTimer(TIME.tv_sec));
+ FOREACH_MOD(OnBackgroundTimer, (TIME.tv_sec));
SNO->FlushSnotices();
}
}
@@ -846,8 +691,8 @@ int InspIRCd::Run()
* This will cause any read or write events to be
* dispatched to their handlers.
*/
- this->SE->DispatchTrialWrites();
- this->SE->DispatchEvents();
+ SocketEngine::DispatchTrialWrites();
+ SocketEngine::DispatchEvents();
/* if any users were quit, take them out */
GlobalCulls.Apply();
@@ -859,25 +704,6 @@ int InspIRCd::Run()
s_signal = 0;
}
}
-
- return 0;
-}
-
-/**********************************************************************************/
-
-/**
- * An ircd in five lines! bwahahaha. ahahahahaha. ahahah *cough*.
- */
-
-/* this returns true when all modules are satisfied that the user should be allowed onto the irc server
- * (until this returns true, a user will block in the waiting state, waiting to connect up to the
- * registration timeout maximum seconds)
- */
-bool InspIRCd::AllModulesReportReady(LocalUser* user)
-{
- ModResult res;
- FIRST_MOD_RESULT(OnCheckReady, res, (user));
- return (res == MOD_RES_PASSTHRU);
}
sig_atomic_t InspIRCd::s_signal = 0;
diff --git a/src/inspsocket.cpp b/src/inspsocket.cpp
index 356904f74..494422075 100644
--- a/src/inspsocket.cpp
+++ b/src/inspsocket.cpp
@@ -23,9 +23,7 @@
#include "inspircd.h"
-#include "socket.h"
-#include "inspstring.h"
-#include "socketengine.h"
+#include "iohook.h"
#ifndef DISABLE_WRITEV
#include <sys/uio.h>
@@ -47,7 +45,7 @@ BufferedSocket::BufferedSocket(int newfd)
this->fd = newfd;
this->state = I_CONNECTED;
if (fd > -1)
- ServerInstance->SE->AddFd(this, FD_WANT_FAST_READ | FD_WANT_EDGE_WRITE);
+ SocketEngine::AddFd(this, FD_WANT_FAST_READ | FD_WANT_EDGE_WRITE);
}
void BufferedSocket::DoConnect(const std::string &ipaddr, int aport, unsigned long maxtime, const std::string &connectbindip)
@@ -66,7 +64,7 @@ BufferedSocketError BufferedSocket::BeginConnect(const std::string &ipaddr, int
irc::sockets::sockaddrs addr, bind;
if (!irc::sockets::aptosa(ipaddr, aport, addr))
{
- ServerInstance->Logs->Log("SOCKET", DEBUG, "BUG: Hostname passed to BufferedSocket, rather than an IP address!");
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "BUG: Hostname passed to BufferedSocket, rather than an IP address!");
return I_ERR_CONNECT;
}
@@ -92,13 +90,13 @@ BufferedSocketError BufferedSocket::BeginConnect(const irc::sockets::sockaddrs&
if (bind.sa.sa_family != 0)
{
- if (ServerInstance->SE->Bind(fd, bind) < 0)
+ if (SocketEngine::Bind(fd, bind) < 0)
return I_ERR_BIND;
}
- ServerInstance->SE->NonBlocking(fd);
+ SocketEngine::NonBlocking(fd);
- if (ServerInstance->SE->Connect(this, &dest.sa, sa_size(dest)) == -1)
+ if (SocketEngine::Connect(this, &dest.sa, dest.sa_size()) == -1)
{
if (errno != EINPROGRESS)
return I_ERR_CONNECT;
@@ -106,13 +104,13 @@ BufferedSocketError BufferedSocket::BeginConnect(const irc::sockets::sockaddrs&
this->state = I_CONNECTING;
- if (!ServerInstance->SE->AddFd(this, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE | FD_WRITE_WILL_BLOCK))
+ if (!SocketEngine::AddFd(this, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE | FD_WRITE_WILL_BLOCK))
return I_ERR_NOMOREFDS;
- this->Timeout = new SocketTimeout(this->GetFd(), this, timeout, ServerInstance->Time());
- ServerInstance->Timers->AddTimer(this->Timeout);
+ this->Timeout = new SocketTimeout(this->GetFd(), this, timeout);
+ ServerInstance->Timers.AddTimer(this->Timeout);
- ServerInstance->Logs->Log("SOCKET", DEBUG,"BufferedSocket::DoConnect success");
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "BufferedSocket::DoConnect success");
return I_ERR_NONE;
}
@@ -122,23 +120,22 @@ void StreamSocket::Close()
{
// final chance, dump as much of the sendq as we can
DoWrite();
- if (IOHook)
+ if (GetIOHook())
{
try
{
- IOHook->OnStreamSocketClose(this);
+ GetIOHook()->OnStreamSocketClose(this);
}
catch (CoreException& modexcept)
{
- ServerInstance->Logs->Log("SOCKET", DEFAULT,"%s threw an exception: %s",
- modexcept.GetSource(), modexcept.GetReason());
+ ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "%s threw an exception: %s",
+ modexcept.GetSource().c_str(), modexcept.GetReason().c_str());
}
- IOHook = NULL;
+ delete iohook;
+ DelIOHook();
}
- ServerInstance->SE->Shutdown(this, 2);
- ServerInstance->SE->DelFd(this);
- ServerInstance->SE->Close(this);
- fd = -1;
+ SocketEngine::Shutdown(this, 2);
+ SocketEngine::Close(this);
}
}
@@ -161,17 +158,17 @@ bool StreamSocket::GetNextLine(std::string& line, char delim)
void StreamSocket::DoRead()
{
- if (IOHook)
+ if (GetIOHook())
{
int rv = -1;
try
{
- rv = IOHook->OnStreamSocketRead(this, recvq);
+ rv = GetIOHook()->OnStreamSocketRead(this, recvq);
}
catch (CoreException& modexcept)
{
- ServerInstance->Logs->Log("SOCKET", DEFAULT, "%s threw an exception: %s",
- modexcept.GetSource(), modexcept.GetReason());
+ ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "%s threw an exception: %s",
+ modexcept.GetSource().c_str(), modexcept.GetReason().c_str());
return;
}
if (rv > 0)
@@ -182,36 +179,36 @@ void StreamSocket::DoRead()
else
{
char* ReadBuffer = ServerInstance->GetReadBuffer();
- int n = ServerInstance->SE->Recv(this, ReadBuffer, ServerInstance->Config->NetBufferSize, 0);
+ int n = SocketEngine::Recv(this, ReadBuffer, ServerInstance->Config->NetBufferSize, 0);
if (n == ServerInstance->Config->NetBufferSize)
{
- ServerInstance->SE->ChangeEventMask(this, FD_WANT_FAST_READ | FD_ADD_TRIAL_READ);
+ SocketEngine::ChangeEventMask(this, FD_WANT_FAST_READ | FD_ADD_TRIAL_READ);
recvq.append(ReadBuffer, n);
OnDataReady();
}
else if (n > 0)
{
- ServerInstance->SE->ChangeEventMask(this, FD_WANT_FAST_READ);
+ SocketEngine::ChangeEventMask(this, FD_WANT_FAST_READ);
recvq.append(ReadBuffer, n);
OnDataReady();
}
else if (n == 0)
{
error = "Connection closed";
- ServerInstance->SE->ChangeEventMask(this, FD_WANT_NO_READ | FD_WANT_NO_WRITE);
+ SocketEngine::ChangeEventMask(this, FD_WANT_NO_READ | FD_WANT_NO_WRITE);
}
else if (SocketEngine::IgnoreError())
{
- ServerInstance->SE->ChangeEventMask(this, FD_WANT_FAST_READ | FD_READ_WILL_BLOCK);
+ SocketEngine::ChangeEventMask(this, FD_WANT_FAST_READ | FD_READ_WILL_BLOCK);
}
else if (errno == EINTR)
{
- ServerInstance->SE->ChangeEventMask(this, FD_WANT_FAST_READ | FD_ADD_TRIAL_READ);
+ SocketEngine::ChangeEventMask(this, FD_WANT_FAST_READ | FD_ADD_TRIAL_READ);
}
else
{
error = SocketEngine::LastError();
- ServerInstance->SE->ChangeEventMask(this, FD_WANT_NO_READ | FD_WANT_NO_WRITE);
+ SocketEngine::ChangeEventMask(this, FD_WANT_NO_READ | FD_WANT_NO_WRITE);
}
}
}
@@ -225,12 +222,12 @@ void StreamSocket::DoWrite()
return;
if (!error.empty() || fd < 0 || fd == INT_MAX)
{
- ServerInstance->Logs->Log("SOCKET", DEBUG, "DoWrite on errored or closed socket");
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "DoWrite on errored or closed socket");
return;
}
#ifndef DISABLE_WRITEV
- if (IOHook)
+ if (GetIOHook())
#endif
{
int rv = -1;
@@ -258,9 +255,9 @@ void StreamSocket::DoWrite()
}
std::string& front = sendq.front();
int itemlen = front.length();
- if (IOHook)
+ if (GetIOHook())
{
- rv = IOHook->OnStreamSocketWrite(this, front);
+ rv = GetIOHook()->OnStreamSocketWrite(this, front);
if (rv > 0)
{
// consumed the entire string, and is ready for more
@@ -285,7 +282,7 @@ void StreamSocket::DoWrite()
#ifdef DISABLE_WRITEV
else
{
- rv = ServerInstance->SE->Send(this, front.data(), itemlen, 0);
+ rv = SocketEngine::Send(this, front.data(), itemlen, 0);
if (rv == 0)
{
SetError("Connection closed");
@@ -294,14 +291,14 @@ void StreamSocket::DoWrite()
else if (rv < 0)
{
if (errno == EINTR || SocketEngine::IgnoreError())
- ServerInstance->SE->ChangeEventMask(this, FD_WANT_FAST_WRITE | FD_WRITE_WILL_BLOCK);
+ SocketEngine::ChangeEventMask(this, FD_WANT_FAST_WRITE | FD_WRITE_WILL_BLOCK);
else
SetError(SocketEngine::LastError());
return;
}
else if (rv < itemlen)
{
- ServerInstance->SE->ChangeEventMask(this, FD_WANT_FAST_WRITE | FD_WRITE_WILL_BLOCK);
+ SocketEngine::ChangeEventMask(this, FD_WANT_FAST_WRITE | FD_WRITE_WILL_BLOCK);
front = front.substr(rv);
sendq_len -= rv;
return;
@@ -311,7 +308,7 @@ void StreamSocket::DoWrite()
sendq_len -= itemlen;
sendq.pop_front();
if (sendq.empty())
- ServerInstance->SE->ChangeEventMask(this, FD_WANT_EDGE_WRITE);
+ SocketEngine::ChangeEventMask(this, FD_WANT_EDGE_WRITE);
}
}
#endif
@@ -319,8 +316,8 @@ void StreamSocket::DoWrite()
}
catch (CoreException& modexcept)
{
- ServerInstance->Logs->Log("SOCKET", DEBUG,"%s threw an exception: %s",
- modexcept.GetSource(), modexcept.GetReason());
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "%s threw an exception: %s",
+ modexcept.GetSource().c_str(), modexcept.GetReason().c_str());
}
}
#ifndef DISABLE_WRITEV
@@ -407,11 +404,11 @@ void StreamSocket::DoWrite()
if (!error.empty())
{
// error - kill all events
- ServerInstance->SE->ChangeEventMask(this, FD_WANT_NO_READ | FD_WANT_NO_WRITE);
+ SocketEngine::ChangeEventMask(this, FD_WANT_NO_READ | FD_WANT_NO_WRITE);
}
else
{
- ServerInstance->SE->ChangeEventMask(this, eventChange);
+ SocketEngine::ChangeEventMask(this, eventChange);
}
}
#endif
@@ -421,7 +418,7 @@ void StreamSocket::WriteData(const std::string &data)
{
if (fd < 0)
{
- ServerInstance->Logs->Log("SOCKET", DEBUG, "Attempt to write data to dead socket: %s",
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Attempt to write data to dead socket: %s",
data.c_str());
return;
}
@@ -430,15 +427,18 @@ void StreamSocket::WriteData(const std::string &data)
sendq.push_back(data);
sendq_len += data.length();
- ServerInstance->SE->ChangeEventMask(this, FD_ADD_TRIAL_WRITE);
+ SocketEngine::ChangeEventMask(this, FD_ADD_TRIAL_WRITE);
}
-void SocketTimeout::Tick(time_t)
+bool SocketTimeout::Tick(time_t)
{
- ServerInstance->Logs->Log("SOCKET", DEBUG,"SocketTimeout::Tick");
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "SocketTimeout::Tick");
- if (ServerInstance->SE->GetRef(this->sfd) != this->sock)
- return;
+ if (SocketEngine::GetRef(this->sfd) != this->sock)
+ {
+ delete this;
+ return false;
+ }
if (this->sock->state == I_CONNECTING)
{
@@ -454,6 +454,8 @@ void SocketTimeout::Tick(time_t)
}
this->sock->Timeout = NULL;
+ delete this;
+ return false;
}
void BufferedSocket::OnConnected() { }
@@ -465,10 +467,8 @@ void BufferedSocket::DoWrite()
{
state = I_CONNECTED;
this->OnConnected();
- if (GetIOHook())
- GetIOHook()->OnStreamSocketConnect(this);
- else
- ServerInstance->SE->ChangeEventMask(this, FD_WANT_FAST_READ | FD_WANT_EDGE_WRITE);
+ if (!GetIOHook())
+ SocketEngine::ChangeEventMask(this, FD_WANT_FAST_READ | FD_WANT_EDGE_WRITE);
}
this->StreamSocket::DoWrite();
}
@@ -478,8 +478,8 @@ BufferedSocket::~BufferedSocket()
this->Close();
if (Timeout)
{
- ServerInstance->Timers->DelTimer(Timeout);
- Timeout = NULL;
+ // The timer is removed from the TimerManager in Timer::~Timer()
+ delete Timeout;
}
}
@@ -530,14 +530,13 @@ void StreamSocket::HandleEvent(EventType et, int errornum)
}
catch (CoreException& ex)
{
- ServerInstance->Logs->Log("SOCKET", DEFAULT, "Caught exception in socket processing on FD %d - '%s'",
- fd, ex.GetReason());
+ ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "Caught exception in socket processing on FD %d - '%s'",
+ fd, ex.GetReason().c_str());
SetError(ex.GetReason());
}
if (!error.empty())
{
- ServerInstance->Logs->Log("SOCKET", DEBUG, "Error on FD %d - '%s'", fd, error.c_str());
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Error on FD %d - '%s'", fd, error.c_str());
OnError(errcode);
}
}
-
diff --git a/src/inspstring.cpp b/src/inspstring.cpp
index 534b7ce00..b59492738 100644
--- a/src/inspstring.cpp
+++ b/src/inspstring.cpp
@@ -21,140 +21,18 @@
#include "inspircd.h"
-/*
- * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef HAS_STRLCPY
-CoreExport size_t strlcat(char *dst, const char *src, size_t siz)
-{
- char *d = dst;
- const char *s = src;
- size_t n = siz, dlen;
-
- while (n-- != 0 && *d != '\0')
- d++;
-
- dlen = d - dst;
- n = siz - dlen;
-
- if (n == 0)
- return(dlen + strlen(s));
-
- while (*s != '\0')
- {
- if (n != 1)
- {
- *d++ = *s;
- n--;
- }
-
- s++;
- }
-
- *d = '\0';
- return(dlen + (s - src)); /* count does not include NUL */
-}
-
-CoreExport size_t strlcpy(char *dst, const char *src, size_t siz)
-{
- char *d = dst;
- const char *s = src;
- size_t n = siz;
-
- /* Copy as many bytes as will fit */
- if (n != 0 && --n != 0)
- {
- do
- {
- if ((*d++ = *s++) == 0)
- break;
- } while (--n != 0);
- }
-
- /* Not enough room in dst, add NUL and traverse rest of src */
- if (n == 0)
- {
- if (siz != 0)
- *d = '\0'; /* NUL-terminate dst */
- while (*s++);
- }
-
- return(s - src - 1); /* count does not include NUL */
-}
-#endif
-
-CoreExport int charlcat(char* x,char y,int z)
-{
- char* x__n = x;
- int v = 0;
-
- while(*x__n++)
- v++;
-
- if (v < z - 1)
- {
- *--x__n = y;
- *++x__n = 0;
- }
-
- return v;
-}
-
-CoreExport bool charremove(char* mp, char remove)
-{
- char* mptr = mp;
- bool shift_down = false;
-
- while (*mptr)
- {
- if (*mptr == remove)
- shift_down = true;
-
- if (shift_down)
- *mptr = *(mptr+1);
-
- mptr++;
- }
-
- return shift_down;
-}
-
static const char hextable[] = "0123456789abcdef";
-std::string BinToHex(const std::string& data)
+std::string BinToHex(const void* raw, size_t l)
{
- int l = data.length();
+ const char* data = static_cast<const char*>(raw);
std::string rv;
rv.reserve(l * 2);
- for(int i=0; i < l; i++)
+ for (size_t i = 0; i < l; i++)
{
unsigned char c = data[i];
- rv.append(1, hextable[c >> 4]);
- rv.append(1, hextable[c & 0xF]);
+ rv.push_back(hextable[c >> 4]);
+ rv.push_back(hextable[c & 0xF]);
}
return rv;
}
@@ -230,3 +108,19 @@ std::string Base64ToBin(const std::string& data_str, const char* table)
}
return rv;
}
+
+bool InspIRCd::TimingSafeCompare(const std::string& one, const std::string& two)
+{
+ if (one.length() != two.length())
+ return false;
+
+ unsigned int diff = 0;
+ for (std::string::const_iterator i = one.begin(), j = two.begin(); i != one.end(); ++i, ++j)
+ {
+ unsigned char a = static_cast<unsigned char>(*i);
+ unsigned char b = static_cast<unsigned char>(*j);
+ diff |= a ^ b;
+ }
+
+ return (diff == 0);
+}
diff --git a/src/listensocket.cpp b/src/listensocket.cpp
index ae11c3b48..c1339fb3d 100644
--- a/src/listensocket.cpp
+++ b/src/listensocket.cpp
@@ -19,14 +19,17 @@
#include "inspircd.h"
-#include "socket.h"
-#include "socketengine.h"
+
+#ifndef _WIN32
+#include <netinet/tcp.h>
+#endif
ListenSocket::ListenSocket(ConfigTag* tag, const irc::sockets::sockaddrs& bind_to)
: bind_tag(tag)
+ , iohookprov(NULL, std::string())
{
irc::sockets::satoap(bind_to, bind_addr, bind_port);
- bind_desc = irc::sockets::satouser(bind_to);
+ bind_desc = bind_to.str();
fd = socket(bind_to.sa.sa_family, SOCK_STREAM, 0);
@@ -51,23 +54,38 @@ ListenSocket::ListenSocket(ConfigTag* tag, const irc::sockets::sockaddrs& bind_t
}
#endif
- ServerInstance->SE->SetReuse(fd);
- int rv = ServerInstance->SE->Bind(this->fd, bind_to);
+ SocketEngine::SetReuse(fd);
+ int rv = SocketEngine::Bind(this->fd, bind_to);
if (rv >= 0)
- rv = ServerInstance->SE->Listen(this->fd, ServerInstance->Config->MaxConn);
+ rv = SocketEngine::Listen(this->fd, ServerInstance->Config->MaxConn);
+
+ int timeout = tag->getInt("defer", 0);
+ if (timeout && !rv)
+ {
+#if defined TCP_DEFER_ACCEPT
+ setsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &timeout, sizeof(timeout));
+#elif defined SO_ACCEPTFILTER
+ struct accept_filter_arg afa;
+ memset(&afa, 0, sizeof(afa));
+ strcpy(afa.af_name, "dataready");
+ setsockopt(fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa));
+#endif
+ }
if (rv < 0)
{
int errstore = errno;
- ServerInstance->SE->Shutdown(this, 2);
- ServerInstance->SE->Close(this);
+ SocketEngine::Shutdown(this, 2);
+ SocketEngine::Close(this->GetFd());
this->fd = -1;
errno = errstore;
}
else
{
- ServerInstance->SE->NonBlocking(this->fd);
- ServerInstance->SE->AddFd(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
+ SocketEngine::NonBlocking(this->fd);
+ SocketEngine::AddFd(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
+
+ this->ResetIOHookProvider();
}
}
@@ -75,12 +93,10 @@ ListenSocket::~ListenSocket()
{
if (this->GetFd() > -1)
{
- ServerInstance->SE->DelFd(this);
- ServerInstance->Logs->Log("SOCKET", DEBUG,"Shut down listener on fd %d", this->fd);
- ServerInstance->SE->Shutdown(this, 2);
- if (ServerInstance->SE->Close(this) != 0)
- ServerInstance->Logs->Log("SOCKET", DEBUG,"Failed to cancel listener: %s", strerror(errno));
- this->fd = -1;
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Shut down listener on fd %d", this->fd);
+ SocketEngine::Shutdown(this, 2);
+ if (SocketEngine::Close(this) != 0)
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Failed to cancel listener: %s", strerror(errno));
}
}
@@ -91,41 +107,22 @@ void ListenSocket::AcceptInternal()
irc::sockets::sockaddrs server;
socklen_t length = sizeof(client);
- int incomingSockfd = ServerInstance->SE->Accept(this, &client.sa, &length);
+ int incomingSockfd = SocketEngine::Accept(this, &client.sa, &length);
- ServerInstance->Logs->Log("SOCKET",DEBUG,"HandleEvent for Listensocket %s nfd=%d", bind_desc.c_str(), incomingSockfd);
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "HandleEvent for Listensocket %s nfd=%d", bind_desc.c_str(), incomingSockfd);
if (incomingSockfd < 0)
{
- ServerInstance->stats->statsRefused++;
+ ServerInstance->stats.Refused++;
return;
}
socklen_t sz = sizeof(server);
if (getsockname(incomingSockfd, &server.sa, &sz))
{
- ServerInstance->Logs->Log("SOCKET", DEBUG, "Can't get peername: %s", strerror(errno));
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Can't get peername: %s", strerror(errno));
irc::sockets::aptosa(bind_addr, bind_port, server);
}
- /*
- * XXX -
- * this is done as a safety check to keep the file descriptors within range of fd_ref_table.
- * its a pretty big but for the moment valid assumption:
- * file descriptors are handed out starting at 0, and are recycled as theyre freed.
- * therefore if there is ever an fd over 65535, 65536 clients must be connected to the
- * irc server at once (or the irc server otherwise initiating this many connections, files etc)
- * which for the time being is a physical impossibility (even the largest networks dont have more
- * than about 10,000 users on ONE server!)
- */
- if (incomingSockfd >= ServerInstance->SE->GetMaxFds())
- {
- ServerInstance->Logs->Log("SOCKET", DEBUG, "Server is full");
- ServerInstance->SE->Shutdown(incomingSockfd, 2);
- ServerInstance->SE->Close(incomingSockfd);
- ServerInstance->stats->statsRefused++;
- return;
- }
-
if (client.sa.sa_family == AF_INET6)
{
/*
@@ -156,7 +153,7 @@ void ListenSocket::AcceptInternal()
}
}
- ServerInstance->SE->NonBlocking(incomingSockfd);
+ SocketEngine::NonBlocking(incomingSockfd);
ModResult res;
FIRST_MOD_RESULT(OnAcceptConnection, res, (incomingSockfd, this, &client, &server));
@@ -171,14 +168,14 @@ void ListenSocket::AcceptInternal()
}
if (res == MOD_RES_ALLOW)
{
- ServerInstance->stats->statsAccept++;
+ ServerInstance->stats.Accept++;
}
else
{
- ServerInstance->stats->statsRefused++;
- ServerInstance->Logs->Log("SOCKET",DEFAULT,"Refusing connection on %s - %s",
+ ServerInstance->stats.Refused++;
+ ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "Refusing connection on %s - %s",
bind_desc.c_str(), res == MOD_RES_DENY ? "Connection refused by module" : "Module for this port not found");
- ServerInstance->SE->Close(incomingSockfd);
+ SocketEngine::Close(incomingSockfd);
}
}
@@ -187,13 +184,26 @@ void ListenSocket::HandleEvent(EventType e, int err)
switch (e)
{
case EVENT_ERROR:
- ServerInstance->Logs->Log("SOCKET",DEFAULT,"ListenSocket::HandleEvent() received a socket engine error event! well shit! '%s'", strerror(err));
+ ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "ListenSocket::HandleEvent() received a socket engine error event! well shit! '%s'", strerror(err));
break;
case EVENT_WRITE:
- ServerInstance->Logs->Log("SOCKET",DEBUG,"*** BUG *** ListenSocket::HandleEvent() got a WRITE event!!!");
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "*** BUG *** ListenSocket::HandleEvent() got a WRITE event!!!");
break;
case EVENT_READ:
this->AcceptInternal();
break;
}
}
+
+bool ListenSocket::ResetIOHookProvider()
+{
+ std::string provname = bind_tag->getString("ssl");
+ if (!provname.empty())
+ provname.insert(0, "ssl/");
+
+ // Set the new provider name, dynref handles the rest
+ iohookprov.SetProvider(provname);
+
+ // Return true if no provider was set, or one was set and it was also found
+ return (provname.empty() || iohookprov);
+}
diff --git a/src/listmode.cpp b/src/listmode.cpp
new file mode 100644
index 000000000..0f139bb01
--- /dev/null
+++ b/src/listmode.cpp
@@ -0,0 +1,222 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "inspircd.h"
+#include "listmode.h"
+
+ListModeBase::ListModeBase(Module* Creator, const std::string& Name, char modechar, const std::string &eolstr, unsigned int lnum, unsigned int eolnum, bool autotidy, const std::string &ctag)
+ : ModeHandler(Creator, Name, modechar, PARAM_ALWAYS, MODETYPE_CHANNEL, MC_LIST),
+ listnumeric(lnum), endoflistnumeric(eolnum), endofliststring(eolstr), tidy(autotidy),
+ configtag(ctag), extItem("listbase_mode_" + name + "_list", Creator)
+{
+ list = true;
+}
+
+void ListModeBase::DisplayList(User* user, Channel* channel)
+{
+ ChanData* cd = extItem.get(channel);
+ if (cd)
+ {
+ for (ModeList::reverse_iterator it = cd->list.rbegin(); it != cd->list.rend(); ++it)
+ {
+ user->WriteNumeric(listnumeric, "%s %s %s %lu", channel->name.c_str(), it->mask.c_str(), (!it->setter.empty() ? it->setter.c_str() : ServerInstance->Config->ServerName.c_str()), (unsigned long) it->time);
+ }
+ }
+ user->WriteNumeric(endoflistnumeric, "%s :%s", channel->name.c_str(), endofliststring.c_str());
+}
+
+void ListModeBase::DisplayEmptyList(User* user, Channel* channel)
+{
+ user->WriteNumeric(endoflistnumeric, "%s :%s", channel->name.c_str(), endofliststring.c_str());
+}
+
+void ListModeBase::RemoveMode(Channel* channel, irc::modestacker& stack)
+{
+ ChanData* cd = extItem.get(channel);
+ if (cd)
+ {
+ for (ModeList::iterator it = cd->list.begin(); it != cd->list.end(); it++)
+ {
+ stack.Push(this->GetModeChar(), it->mask);
+ }
+ }
+}
+
+void ListModeBase::DoRehash()
+{
+ ConfigTagList tags = ServerInstance->Config->ConfTags(configtag);
+
+ limitlist oldlimits = chanlimits;
+ chanlimits.clear();
+
+ for (ConfigIter i = tags.first; i != tags.second; i++)
+ {
+ // For each <banlist> tag
+ ConfigTag* c = i->second;
+ ListLimit limit(c->getString("chan"), c->getInt("limit"));
+
+ if (limit.mask.size() && limit.limit > 0)
+ chanlimits.push_back(limit);
+ }
+
+ if (chanlimits.empty())
+ chanlimits.push_back(ListLimit("*", 64));
+
+ // Most of the time our settings are unchanged, so we can avoid iterating the chanlist
+ if (oldlimits == chanlimits)
+ return;
+
+ const chan_hash& chans = ServerInstance->GetChans();
+ for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); ++i)
+ {
+ ChanData* cd = extItem.get(i->second);
+ if (cd)
+ cd->maxitems = -1;
+ }
+}
+
+unsigned int ListModeBase::FindLimit(const std::string& channame)
+{
+ for (limitlist::iterator it = chanlimits.begin(); it != chanlimits.end(); ++it)
+ {
+ if (InspIRCd::Match(channame, it->mask))
+ {
+ // We have a pattern matching the channel
+ return it->limit;
+ }
+ }
+ return 64;
+}
+
+unsigned int ListModeBase::GetLimitInternal(const std::string& channame, ChanData* cd)
+{
+ if (cd->maxitems < 0)
+ cd->maxitems = FindLimit(channame);
+ return cd->maxitems;
+}
+
+unsigned int ListModeBase::GetLimit(Channel* channel)
+{
+ ChanData* cd = extItem.get(channel);
+ if (!cd) // just find the limit
+ return FindLimit(channel->name);
+
+ return GetLimitInternal(channel->name, cd);
+}
+
+ModeAction ListModeBase::OnModeChange(User* source, User*, Channel* channel, std::string &parameter, bool adding)
+{
+ // Try and grab the list
+ ChanData* cd = extItem.get(channel);
+
+ if (adding)
+ {
+ if (tidy)
+ ModeParser::CleanMask(parameter);
+
+ if (parameter.length() > 250)
+ return MODEACTION_DENY;
+
+ // If there was no list
+ if (!cd)
+ {
+ // Make one
+ cd = new ChanData;
+ extItem.set(channel, cd);
+ }
+
+ // Check if the item already exists in the list
+ for (ModeList::iterator it = cd->list.begin(); it != cd->list.end(); it++)
+ {
+ if (parameter == it->mask)
+ {
+ /* Give a subclass a chance to error about this */
+ TellAlreadyOnList(source, channel, parameter);
+
+ // it does, deny the change
+ return MODEACTION_DENY;
+ }
+ }
+
+ if ((IS_LOCAL(source)) && (cd->list.size() >= GetLimitInternal(channel->name, cd)))
+ {
+ /* List is full, give subclass a chance to send a custom message */
+ TellListTooLong(source, channel, parameter);
+ return MODEACTION_DENY;
+ }
+
+ /* Ok, it *could* be allowed, now give someone subclassing us
+ * a chance to validate the parameter.
+ * The param is passed by reference, so they can both modify it
+ * and tell us if we allow it or not.
+ *
+ * eg, the subclass could:
+ * 1) allow
+ * 2) 'fix' parameter and then allow
+ * 3) deny
+ */
+ if (ValidateParam(source, channel, parameter))
+ {
+ // And now add the mask onto the list...
+ cd->list.push_back(ListItem(parameter, source->nick, ServerInstance->Time()));
+ return MODEACTION_ALLOW;
+ }
+ else
+ {
+ /* If they deny it they have the job of giving an error message */
+ return MODEACTION_DENY;
+ }
+ }
+ else
+ {
+ // We're taking the mode off
+ if (cd)
+ {
+ for (ModeList::iterator it = cd->list.begin(); it != cd->list.end(); ++it)
+ {
+ if (parameter == it->mask)
+ {
+ cd->list.erase(it);
+ return MODEACTION_ALLOW;
+ }
+ }
+ }
+
+ /* Tried to remove something that wasn't set */
+ TellNotSet(source, channel, parameter);
+ return MODEACTION_DENY;
+ }
+}
+
+bool ListModeBase::ValidateParam(User*, Channel*, std::string&)
+{
+ return true;
+}
+
+void ListModeBase::TellListTooLong(User* source, Channel* channel, std::string& parameter)
+{
+ source->WriteNumeric(ERR_BANLISTFULL, "%s %s :Channel ban list is full", channel->name.c_str(), parameter.c_str());
+}
+
+void ListModeBase::TellAlreadyOnList(User*, Channel*, std::string&)
+{
+}
+
+void ListModeBase::TellNotSet(User*, Channel*, std::string&)
+{
+}
diff --git a/src/logger.cpp b/src/logger.cpp
index 89b2be019..bf4ef582a 100644
--- a/src/logger.cpp
+++ b/src/logger.cpp
@@ -22,8 +22,6 @@
#include "inspircd.h"
-#include "filelogger.h"
-
/*
* Suggested implementation...
* class LogManager
@@ -51,9 +49,13 @@
*
*/
+const char LogStream::LogHeader[] =
+ "Log started for " INSPIRCD_VERSION " (" INSPIRCD_REVISION ", " MODULE_INIT_STR ")"
+ " - compiled on " INSPIRCD_SYSTEM;
+
LogManager::LogManager()
+ : Logging(false)
{
- Logging = false;
}
LogManager::~LogManager()
@@ -82,41 +84,41 @@ void LogManager::OpenFileLogs()
}
std::string type = tag->getString("type");
std::string level = tag->getString("level");
- int loglevel = DEFAULT;
+ LogLevel loglevel = LOG_DEFAULT;
if (level == "rawio")
{
- loglevel = RAWIO;
+ loglevel = LOG_RAWIO;
ServerInstance->Config->RawLog = true;
}
else if (level == "debug")
{
- loglevel = DEBUG;
+ loglevel = LOG_DEBUG;
}
else if (level == "verbose")
{
- loglevel = VERBOSE;
+ loglevel = LOG_VERBOSE;
}
else if (level == "default")
{
- loglevel = DEFAULT;
+ loglevel = LOG_DEFAULT;
}
else if (level == "sparse")
{
- loglevel = SPARSE;
+ loglevel = LOG_SPARSE;
}
else if (level == "none")
{
- loglevel = NONE;
+ loglevel = LOG_NONE;
}
FileWriter* fw;
- std::string target = tag->getString("target");
+ std::string target = ServerInstance->Config->Paths.PrependLog(tag->getString("target"));
std::map<std::string, FileWriter*>::iterator fwi = logmap.find(target);
if (fwi == logmap.end())
{
- char realtarget[MAXBUF];
+ char realtarget[256];
time_t time = ServerInstance->Time();
struct tm *mytime = gmtime(&time);
- strftime(realtarget, MAXBUF, target.c_str(), mytime);
+ strftime(realtarget, sizeof(realtarget), target.c_str(), mytime);
FILE* f = fopen(realtarget, "a");
fw = new FileWriter(f);
logmap.insert(std::make_pair(target, fw));
@@ -126,7 +128,7 @@ void LogManager::OpenFileLogs()
fw = fwi->second;
}
FileLogStream* fls = new FileLogStream(loglevel, fw);
- fls->OnLog(SPARSE, "HEADER", InspIRCd::LogHeader);
+ fls->OnLog(LOG_SPARSE, "HEADER", LogStream::LogHeader);
AddLogTypes(type, fls, true);
}
}
@@ -135,13 +137,16 @@ void LogManager::CloseLogs()
{
if (ServerInstance->Config && ServerInstance->Config->cmdline.forcedebug)
return;
- std::map<std::string, std::vector<LogStream*> >().swap(LogStreams); /* Clear it */
- std::map<LogStream*, std::vector<std::string> >().swap(GlobalLogStreams); /* Clear it */
+
+ LogStreams.clear();
+ GlobalLogStreams.clear();
+
for (std::map<LogStream*, int>::iterator i = AllLogStreams.begin(); i != AllLogStreams.end(); ++i)
{
delete i->first;
}
- std::map<LogStream*, int>().swap(AllLogStreams); /* And clear it */
+
+ AllLogStreams.clear();
}
void LogManager::AddLogTypes(const std::string &types, LogStream* l, bool autoclose)
@@ -187,36 +192,13 @@ void LogManager::AddLogTypes(const std::string &types, LogStream* l, bool autocl
bool LogManager::AddLogType(const std::string &type, LogStream *l, bool autoclose)
{
- std::map<std::string, std::vector<LogStream *> >::iterator i = LogStreams.find(type);
-
- if (i != LogStreams.end())
- {
- i->second.push_back(l);
- }
- else
- {
- std::vector<LogStream *> v;
- v.push_back(l);
- LogStreams[type] = v;
- }
+ LogStreams[type].push_back(l);
if (type == "*")
- {
GlobalLogStreams.insert(std::make_pair(l, std::vector<std::string>()));
- }
if (autoclose)
- {
- std::map<LogStream*, int>::iterator ai = AllLogStreams.find(l);
- if (ai == AllLogStreams.end())
- {
- AllLogStreams.insert(std::make_pair(l, 1));
- }
- else
- {
- ++ai->second;
- }
- }
+ AllLogStreams[l]++;
return true;
}
@@ -228,21 +210,18 @@ void LogManager::DelLogStream(LogStream* l)
std::vector<LogStream*>::iterator it;
while ((it = std::find(i->second.begin(), i->second.end(), l)) != i->second.end())
{
- if (it == i->second.end())
- continue;
i->second.erase(it);
}
}
- std::map<LogStream *, std::vector<std::string> >::iterator gi = GlobalLogStreams.find(l);
- if (gi != GlobalLogStreams.end())
- {
- GlobalLogStreams.erase(gi);
- }
+
+ GlobalLogStreams.erase(l);
+
std::map<LogStream*, int>::iterator ai = AllLogStreams.begin();
if (ai == AllLogStreams.end())
{
return; /* Done. */
}
+
delete ai->first;
AllLogStreams.erase(ai);
}
@@ -252,8 +231,7 @@ bool LogManager::DelLogType(const std::string &type, LogStream *l)
std::map<std::string, std::vector<LogStream *> >::iterator i = LogStreams.find(type);
if (type == "*")
{
- std::map<LogStream *, std::vector<std::string> >::iterator gi = GlobalLogStreams.find(l);
- if (gi != GlobalLogStreams.end()) GlobalLogStreams.erase(gi);
+ GlobalLogStreams.erase(l);
}
if (i != LogStreams.end())
@@ -293,24 +271,17 @@ bool LogManager::DelLogType(const std::string &type, LogStream *l)
return true;
}
-void LogManager::Log(const std::string &type, int loglevel, const char *fmt, ...)
+void LogManager::Log(const std::string &type, LogLevel loglevel, const char *fmt, ...)
{
if (Logging)
- {
return;
- }
-
- va_list a;
- static char buf[65536];
-
- va_start(a, fmt);
- vsnprintf(buf, 65536, fmt, a);
- va_end(a);
- this->Log(type, loglevel, std::string(buf));
+ std::string buf;
+ VAFORMAT(buf, fmt, fmt);
+ this->Log(type, loglevel, buf);
}
-void LogManager::Log(const std::string &type, int loglevel, const std::string &msg)
+void LogManager::Log(const std::string &type, LogLevel loglevel, const std::string &msg)
{
if (Logging)
{
@@ -354,8 +325,8 @@ void FileWriter::WriteLogLine(const std::string &line)
// XXX: For now, just return. Don't throw an exception. It'd be nice to find out if this is happening, but I'm terrified of breaking so close to final release. -- w00t
// throw CoreException("FileWriter::WriteLogLine called with a closed logfile");
- fprintf(log,"%s",line.c_str());
- if (writeops++ % 20)
+ fputs(line.c_str(), log);
+ if (++writeops % 20 == 0)
{
fflush(log);
}
diff --git a/src/mode.cpp b/src/mode.cpp
index 2a32dfac2..7deeb9b32 100644
--- a/src/mode.cpp
+++ b/src/mode.cpp
@@ -24,41 +24,18 @@
#include "inspircd.h"
+#include "builtinmodes.h"
-/* +s (secret) */
-/* +p (private) */
-/* +m (moderated) */
-/* +t (only (half) ops can change topic) */
-/* +n (no external messages) */
-/* +i (invite only) */
-/* +w (see wallops) */
-/* +i (invisible) */
-#include "modes/simplemodes.h"
-/* +b (bans) */
-#include "modes/cmode_b.h"
-/* +k (keyed channel) */
-#include "modes/cmode_k.h"
-/* +l (channel user limit) */
-#include "modes/cmode_l.h"
-/* +o (channel op) */
-#include "modes/cmode_o.h"
-/* +v (channel voice) */
-#include "modes/cmode_v.h"
-/* +o (operator) */
-#include "modes/umode_o.h"
-/* +s (server notice masks) */
-#include "modes/umode_s.h"
-
-ModeHandler::ModeHandler(Module* Creator, const std::string& Name, char modeletter, ParamSpec Params, ModeType type)
- : ServiceProvider(Creator, Name, SERVICE_MODE), m_paramtype(TR_TEXT),
- parameters_taken(Params), mode(modeletter), prefix(0), oper(false),
- list(false), m_type(type), levelrequired(HALFOP_VALUE)
+ModeHandler::ModeHandler(Module* Creator, const std::string& Name, char modeletter, ParamSpec Params, ModeType type, Class mclass)
+ : ServiceProvider(Creator, Name, SERVICE_MODE), modeid(ModeParser::MODEID_MAX), m_paramtype(TR_TEXT),
+ parameters_taken(Params), mode(modeletter), oper(false),
+ list(false), m_type(type), type_id(mclass), levelrequired(HALFOP_VALUE)
{
}
CullResult ModeHandler::cull()
{
- if (ServerInstance->Modes)
+ if (ServerInstance)
ServerInstance->Modes->DelMode(this);
return classbase::cull();
}
@@ -67,16 +44,6 @@ ModeHandler::~ModeHandler()
{
}
-bool ModeHandler::IsListMode()
-{
- return list;
-}
-
-unsigned int ModeHandler::GetPrefixRank()
-{
- return 0;
-}
-
int ModeHandler::GetNumParams(bool adding)
{
switch (parameters_taken)
@@ -127,7 +94,7 @@ ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel
{
/* We're either trying to add a mode we already have or
remove a mode we don't have, deny. */
- if (dest->IsModeSet(this->GetModeChar()) == adding)
+ if (dest->IsModeSet(this) == adding)
return MODEACTION_DENY;
/* adding will be either true or false, depending on if we
@@ -136,7 +103,7 @@ ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel
aren't removing a mode we don't have, we don't have to do any
other checks here to see if it's true or false, just add or
remove the mode */
- dest->SetMode(this->GetModeChar(), adding);
+ dest->SetMode(this, adding);
return MODEACTION_ALLOW;
}
@@ -146,7 +113,7 @@ ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Chan
{
/* We're either trying to add a mode we already have or
remove a mode we don't have, deny. */
- if (channel->IsModeSet(this->GetModeChar()) == adding)
+ if (channel->IsModeSet(this) == adding)
return MODEACTION_DENY;
/* adding will be either true or false, depending on if we
@@ -155,42 +122,20 @@ ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Chan
aren't removing a mode we don't have, we don't have to do any
other checks here to see if it's true or false, just add or
remove the mode */
- channel->SetMode(this->GetModeChar(), adding);
+ channel->SetMode(this, adding);
return MODEACTION_ALLOW;
}
-ModeAction ParamChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
-{
- if (adding && !ParamValidate(parameter))
- return MODEACTION_DENY;
- std::string now = channel->GetModeParameter(this);
- if (parameter == now)
- return MODEACTION_DENY;
- if (adding)
- channel->SetModeParam(this, parameter);
- else
- channel->SetModeParam(this, "");
- return MODEACTION_ALLOW;
-}
-
-bool ParamChannelModeHandler::ParamValidate(std::string& parameter)
-{
- return true;
-}
-
-ModeWatcher::ModeWatcher(Module* Creator, char modeletter, ModeType type)
- : mode(modeletter), m_type(type), creator(Creator)
+ModeWatcher::ModeWatcher(Module* Creator, const std::string& modename, ModeType type)
+ : mode(modename), m_type(type), creator(Creator)
{
+ ServerInstance->Modes->AddModeWatcher(this);
}
ModeWatcher::~ModeWatcher()
{
-}
-
-char ModeWatcher::GetModeChar()
-{
- return mode;
+ ServerInstance->Modes->DelModeWatcher(this);
}
ModeType ModeWatcher::GetModeType()
@@ -198,29 +143,13 @@ ModeType ModeWatcher::GetModeType()
return m_type;
}
-bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType)
+bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool)
{
return true;
}
-void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType)
-{
-}
-
-User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
+void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool)
{
- User *d;
- if ((!user) || (!dest) || (!chan) || (!*dest))
- {
- return NULL;
- }
- d = ServerInstance->FindNick(dest);
- if (!d)
- {
- user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), dest);
- return NULL;
- }
- return d;
}
void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
@@ -228,8 +157,8 @@ void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targ
if (targetchannel)
{
/* Display channel's current mode string */
- user->WriteNumeric(RPL_CHANNELMODEIS, "%s %s +%s",user->nick.c_str(), targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
- user->WriteNumeric(RPL_CHANNELCREATED, "%s %s %lu", user->nick.c_str(), targetchannel->name.c_str(), (unsigned long)targetchannel->age);
+ user->WriteNumeric(RPL_CHANNELMODEIS, "%s +%s", targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
+ user->WriteNumeric(RPL_CHANNELCREATED, "%s %lu", targetchannel->name.c_str(), (unsigned long)targetchannel->age);
return;
}
else
@@ -237,24 +166,82 @@ void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targ
if (targetuser == user || user->HasPrivPermission("users/auspex"))
{
/* Display user's current mode string */
- user->WriteNumeric(RPL_UMODEIS, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes());
- if (IS_OPER(targetuser))
- user->WriteNumeric(RPL_SNOMASKIS, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks());
+ user->WriteNumeric(RPL_UMODEIS, ":+%s", targetuser->FormatModes());
+ if ((targetuser->IsOper()))
+ {
+ ModeHandler* snomask = FindMode('s', MODETYPE_USER);
+ user->WriteNumeric(RPL_SNOMASKIS, "%s :Server notice mask", snomask->GetUserParameter(user).c_str());
+ }
return;
}
else
{
- user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't view modes for other users", user->nick.c_str());
+ user->WriteNumeric(ERR_USERSDONTMATCH, ":Can't view modes for other users");
return;
}
}
}
+PrefixMode::PrefixMode(Module* Creator, const std::string& Name, char ModeLetter)
+ : ModeHandler(Creator, Name, ModeLetter, PARAM_ALWAYS, MODETYPE_CHANNEL, MC_PREFIX)
+ , prefix(0), prefixrank(0)
+{
+ list = true;
+ m_paramtype = TR_NICK;
+}
+
+ModeAction PrefixMode::OnModeChange(User* source, User*, Channel* chan, std::string& parameter, bool adding)
+{
+ User* target;
+ if (IS_LOCAL(source))
+ target = ServerInstance->FindNickOnly(parameter);
+ else
+ target = ServerInstance->FindNick(parameter);
+
+ if (!target)
+ {
+ source->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", parameter.c_str());
+ return MODEACTION_DENY;
+ }
+
+ Membership* memb = chan->GetUser(target);
+ if (!memb)
+ return MODEACTION_DENY;
+
+ parameter = target->nick;
+ return (memb->SetPrefix(this, adding) ? MODEACTION_ALLOW : MODEACTION_DENY);
+}
+
+ModeAction ParamModeBase::OnModeChange(User* source, User*, Channel* chan, std::string& parameter, bool adding)
+{
+ if (adding)
+ {
+ if (chan->GetModeParameter(this) == parameter)
+ return MODEACTION_DENY;
+
+ if (OnSet(source, chan, parameter) != MODEACTION_ALLOW)
+ return MODEACTION_DENY;
+
+ chan->SetMode(this, true);
+
+ // Handler might have changed the parameter internally
+ parameter.clear();
+ this->GetParameter(chan, parameter);
+ }
+ else
+ {
+ if (!chan->IsModeSet(this))
+ return MODEACTION_DENY;
+ this->OnUnsetInternal(source, chan);
+ chan->SetMode(this, false);
+ }
+ return MODEACTION_ALLOW;
+}
+
ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool adding, const unsigned char modechar,
std::string &parameter, bool SkipACL)
{
ModeType type = chan ? MODETYPE_CHANNEL : MODETYPE_USER;
- unsigned char mask = chan ? MASK_CHANNEL : MASK_USER;
ModeHandler *mh = FindMode(modechar, type);
int pcnt = mh->GetNumParams(adding);
@@ -264,7 +251,7 @@ ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool
parameter = parameter.substr(0, 250);
ModResult MOD_RESULT;
- FIRST_MOD_RESULT(OnRawMode, MOD_RESULT, (user, chan, modechar, parameter, adding, pcnt));
+ FIRST_MOD_RESULT(OnRawMode, MOD_RESULT, (user, chan, mh, parameter, adding));
if (IS_LOCAL(user) && (MOD_RESULT == MOD_RES_DENY))
return MODEACTION_DENY;
@@ -286,10 +273,10 @@ ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool
unsigned int ourrank = chan->GetPrefixValue(user);
if (ourrank < neededrank)
{
- ModeHandler* neededmh = NULL;
+ PrefixMode* neededmh = NULL;
for(char c='A'; c <= 'z'; c++)
{
- ModeHandler *privmh = FindMode(c, MODETYPE_CHANNEL);
+ PrefixMode* privmh = FindPrefixMode(c);
if (privmh && privmh->GetPrefixRank() >= neededrank)
{
// this mode is sufficient to allow this action
@@ -298,34 +285,39 @@ ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool
}
}
if (neededmh)
- user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel %s access or above to %sset channel mode %c",
- user->nick.c_str(), chan->name.c_str(), neededmh->name.c_str(), adding ? "" : "un", modechar);
+ user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s :You must have channel %s access or above to %sset channel mode %c",
+ chan->name.c_str(), neededmh->name.c_str(), adding ? "" : "un", modechar);
else
- user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You cannot %sset channel mode %c",
- user->nick.c_str(), chan->name.c_str(), adding ? "" : "un", modechar);
+ user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s :You cannot %sset channel mode %c",
+ chan->name.c_str(), adding ? "" : "un", modechar);
return MODEACTION_DENY;
}
}
}
- unsigned char handler_id = (modechar - 'A') | mask;
-
- for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
+ // Ask mode watchers whether this mode change is OK
+ std::pair<ModeWatchIter, ModeWatchIter> itpair = modewatchermap.equal_range(mh->name);
+ for (ModeWatchIter i = itpair.first; i != itpair.second; ++i)
{
- if ((*watchers)->BeforeMode(user, targetuser, chan, parameter, adding, type) == false)
- return MODEACTION_DENY;
- /* A module whacked the parameter completely, and there was one. abort. */
- if (pcnt && parameter.empty())
- return MODEACTION_DENY;
+ ModeWatcher* mw = i->second;
+ if (mw->GetModeType() == type)
+ {
+ if (!mw->BeforeMode(user, targetuser, chan, parameter, adding))
+ return MODEACTION_DENY;
+
+ // A module whacked the parameter completely, and there was one. Abort.
+ if (pcnt && parameter.empty())
+ return MODEACTION_DENY;
+ }
}
- if (IS_LOCAL(user) && !IS_OPER(user))
+ if (IS_LOCAL(user) && !user->IsOper())
{
char* disabled = (type == MODETYPE_CHANNEL) ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes;
if (disabled[modechar - 'A'])
{
- user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - %s mode %c has been locked by the administrator",
- user->nick.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
+ user->WriteNumeric(ERR_NOPRIVILEGES, ":Permission Denied - %s mode %c has been locked by the administrator",
+ type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
return MODEACTION_DENY;
}
}
@@ -333,43 +325,19 @@ ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool
if (adding && IS_LOCAL(user) && mh->NeedsOper() && !user->HasModePermission(modechar, type))
{
/* It's an oper only mode, and they don't have access to it. */
- if (IS_OPER(user))
+ if (user->IsOper())
{
- user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
- user->nick.c_str(), user->oper->NameStr(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
+ user->WriteNumeric(ERR_NOPRIVILEGES, ":Permission Denied - Oper type %s does not have access to set %s mode %c",
+ user->oper->name.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
}
else
{
- user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
- user->nick.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
+ user->WriteNumeric(ERR_NOPRIVILEGES, ":Permission Denied - Only operators may set %s mode %c",
+ type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
}
return MODEACTION_DENY;
}
- if (mh->GetTranslateType() == TR_NICK)
- {
- User* prefixtarget;
- if (IS_LOCAL(user))
- prefixtarget = ServerInstance->FindNickOnly(parameter);
- else
- prefixtarget = ServerInstance->FindNick(parameter);
-
- if (!prefixtarget)
- {
- user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel", user->nick.c_str(), parameter.c_str());
- return MODEACTION_DENY;
- }
- }
-
- if (mh->GetPrefixRank() && chan)
- {
- User* user_to_prefix = ServerInstance->FindNick(parameter);
- if (!user_to_prefix)
- return MODEACTION_DENY;
- if (!chan->SetPrefix(user_to_prefix, modechar, adding))
- return MODEACTION_DENY;
- }
-
/* Call the handler for the mode */
ModeAction ma = mh->OnModeChange(user, targetuser, chan, parameter, adding);
@@ -379,13 +347,18 @@ ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool
if (ma != MODEACTION_ALLOW)
return ma;
- for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
- (*watchers)->AfterMode(user, targetuser, chan, parameter, adding, type);
+ itpair = modewatchermap.equal_range(mh->name);
+ for (ModeWatchIter i = itpair.first; i != itpair.second; ++i)
+ {
+ ModeWatcher* mw = i->second;
+ if (mw->GetModeType() == type)
+ mw->AfterMode(user, targetuser, chan, parameter, adding);
+ }
return MODEACTION_ALLOW;
}
-void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool merge)
+void ModeParser::Process(const std::vector<std::string>& parameters, User* user, ModeProcessFlag flags)
{
const std::string& target = parameters[0];
Channel* targetchannel = ServerInstance->FindChan(target);
@@ -405,7 +378,7 @@ void ModeParser::Process(const std::vector<std::string>& parameters, User *user,
if ((!targetchannel) && ((!targetuser) || (IS_SERVER(targetuser))))
{
- user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(),target.c_str());
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", target.c_str());
return;
}
if (parameters.size() == 1)
@@ -419,14 +392,14 @@ void ModeParser::Process(const std::vector<std::string>& parameters, User *user,
bool SkipAccessChecks = false;
- if (!IS_LOCAL(user) || ServerInstance->ULine(user->server) || MOD_RESULT == MOD_RES_ALLOW)
+ if (!IS_LOCAL(user) || MOD_RESULT == MOD_RES_ALLOW)
SkipAccessChecks = true;
else if (MOD_RESULT == MOD_RES_DENY)
return;
if (targetuser && !SkipAccessChecks && user != targetuser)
{
- user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
+ user->WriteNumeric(ERR_USERSDONTMATCH, ":Can't change mode for other users");
return;
}
@@ -454,7 +427,7 @@ void ModeParser::Process(const std::vector<std::string>& parameters, User *user,
if (!mh)
{
/* No mode handler? Unknown mode character then. */
- user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
+ user->WriteNumeric(type == MODETYPE_CHANNEL ? ERR_UNKNOWNMODE : ERR_UNKNOWNSNOMASK, "%c :is unknown mode char to me", modechar);
continue;
}
@@ -472,9 +445,9 @@ void ModeParser::Process(const std::vector<std::string>& parameters, User *user,
/* Make sure the user isn't trying to slip in an invalid parameter */
if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
continue;
- if (merge && targetchannel && targetchannel->IsModeSet(modechar) && !mh->IsListMode())
+ if ((flags & MODE_MERGE) && targetchannel && targetchannel->IsModeSet(mh) && !mh->IsListMode())
{
- std::string ours = targetchannel->GetModeParameter(modechar);
+ std::string ours = targetchannel->GetModeParameter(mh);
if (!mh->ResolveModeConflict(parameter, ours, targetchannel))
/* we won the mode merge, don't apply this mode */
continue;
@@ -496,16 +469,9 @@ void ModeParser::Process(const std::vector<std::string>& parameters, User *user,
if (pcnt)
{
- TranslateType tt = mh->GetTranslateType();
- if (tt == TR_NICK)
- {
- User* u = ServerInstance->FindNick(parameter);
- if (u)
- parameter = u->nick;
- }
output_parameters << " " << parameter;
LastParseParams.push_back(parameter);
- LastParseTranslate.push_back(tt);
+ LastParseTranslate.push_back(mh->GetTranslateType());
}
if ( (output_mode.length() + output_parameters.str().length() > 450)
@@ -526,16 +492,15 @@ void ModeParser::Process(const std::vector<std::string>& parameters, User *user,
LastParse.append(output_mode);
LastParse.append(output_parameters.str());
+ if (!(flags & MODE_LOCALONLY))
+ ServerInstance->PI->SendMode(user, targetuser, targetchannel, LastParseParams, LastParseTranslate);
+
if (targetchannel)
- {
- targetchannel->WriteChannel(user, "MODE %s", LastParse.c_str());
- FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, LastParseParams, LastParseTranslate));
- }
+ targetchannel->WriteChannel(user, "MODE " + LastParse);
else
- {
- targetuser->WriteFrom(user, "MODE %s", LastParse.c_str());
- FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, LastParseParams, LastParseTranslate));
- }
+ targetuser->WriteFrom(user, "MODE " + LastParse);
+
+ FOREACH_MOD(OnMode, (user, targetuser, targetchannel, LastParseParams, LastParseTranslate));
}
else if (targetchannel && parameters.size() == 2)
{
@@ -570,27 +535,36 @@ void ModeParser::DisplayListModes(User* user, Channel* chan, std::string &mode_s
return;
ModResult MOD_RESULT;
- FIRST_MOD_RESULT(OnRawMode, MOD_RESULT, (user, chan, mletter, "", true, 0));
+ FIRST_MOD_RESULT(OnRawMode, MOD_RESULT, (user, chan, mh, "", true));
if (MOD_RESULT == MOD_RES_DENY)
continue;
bool display = true;
if (!user->HasPrivPermission("channels/auspex") && ServerInstance->Config->HideModeLists[mletter] && (chan->GetPrefixValue(user) < HALFOP_VALUE))
{
- user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You do not have access to view the +%c list",
- user->nick.c_str(), chan->name.c_str(), mletter);
+ user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s :You do not have access to view the +%c list",
+ chan->name.c_str(), mletter);
display = false;
}
- unsigned char handler_id = (mletter - 'A') | MASK_CHANNEL;
-
- for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
+ // Ask mode watchers whether it's OK to show the list
+ std::pair<ModeWatchIter, ModeWatchIter> itpair = modewatchermap.equal_range(mh->name);
+ for (ModeWatchIter i = itpair.first; i != itpair.second; ++i)
{
- std::string dummyparam;
+ ModeWatcher* mw = i->second;
+ if (mw->GetModeType() == MODETYPE_CHANNEL)
+ {
+ std::string dummyparam;
- if (!((*watchers)->BeforeMode(user, NULL, chan, dummyparam, true, MODETYPE_CHANNEL)))
- display = false;
+ if (!mw->BeforeMode(user, NULL, chan, dummyparam, true))
+ {
+ // A mode watcher doesn't want us to show the list
+ display = false;
+ break;
+ }
+ }
}
+
if (display)
mh->DisplayList(user, chan);
else
@@ -598,11 +572,6 @@ void ModeParser::DisplayListModes(User* user, Channel* chan, std::string &mode_s
}
}
-const std::string& ModeParser::GetLastParse()
-{
- return LastParse;
-}
-
void ModeParser::CleanMask(std::string &mask)
{
std::string::size_type pos_of_pling = mask.find_first_of('!');
@@ -639,50 +608,83 @@ void ModeParser::CleanMask(std::string &mask)
}
}
-bool ModeParser::AddMode(ModeHandler* mh)
+ModeHandler::Id ModeParser::AllocateModeId(ModeType mt)
{
- unsigned char mask = 0;
- unsigned char pos = 0;
+ for (ModeHandler::Id i = 0; i != MODEID_MAX; ++i)
+ {
+ if (!modehandlersbyid[mt][i])
+ return i;
+ }
+ throw ModuleException("Out of ModeIds");
+}
+
+void ModeParser::AddMode(ModeHandler* mh)
+{
/* Yes, i know, this might let people declare modes like '_' or '^'.
* If they do that, thats their problem, and if i ever EVER see an
* official InspIRCd developer do that, i'll beat them with a paddle!
*/
- if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
- return false;
+ if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
+ throw ModuleException("Invalid letter for mode " + mh->name);
/* A mode prefix of ',' is not acceptable, it would fuck up server to server.
* A mode prefix of ':' will fuck up both server to server, and client to server.
* A mode prefix of '#' will mess up /whois and /privmsg
*/
- if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
- return false;
+ PrefixMode* pm = mh->IsPrefixMode();
+ if (pm)
+ {
+ if ((pm->GetPrefix() > 126) || (pm->GetPrefix() == ',') || (pm->GetPrefix() == ':') || (pm->GetPrefix() == '#'))
+ throw ModuleException("Invalid prefix for mode " + mh->name);
- if (mh->GetPrefix() && FindPrefix(mh->GetPrefix()))
- return false;
+ if (FindPrefix(pm->GetPrefix()))
+ throw ModuleException("Prefix already exists for mode " + mh->name);
+ }
- mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
- pos = (mh->GetModeChar()-65) | mask;
+ ModeHandler*& slot = modehandlers[mh->GetModeType()][mh->GetModeChar()-65];
+ if (slot)
+ throw ModuleException("Letter is already in use for mode " + mh->name);
- if (modehandlers[pos])
- return false;
+ // The mode needs an id if it is either a user mode, a simple mode (flag) or a parameter mode.
+ // Otherwise (for listmodes and prefix modes) the id remains MODEID_MAX, which is invalid.
+ ModeHandler::Id modeid = MODEID_MAX;
+ if ((mh->GetModeType() == MODETYPE_USER) || (mh->IsParameterMode()) || (!mh->IsListMode()))
+ modeid = AllocateModeId(mh->GetModeType());
- modehandlers[pos] = mh;
- return true;
+ if (!modehandlersbyname[mh->GetModeType()].insert(std::make_pair(mh->name, mh)).second)
+ throw ModuleException("Mode name already in use: " + mh->name);
+
+ // Everything is fine, add the mode
+
+ // If we allocated an id for this mode then save it and put the mode handler into the slot
+ if (modeid != MODEID_MAX)
+ {
+ mh->modeid = modeid;
+ modehandlersbyid[mh->GetModeType()][modeid] = mh;
+ }
+
+ slot = mh;
+ if (pm)
+ mhlist.prefix.push_back(pm);
+ else if (mh->IsListModeBase())
+ mhlist.list.push_back(mh->IsListModeBase());
+
+ RecreateModeListFor004Numeric();
}
bool ModeParser::DelMode(ModeHandler* mh)
{
- unsigned char mask = 0;
- unsigned char pos = 0;
-
if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
return false;
- mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
- pos = (mh->GetModeChar()-65) | mask;
+ ModeHandlerMap& mhmap = modehandlersbyname[mh->GetModeType()];
+ ModeHandlerMap::iterator mhmapit = mhmap.find(mh->name);
+ if ((mhmapit == mhmap.end()) || (mhmapit->second != mh))
+ return false;
- if (modehandlers[pos] != mh)
+ ModeHandler*& slot = modehandlers[mh->GetModeType()][mh->GetModeChar()-65];
+ if (slot != mh)
return false;
/* Note: We can't stack here, as we have modes potentially being removed across many different channels.
@@ -691,106 +693,111 @@ bool ModeParser::DelMode(ModeHandler* mh)
switch (mh->GetModeType())
{
case MODETYPE_USER:
- for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); )
+ {
+ const user_hash& users = ServerInstance->Users->GetUsers();
+ for (user_hash::const_iterator i = users.begin(); i != users.end(); )
{
User* user = i->second;
++i;
mh->RemoveMode(user);
}
+ }
break;
case MODETYPE_CHANNEL:
- for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); )
+ {
+ const chan_hash& chans = ServerInstance->GetChans();
+ for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); )
{
// The channel may not be in the hash after RemoveMode(), see m_permchannels
Channel* chan = i->second;
++i;
- mh->RemoveMode(chan);
+
+ irc::modestacker stack(false);
+ mh->RemoveMode(chan, stack);
+
+ std::vector<std::string> stackresult;
+ stackresult.push_back(chan->name);
+ while (stack.GetStackedLine(stackresult))
+ {
+ this->Process(stackresult, ServerInstance->FakeClient, MODE_LOCALONLY);
+ stackresult.erase(stackresult.begin() + 1, stackresult.end());
+ }
}
+ }
break;
}
- modehandlers[pos] = NULL;
+ mhmap.erase(mhmapit);
+ if (mh->GetId() != MODEID_MAX)
+ modehandlersbyid[mh->GetModeType()][mh->GetId()] = NULL;
+ slot = NULL;
+ if (mh->IsPrefixMode())
+ mhlist.prefix.erase(std::find(mhlist.prefix.begin(), mhlist.prefix.end(), mh->IsPrefixMode()));
+ else if (mh->IsListModeBase())
+ mhlist.list.erase(std::find(mhlist.list.begin(), mhlist.list.end(), mh->IsListModeBase()));
+ RecreateModeListFor004Numeric();
return true;
}
-ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
+ModeHandler* ModeParser::FindMode(const std::string& modename, ModeType mt)
{
- unsigned char mask = 0;
- unsigned char pos = 0;
+ ModeHandlerMap& mhmap = modehandlersbyname[mt];
+ ModeHandlerMap::const_iterator it = mhmap.find(modename);
+ if (it != mhmap.end())
+ return it->second;
+ return NULL;
+}
+
+ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
+{
if ((modeletter < 'A') || (modeletter > 'z'))
return NULL;
- mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
- pos = (modeletter-65) | mask;
-
- return modehandlers[pos];
+ return modehandlers[mt][modeletter-65];
}
-std::string ModeParser::UserModeList()
+PrefixMode* ModeParser::FindPrefixMode(unsigned char modeletter)
{
- char modestr[256];
- int pointer = 0;
-
- for (unsigned char mode = 'A'; mode <= 'z'; mode++)
- {
- unsigned char pos = (mode-65) | MASK_USER;
-
- if (modehandlers[pos])
- modestr[pointer++] = mode;
- }
- modestr[pointer++] = 0;
- return modestr;
+ ModeHandler* mh = FindMode(modeletter, MODETYPE_CHANNEL);
+ if (!mh)
+ return NULL;
+ return mh->IsPrefixMode();
}
-std::string ModeParser::ChannelModeList()
+std::string ModeParser::CreateModeList(ModeType mt, bool needparam)
{
- char modestr[256];
- int pointer = 0;
+ std::string modestr;
for (unsigned char mode = 'A'; mode <= 'z'; mode++)
{
- unsigned char pos = (mode-65) | MASK_CHANNEL;
-
- if (modehandlers[pos])
- modestr[pointer++] = mode;
+ ModeHandler* mh = modehandlers[mt][mode-65];
+ if ((mh) && ((!needparam) || (mh->GetNumParams(true))))
+ modestr.push_back(mode);
}
- modestr[pointer++] = 0;
+
return modestr;
}
-std::string ModeParser::ParaModeList()
+void ModeParser::RecreateModeListFor004Numeric()
{
- char modestr[256];
- int pointer = 0;
-
- for (unsigned char mode = 'A'; mode <= 'z'; mode++)
- {
- unsigned char pos = (mode-65) | MASK_CHANNEL;
-
- if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
- modestr[pointer++] = mode;
- }
- modestr[pointer++] = 0;
- return modestr;
+ Cached004ModeList = CreateModeList(MODETYPE_USER) + " " + CreateModeList(MODETYPE_CHANNEL) + " " + CreateModeList(MODETYPE_CHANNEL, true);
}
-ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
+PrefixMode* ModeParser::FindPrefix(unsigned const char pfxletter)
{
- for (unsigned char mode = 'A'; mode <= 'z'; mode++)
+ const PrefixModeList& list = GetPrefixModes();
+ for (PrefixModeList::const_iterator i = list.begin(); i != list.end(); ++i)
{
- unsigned char pos = (mode-65) | MASK_CHANNEL;
-
- if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
- {
- return modehandlers[pos];
- }
+ PrefixMode* pm = *i;
+ if (pm->GetPrefix() == pfxletter)
+ return pm;
}
return NULL;
}
-std::string ModeParser::GiveModeList(ModeMasks m)
+std::string ModeParser::GiveModeList(ModeType mt)
{
std::string type1; /* Listmodes EXCEPT those with a prefix */
std::string type2; /* Modes that take a param when adding or removing */
@@ -799,37 +806,38 @@ std::string ModeParser::GiveModeList(ModeMasks m)
for (unsigned char mode = 'A'; mode <= 'z'; mode++)
{
- unsigned char pos = (mode-65) | m;
+ ModeHandler* mh = modehandlers[mt][mode-65];
/* One parameter when adding */
- if (modehandlers[pos])
+ if (mh)
{
- if (modehandlers[pos]->GetNumParams(true))
+ if (mh->GetNumParams(true))
{
- if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
+ PrefixMode* pm = mh->IsPrefixMode();
+ if ((mh->IsListMode()) && ((!pm) || (pm->GetPrefix() == 0)))
{
- type1 += modehandlers[pos]->GetModeChar();
+ type1 += mh->GetModeChar();
}
else
{
/* ... and one parameter when removing */
- if (modehandlers[pos]->GetNumParams(false))
+ if (mh->GetNumParams(false))
{
/* But not a list mode */
- if (!modehandlers[pos]->GetPrefix())
+ if (!pm)
{
- type2 += modehandlers[pos]->GetModeChar();
+ type2 += mh->GetModeChar();
}
}
else
{
/* No parameters when removing */
- type3 += modehandlers[pos]->GetModeChar();
+ type3 += mh->GetModeChar();
}
}
}
else
{
- type4 += modehandlers[pos]->GetModeChar();
+ type4 += mh->GetModeChar();
}
}
}
@@ -843,15 +851,12 @@ std::string ModeParser::BuildPrefixes(bool lettersAndModes)
std::string mprefixes;
std::map<int,std::pair<char,char> > prefixes;
- for (unsigned char mode = 'A'; mode <= 'z'; mode++)
+ const PrefixModeList& list = GetPrefixModes();
+ for (PrefixModeList::const_iterator i = list.begin(); i != list.end(); ++i)
{
- unsigned char pos = (mode-65) | MASK_CHANNEL;
-
- if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
- {
- prefixes[modehandlers[pos]->GetPrefixRank()] = std::make_pair(
- modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetModeChar());
- }
+ PrefixMode* pm = *i;
+ if (pm->GetPrefix())
+ prefixes[pm->GetPrefixRank()] = std::make_pair(pm->GetPrefix(), pm->GetModeChar());
}
for(std::map<int,std::pair<char,char> >::reverse_iterator n = prefixes.rbegin(); n != prefixes.rend(); n++)
@@ -863,91 +868,58 @@ std::string ModeParser::BuildPrefixes(bool lettersAndModes)
return lettersAndModes ? "(" + mprefixes + ")" + mletters : mletters;
}
-bool ModeParser::AddModeWatcher(ModeWatcher* mw)
+void ModeParser::AddModeWatcher(ModeWatcher* mw)
{
- unsigned char mask = 0;
- unsigned char pos = 0;
-
- if (!mw)
- return false;
-
- if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
- return false;
-
- mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
- pos = (mw->GetModeChar()-65) | mask;
-
- modewatchers[pos].push_back(mw);
-
- return true;
+ modewatchermap.insert(std::make_pair(mw->GetModeName(), mw));
}
bool ModeParser::DelModeWatcher(ModeWatcher* mw)
{
- unsigned char mask = 0;
- unsigned char pos = 0;
-
- if (!mw)
- return false;
-
- if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
- return false;
-
- mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
- pos = (mw->GetModeChar()-65) | mask;
-
- ModeWatchIter a = std::find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
-
- if (a == modewatchers[pos].end())
+ std::pair<ModeWatchIter, ModeWatchIter> itpair = modewatchermap.equal_range(mw->GetModeName());
+ for (ModeWatchIter i = itpair.first; i != itpair.second; ++i)
{
- return false;
+ if (i->second == mw)
+ {
+ modewatchermap.erase(i);
+ return true;
+ }
}
- modewatchers[pos].erase(a);
-
- return true;
+ return false;
}
-/** This default implementation can remove simple user modes
- */
-void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
+void ModeHandler::RemoveMode(User* user)
{
+ // Remove the mode if it's set on the user
if (user->IsModeSet(this->GetModeChar()))
{
- if (stack)
- {
- stack->Push(this->GetModeChar());
- }
- else
- {
- std::vector<std::string> parameters;
- parameters.push_back(user->nick);
- parameters.push_back("-");
- parameters[1].push_back(this->GetModeChar());
- ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient);
- }
+ std::vector<std::string> parameters;
+ parameters.push_back(user->nick);
+ parameters.push_back("-");
+ parameters[1].push_back(this->GetModeChar());
+ ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient, ModeParser::MODE_LOCALONLY);
}
}
-/** This default implementation can remove simple channel modes
- * (no parameters)
- */
-void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
+void ModeHandler::RemoveMode(Channel* channel, irc::modestacker& stack)
{
- if (channel->IsModeSet(this->GetModeChar()))
+ if (channel->IsModeSet(this))
{
- if (stack)
- {
- stack->Push(this->GetModeChar());
- }
+ if (this->GetNumParams(false))
+ // Removing this mode requires a parameter
+ stack.Push(this->GetModeChar(), channel->GetModeParameter(this));
else
- {
- std::vector<std::string> parameters;
- parameters.push_back(channel->name);
- parameters.push_back("-");
- parameters[1].push_back(this->GetModeChar());
- ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
- }
+ stack.Push(this->GetModeChar());
+ }
+}
+
+void PrefixMode::RemoveMode(Channel* chan, irc::modestacker& stack)
+{
+ const Channel::MemberMap& userlist = chan->GetUsers();
+ for (Channel::MemberMap::const_iterator i = userlist.begin(); i != userlist.end(); ++i)
+ {
+ if (i->second->hasMode(this->GetModeChar()))
+ stack.Push(this->GetModeChar(), i->first->nick);
}
}
@@ -967,45 +939,34 @@ struct builtin_modes
ModeChannelOp o;
ModeChannelVoice v;
- ModeUserWallops uw;
ModeUserInvisible ui;
ModeUserOperator uo;
ModeUserServerNoticeMask us;
- void init(ModeParser* modes)
- {
- modes->AddMode(&s);
- modes->AddMode(&p);
- modes->AddMode(&m);
- modes->AddMode(&t);
- modes->AddMode(&n);
- modes->AddMode(&i);
- modes->AddMode(&k);
- modes->AddMode(&l);
- modes->AddMode(&b);
- modes->AddMode(&o);
- modes->AddMode(&v);
- modes->AddMode(&uw);
- modes->AddMode(&ui);
- modes->AddMode(&uo);
- modes->AddMode(&us);
+ void init()
+ {
+ ServiceProvider* modes[] = { &s, &p, &m, &t, &n, &i, &k, &l, &b, &o, &v,
+ &ui, &uo, &us };
+ ServerInstance->Modules->AddServices(modes, sizeof(modes)/sizeof(ServiceProvider*));
}
};
static builtin_modes static_modes;
+void ModeParser::InitBuiltinModes()
+{
+ static_modes.init();
+ static_modes.b.DoRehash();
+}
+
ModeParser::ModeParser()
{
/* Clear mode handler list */
memset(modehandlers, 0, sizeof(modehandlers));
-
- /* Last parse string */
- LastParse.clear();
+ memset(modehandlersbyid, 0, sizeof(modehandlersbyid));
seq = 0;
memset(&sent, 0, sizeof(sent));
-
- static_modes.init(this);
}
ModeParser::~ModeParser()
diff --git a/src/modes/cmode_b.cpp b/src/modes/cmode_b.cpp
deleted file mode 100644
index 09df05100..000000000
--- a/src/modes/cmode_b.cpp
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
- * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-#include <string>
-#include <vector>
-#include "inspircd_config.h"
-#include "configreader.h"
-#include "hash_map.h"
-#include "mode.h"
-#include "channels.h"
-#include "users.h"
-#include "modules.h"
-#include "inspstring.h"
-#include "hashcomp.h"
-#include "modes/cmode_b.h"
-
-ModeChannelBan::ModeChannelBan() : ModeHandler(NULL, "ban", 'b', PARAM_ALWAYS, MODETYPE_CHANNEL)
-{
- list = true;
-}
-
-ModeAction ModeChannelBan::OnModeChange(User* source, User*, Channel* channel, std::string &parameter, bool adding)
-{
- int status = channel->GetPrefixValue(source);
- /* Call the correct method depending on wether we're adding or removing the mode */
- if (adding)
- {
- this->AddBan(source, parameter, channel, status);
- }
- else
- {
- this->DelBan(source, parameter, channel, status);
- }
- /* If the method above 'ate' the parameter by reducing it to an empty string, then
- * it won't matter wether we return ALLOW or DENY here, as an empty string overrides
- * the return value and is always MODEACTION_DENY if the mode is supposed to have
- * a parameter.
- */
- return MODEACTION_ALLOW;
-}
-
-void ModeChannelBan::RemoveMode(Channel* channel, irc::modestacker* stack)
-{
- BanList copy;
-
- for (BanList::iterator i = channel->bans.begin(); i != channel->bans.end(); i++)
- {
- copy.push_back(*i);
- }
-
- for (BanList::iterator i = copy.begin(); i != copy.end(); i++)
- {
- if (stack)
- {
- stack->Push(this->GetModeChar(), i->data);
- }
- else
- {
- std::vector<std::string> parameters; parameters.push_back(channel->name); parameters.push_back("-b"); parameters.push_back(i->data);
- ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
- }
- }
-}
-
-void ModeChannelBan::RemoveMode(User*, irc::modestacker* stack)
-{
-}
-
-void ModeChannelBan::DisplayList(User* user, Channel* channel)
-{
- /* Display the channel banlist */
- for (BanList::reverse_iterator i = channel->bans.rbegin(); i != channel->bans.rend(); ++i)
- {
- user->WriteServ("367 %s %s %s %s %lu",user->nick.c_str(), channel->name.c_str(), i->data.c_str(), i->set_by.c_str(), (unsigned long)i->set_time);
- }
- user->WriteServ("368 %s %s :End of channel ban list",user->nick.c_str(), channel->name.c_str());
- return;
-}
-
-void ModeChannelBan::DisplayEmptyList(User* user, Channel* channel)
-{
- user->WriteServ("368 %s %s :End of channel ban list",user->nick.c_str(), channel->name.c_str());
-}
-
-std::string& ModeChannelBan::AddBan(User *user, std::string &dest, Channel *chan, int)
-{
- if ((!user) || (!chan))
- {
- ServerInstance->Logs->Log("MODE",DEFAULT,"*** BUG *** AddBan was given an invalid parameter");
- dest.clear();
- return dest;
- }
-
- /* Attempt to tidy the mask */
- ModeParser::CleanMask(dest);
- /* If the mask was invalid, we exit */
- if (dest.empty() || dest.length() > 250)
- return dest;
-
- long maxbans = chan->GetMaxBans();
- if (IS_LOCAL(user) && ((unsigned)chan->bans.size() >= (unsigned)maxbans))
- {
- user->WriteServ("478 %s %s :Channel ban list for %s is full (maximum entries for this channel is %ld)",user->nick.c_str(), chan->name.c_str(), chan->name.c_str(), maxbans);
- dest.clear();
- return dest;
- }
-
- ModResult MOD_RESULT;
- FIRST_MOD_RESULT(OnAddBan, MOD_RESULT, (user,chan,dest));
- if (MOD_RESULT == MOD_RES_DENY)
- {
- dest.clear();
- return dest;
- }
-
- for (BanList::iterator i = chan->bans.begin(); i != chan->bans.end(); i++)
- {
- if (i->data == dest)
- {
- /* dont allow a user to set the same ban twice */
- dest.clear();
- return dest;
- }
- }
-
- b.set_time = ServerInstance->Time();
- b.data.assign(dest, 0, MAXBUF);
- b.set_by.assign(user->nick, 0, 64);
- chan->bans.push_back(b);
- return dest;
-}
-
-std::string& ModeChannelBan::DelBan(User *user, std::string& dest, Channel *chan, int)
-{
- if ((!user) || (!chan))
- {
- ServerInstance->Logs->Log("MODE",DEFAULT,"*** BUG *** TakeBan was given an invalid parameter");
- dest.clear();
- return dest;
- }
-
- for (BanList::iterator i = chan->bans.begin(); i != chan->bans.end(); i++)
- {
- if (!strcasecmp(i->data.c_str(), dest.c_str()))
- {
- ModResult MOD_RESULT;
- FIRST_MOD_RESULT(OnDelBan, MOD_RESULT, (user, chan, dest));
- if (MOD_RESULT == MOD_RES_DENY)
- {
- dest.clear();
- return dest;
- }
- chan->bans.erase(i);
- return dest;
- }
- }
- dest.clear();
- return dest;
-}
-
diff --git a/src/modes/cmode_k.cpp b/src/modes/cmode_k.cpp
index 400333fce..0f8070cb4 100644
--- a/src/modes/cmode_k.cpp
+++ b/src/modes/cmode_k.cpp
@@ -21,79 +21,53 @@
#include "inspircd.h"
-#include "mode.h"
-#include "channels.h"
-#include "users.h"
-#include "modes/cmode_k.h"
+#include "builtinmodes.h"
-ModeChannelKey::ModeChannelKey() : ModeHandler(NULL, "key", 'k', PARAM_ALWAYS, MODETYPE_CHANNEL)
-{
-}
-
-void ModeChannelKey::RemoveMode(Channel* channel, irc::modestacker* stack)
-{
- /** +k needs a parameter when being removed,
- * so we have a special-case RemoveMode here for it
- */
-
- if (channel->IsModeSet('k'))
- {
- if (stack)
- {
- stack->Push('k', channel->GetModeParameter('k'));
- }
- else
- {
- std::vector<std::string> parameters;
- parameters.push_back(channel->name);
- parameters.push_back("-k");
- parameters.push_back(channel->GetModeParameter('k'));
- ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
- }
- }
-}
-
-void ModeChannelKey::RemoveMode(User*, irc::modestacker* stack)
+ModeChannelKey::ModeChannelKey()
+ : ParamMode<ModeChannelKey, LocalStringExt>(NULL, "key", 'k', PARAM_ALWAYS)
{
}
ModeAction ModeChannelKey::OnModeChange(User* source, User*, Channel* channel, std::string &parameter, bool adding)
{
- bool exists = channel->IsModeSet('k');
+ const std::string* key = ext.get(channel);
+ bool exists = (key != NULL);
if (IS_LOCAL(source))
{
if (exists == adding)
return MODEACTION_DENY;
- if (exists && (parameter != channel->GetModeParameter('k')))
+ if (exists && (parameter != *key))
{
/* Key is currently set and the correct key wasnt given */
return MODEACTION_DENY;
}
} else {
- if (exists && adding && parameter == channel->GetModeParameter('k'))
+ if (exists && adding && parameter == *key)
{
/* no-op, don't show */
return MODEACTION_DENY;
}
}
- /* invalid keys */
- if (!parameter.length())
- return MODEACTION_DENY;
-
- if (parameter.rfind(' ') != std::string::npos)
- return MODEACTION_DENY;
-
+ channel->SetMode(this, adding);
if (adding)
{
- std::string ckey;
- ckey.assign(parameter, 0, 32);
- parameter = ckey;
- channel->SetModeParam('k', parameter);
+ parameter = parameter.substr(0, 32);
+ ext.set(channel, parameter);
}
else
- {
- channel->SetModeParam('k', "");
- }
+ ext.unset(channel);
+
return MODEACTION_ALLOW;
}
+
+void ModeChannelKey::SerializeParam(Channel* chan, const std::string* key, std::string& out)
+{
+ out += *key;
+}
+
+ModeAction ModeChannelKey::OnSet(User* source, Channel* chan, std::string& param)
+{
+ // Dummy function, never called
+ return MODEACTION_DENY;
+}
diff --git a/src/modes/cmode_l.cpp b/src/modes/cmode_l.cpp
index 001d058bb..9121d64ec 100644
--- a/src/modes/cmode_l.cpp
+++ b/src/modes/cmode_l.cpp
@@ -20,12 +20,10 @@
#include "inspircd.h"
-#include "mode.h"
-#include "channels.h"
-#include "users.h"
-#include "modes/cmode_l.h"
+#include "builtinmodes.h"
-ModeChannelLimit::ModeChannelLimit() : ParamChannelModeHandler(NULL, "limit", 'l')
+ModeChannelLimit::ModeChannelLimit()
+ : ParamMode<ModeChannelLimit, LocalIntExt>(NULL, "limit", 'l')
{
}
@@ -35,13 +33,13 @@ bool ModeChannelLimit::ResolveModeConflict(std::string &their_param, const std::
return (atoi(their_param.c_str()) < atoi(our_param.c_str()));
}
-bool ModeChannelLimit::ParamValidate(std::string &parameter)
+ModeAction ModeChannelLimit::OnSet(User* user, Channel* chan, std::string& parameter)
{
- int limit = atoi(parameter.c_str());
-
- if (limit < 0)
- return false;
+ ext.set(chan, ConvToInt(parameter));
+ return MODEACTION_ALLOW;
+}
- parameter = ConvToStr(limit);
- return true;
+void ModeChannelLimit::SerializeParam(Channel* chan, intptr_t n, std::string& out)
+{
+ out += ConvToStr(n);
}
diff --git a/src/modes/cmode_o.cpp b/src/modes/cmode_o.cpp
index 0a13b39ce..496a32718 100644
--- a/src/modes/cmode_o.cpp
+++ b/src/modes/cmode_o.cpp
@@ -21,50 +21,11 @@
#include "inspircd.h"
-#include "configreader.h"
-#include "mode.h"
-#include "channels.h"
-#include "users.h"
-#include "modules.h"
-#include "modes/cmode_o.h"
+#include "builtinmodes.h"
-ModeChannelOp::ModeChannelOp() : ModeHandler(NULL, "op", 'o', PARAM_ALWAYS, MODETYPE_CHANNEL)
+ModeChannelOp::ModeChannelOp() : PrefixMode(NULL, "op", 'o')
{
- list = true;
prefix = '@';
levelrequired = OP_VALUE;
- m_paramtype = TR_NICK;
-}
-
-unsigned int ModeChannelOp::GetPrefixRank()
-{
- return OP_VALUE;
-}
-
-void ModeChannelOp::RemoveMode(Channel* channel, irc::modestacker* stack)
-{
- const UserMembList* clist = channel->GetUsers();
-
- for (UserMembCIter i = clist->begin(); i != clist->end(); i++)
- {
- if (stack)
- stack->Push(this->GetModeChar(), i->first->nick);
- else
- {
- std::vector<std::string> parameters;
- parameters.push_back(channel->name);
- parameters.push_back("-o");
- parameters.push_back(i->first->nick);
- ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
- }
- }
-}
-
-void ModeChannelOp::RemoveMode(User*, irc::modestacker* stack)
-{
-}
-
-ModeAction ModeChannelOp::OnModeChange(User* source, User*, Channel* channel, std::string &parameter, bool adding)
-{
- return MODEACTION_ALLOW;
+ prefixrank = OP_VALUE;
}
diff --git a/src/modes/cmode_v.cpp b/src/modes/cmode_v.cpp
index 4a00f60f1..d6108a984 100644
--- a/src/modes/cmode_v.cpp
+++ b/src/modes/cmode_v.cpp
@@ -21,50 +21,11 @@
#include "inspircd.h"
-#include "configreader.h"
-#include "mode.h"
-#include "channels.h"
-#include "users.h"
-#include "modules.h"
-#include "modes/cmode_v.h"
+#include "builtinmodes.h"
-ModeChannelVoice::ModeChannelVoice() : ModeHandler(NULL, "voice", 'v', PARAM_ALWAYS, MODETYPE_CHANNEL)
+ModeChannelVoice::ModeChannelVoice() : PrefixMode(NULL, "voice", 'v')
{
- list = true;
prefix = '+';
levelrequired = HALFOP_VALUE;
- m_paramtype = TR_NICK;
-}
-
-unsigned int ModeChannelVoice::GetPrefixRank()
-{
- return VOICE_VALUE;
-}
-
-void ModeChannelVoice::RemoveMode(Channel* channel, irc::modestacker* stack)
-{
- const UserMembList* clist = channel->GetUsers();
-
- for (UserMembCIter i = clist->begin(); i != clist->end(); i++)
- {
- if (stack)
- stack->Push(this->GetModeChar(), i->first->nick);
- else
- {
- std::vector<std::string> parameters;
- parameters.push_back(channel->name);
- parameters.push_back("-v");
- parameters.push_back(i->first->nick);
- ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
- }
- }
-}
-
-void ModeChannelVoice::RemoveMode(User*, irc::modestacker* stack)
-{
-}
-
-ModeAction ModeChannelVoice::OnModeChange(User* source, User*, Channel* channel, std::string &parameter, bool adding)
-{
- return MODEACTION_ALLOW;
+ prefixrank = VOICE_VALUE;
}
diff --git a/src/modes/umode_o.cpp b/src/modes/umode_o.cpp
index a5f590ba0..6e9517a4f 100644
--- a/src/modes/umode_o.cpp
+++ b/src/modes/umode_o.cpp
@@ -19,10 +19,7 @@
#include "inspircd.h"
-#include "mode.h"
-#include "channels.h"
-#include "users.h"
-#include "modes/umode_o.h"
+#include "builtinmodes.h"
ModeUserOperator::ModeUserOperator() : ModeHandler(NULL, "oper", 'o', PARAM_NONE, MODETYPE_USER)
{
@@ -32,7 +29,7 @@ ModeUserOperator::ModeUserOperator() : ModeHandler(NULL, "oper", 'o', PARAM_NONE
ModeAction ModeUserOperator::OnModeChange(User* source, User* dest, Channel*, std::string&, bool adding)
{
/* Only opers can execute this class at all */
- if (!ServerInstance->ULine(source->server) && !IS_OPER(source))
+ if (!source->server->IsULine() && !source->IsOper())
return MODEACTION_DENY;
/* Not even opers can GIVE the +o mode, only take it away */
@@ -46,8 +43,7 @@ ModeAction ModeUserOperator::OnModeChange(User* source, User* dest, Channel*, st
* to your User!
*/
char snomask = IS_LOCAL(dest) ? 'o' : 'O';
- ServerInstance->SNO->WriteToSnoMask(snomask, "User %s de-opered (by %s)", dest->nick.c_str(),
- source->nick.empty() ? source->server.c_str() : source->nick.c_str());
+ ServerInstance->SNO->WriteToSnoMask(snomask, "User %s de-opered (by %s)", dest->nick.c_str(), source->nick.c_str());
dest->UnOper();
return MODEACTION_ALLOW;
diff --git a/src/modes/umode_s.cpp b/src/modes/umode_s.cpp
index 1b782ae85..08ee7f562 100644
--- a/src/modes/umode_s.cpp
+++ b/src/modes/umode_s.cpp
@@ -20,10 +20,7 @@
#include "inspircd.h"
-#include "mode.h"
-#include "channels.h"
-#include "users.h"
-#include "modes/umode_s.h"
+#include "builtinmodes.h"
ModeUserServerNoticeMask::ModeUserServerNoticeMask() : ModeHandler(NULL, "snomask", 's', PARAM_SETONLY, MODETYPE_USER)
{
@@ -32,41 +29,116 @@ ModeUserServerNoticeMask::ModeUserServerNoticeMask() : ModeHandler(NULL, "snomas
ModeAction ModeUserServerNoticeMask::OnModeChange(User* source, User* dest, Channel*, std::string &parameter, bool adding)
{
- /* Set the array fields */
if (adding)
{
- /* Fix for bug #310 reported by Smartys */
- if (!dest->modes[UM_SNOMASK])
- dest->snomasks.reset();
-
- dest->modes[UM_SNOMASK] = true;
- parameter = dest->ProcessNoticeMasks(parameter.c_str());
+ dest->SetMode(this, true);
+ // Process the parameter (remove chars we don't understand, remove redundant chars, etc.)
+ parameter = ProcessNoticeMasks(dest, parameter);
return MODEACTION_ALLOW;
}
else
{
- if (dest->modes[UM_SNOMASK] != false)
+ if (dest->IsModeSet(this))
{
- dest->modes[UM_SNOMASK] = false;
+ dest->SetMode(this, false);
+ dest->snomasks.reset();
return MODEACTION_ALLOW;
}
}
- /* Allow the change */
+ // Mode not set and trying to unset, deny
return MODEACTION_DENY;
}
std::string ModeUserServerNoticeMask::GetUserParameter(User* user)
{
- std::string masks = user->FormatNoticeMasks();
- if (masks.length())
- masks = "+" + masks;
- return masks;
+ std::string ret;
+ if (!user->IsModeSet(this))
+ return ret;
+
+ ret.push_back('+');
+ for (unsigned char n = 0; n < 64; n++)
+ {
+ if (user->snomasks[n])
+ ret.push_back(n + 'A');
+ }
+ return ret;
}
void ModeUserServerNoticeMask::OnParameterMissing(User* user, User* dest, Channel* channel)
{
- user->WriteServ("NOTICE %s :*** The user mode +s requires a parameter (server notice mask). Please provide a parameter, e.g. '+s +*'.",
- user->nick.c_str());
+ user->WriteNotice("*** The user mode +s requires a parameter (server notice mask). Please provide a parameter, e.g. '+s +*'.");
}
+std::string ModeUserServerNoticeMask::ProcessNoticeMasks(User* user, const std::string& input)
+{
+ bool adding = true;
+ std::bitset<64> curr = user->snomasks;
+
+ for (std::string::const_iterator i = input.begin(); i != input.end(); ++i)
+ {
+ switch (*i)
+ {
+ case '+':
+ adding = true;
+ break;
+ case '-':
+ adding = false;
+ break;
+ case '*':
+ for (size_t j = 0; j < 64; j++)
+ {
+ if (ServerInstance->SNO->IsSnomaskUsable(j+'A'))
+ curr[j] = adding;
+ }
+ break;
+ default:
+ // For local users check whether the given snomask is valid and enabled - IsSnomaskUsable() tests both.
+ // For remote users accept what we were told, unless the snomask char is not a letter.
+ if (IS_LOCAL(user))
+ {
+ if (!ServerInstance->SNO->IsSnomaskUsable(*i))
+ {
+ user->WriteNumeric(ERR_UNKNOWNSNOMASK, "%c :is unknown snomask char to me", *i);
+ continue;
+ }
+ }
+ else if (!(((*i >= 'a') && (*i <= 'z')) || ((*i >= 'A') && (*i <= 'Z'))))
+ continue;
+
+ size_t index = ((*i) - 'A');
+ curr[index] = adding;
+ break;
+ }
+ }
+
+ std::string plus = "+";
+ std::string minus = "-";
+
+ // Apply changes and construct two strings consisting of the newly added and the removed snomask chars
+ for (size_t i = 0; i < 64; i++)
+ {
+ bool isset = curr[i];
+ if (user->snomasks[i] != isset)
+ {
+ user->snomasks[i] = isset;
+ std::string& appendhere = (isset ? plus : minus);
+ appendhere.push_back(i+'A');
+ }
+ }
+
+ // Create the final string that will be shown to the user and sent to servers
+ // Form: "+ABc-de"
+ std::string output;
+ if (plus.length() > 1)
+ output = plus;
+
+ if (minus.length() > 1)
+ output += minus;
+
+ // Unset the snomask usermode itself if every snomask was unset
+ if (user->snomasks.none())
+ user->SetMode(this, false);
+
+ return output;
+}
diff --git a/src/modmanager_dynamic.cpp b/src/modmanager_dynamic.cpp
index 045b488b5..184013a4e 100644
--- a/src/modmanager_dynamic.cpp
+++ b/src/modmanager_dynamic.cpp
@@ -18,11 +18,6 @@
#include "inspircd.h"
-#include "xline.h"
-#include "socket.h"
-#include "socketengine.h"
-#include "command_parse.h"
-#include "dns.h"
#include "exitcodes.h"
#include <iostream>
@@ -38,29 +33,32 @@ bool ModuleManager::Load(const std::string& filename, bool defer)
if (filename.find('/') != std::string::npos)
return false;
- char modfile[MAXBUF];
- snprintf(modfile,MAXBUF,"%s/%s",ServerInstance->Config->ModPath.c_str(),filename.c_str());
+ const std::string moduleFile = ServerInstance->Config->Paths.PrependModule(filename);
- if (!ServerConfig::FileExists(modfile))
+ if (!FileSystem::FileExists(moduleFile))
{
LastModuleError = "Module file could not be found: " + filename;
- ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError);
+ ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError);
return false;
}
if (Modules.find(filename) != Modules.end())
{
LastModuleError = "Module " + filename + " is already loaded, cannot load a module twice!";
- ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError);
+ ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError);
return false;
}
Module* newmod = NULL;
- DLLManager* newhandle = new DLLManager(modfile);
+ DLLManager* newhandle = new DLLManager(moduleFile.c_str());
+ ServiceList newservices;
+ if (!defer)
+ this->NewServices = &newservices;
try
{
newmod = newhandle->CallInit();
+ this->NewServices = NULL;
if (newmod)
{
@@ -71,28 +69,35 @@ bool ModuleManager::Load(const std::string& filename, bool defer)
std::string version = newhandle->GetVersion();
if (defer)
{
- ServerInstance->Logs->Log("MODULE", DEFAULT,"New module introduced: %s (Module version %s)",
+ ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "New module introduced: %s (Module version %s)",
filename.c_str(), version.c_str());
}
else
{
+ ConfigStatus confstatus;
+
+ AttachAll(newmod);
+ AddServices(newservices);
newmod->init();
+ newmod->ReadConfig(confstatus);
Version v = newmod->GetVersion();
- ServerInstance->Logs->Log("MODULE", DEFAULT,"New module introduced: %s (Module version %s)%s",
+ ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "New module introduced: %s (Module version %s)%s",
filename.c_str(), version.c_str(), (!(v.Flags & VF_VENDOR) ? " [3rd Party]" : " [Vendor]"));
}
}
else
{
LastModuleError = "Unable to load " + filename + ": " + newhandle->LastError();
- ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError);
+ ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError);
delete newhandle;
return false;
}
}
catch (CoreException& modexcept)
{
+ this->NewServices = NULL;
+
// failure in module constructor
if (newmod)
{
@@ -102,109 +107,41 @@ bool ModuleManager::Load(const std::string& filename, bool defer)
else
delete newhandle;
LastModuleError = "Unable to load " + filename + ": " + modexcept.GetReason();
- ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError);
+ ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError);
return false;
}
- this->ModCount++;
if (defer)
return true;
- FOREACH_MOD(I_OnLoadModule,OnLoadModule(newmod));
- /* We give every module a chance to re-prioritize when we introduce a new one,
- * not just the one thats loading, as the new module could affect the preference
- * of others
- */
- for(int tries = 0; tries < 20; tries++)
- {
- prioritizationState = tries > 0 ? PRIO_STATE_LAST : PRIO_STATE_FIRST;
- for (std::map<std::string, Module*>::iterator n = Modules.begin(); n != Modules.end(); ++n)
- n->second->Prioritize();
-
- if (prioritizationState == PRIO_STATE_LAST)
- break;
- if (tries == 19)
- ServerInstance->Logs->Log("MODULE", DEFAULT, "Hook priority dependency loop detected while loading " + filename);
- }
-
- ServerInstance->BuildISupport();
- return true;
-}
-
-namespace {
- struct UnloadAction : public HandlerBase0<void>
- {
- Module* const mod;
- UnloadAction(Module* m) : mod(m) {}
- void Call()
- {
- DLLManager* dll = mod->ModuleDLLManager;
- ServerInstance->Modules->DoSafeUnload(mod);
- ServerInstance->GlobalCulls.Apply();
- delete dll;
- ServerInstance->GlobalCulls.AddItem(this);
- }
- };
-
- struct ReloadAction : public HandlerBase0<void>
- {
- Module* const mod;
- HandlerBase1<void, bool>* const callback;
- ReloadAction(Module* m, HandlerBase1<void, bool>* c)
- : mod(m), callback(c) {}
- void Call()
- {
- DLLManager* dll = mod->ModuleDLLManager;
- std::string name = mod->ModuleSourceFile;
- ServerInstance->Modules->DoSafeUnload(mod);
- ServerInstance->GlobalCulls.Apply();
- delete dll;
- bool rv = ServerInstance->Modules->Load(name.c_str());
- if (callback)
- callback->Call(rv);
- ServerInstance->GlobalCulls.AddItem(this);
- }
- };
-}
-
-bool ModuleManager::Unload(Module* mod)
-{
- if (!CanUnload(mod))
- return false;
- ServerInstance->AtomicActions.AddAction(new UnloadAction(mod));
+ FOREACH_MOD(OnLoadModule, (newmod));
+ PrioritizeHooks();
+ ServerInstance->ISupport.Build();
return true;
}
-void ModuleManager::Reload(Module* mod, HandlerBase1<void, bool>* callback)
-{
- if (CanUnload(mod))
- ServerInstance->AtomicActions.AddAction(new ReloadAction(mod, callback));
- else if (callback)
- callback->Call(false);
-}
-
/* We must load the modules AFTER initializing the socket engine, now */
-void ModuleManager::LoadAll()
+void ModuleManager::LoadCoreModules(std::map<std::string, ServiceList>& servicemap)
{
- ModCount = 0;
-
std::cout << std::endl << "Loading core commands";
fflush(stdout);
- DIR* library = opendir(ServerInstance->Config->ModPath.c_str());
+ DIR* library = opendir(ServerInstance->Config->Paths.Module.c_str());
if (library)
{
dirent* entry = NULL;
while (0 != (entry = readdir(library)))
{
- if (InspIRCd::Match(entry->d_name, "cmd_*.so", ascii_case_insensitive_map))
+ if (InspIRCd::Match(entry->d_name, "core_*.so", ascii_case_insensitive_map))
{
std::cout << ".";
fflush(stdout);
+ this->NewServices = &servicemap[entry->d_name];
+
if (!Load(entry->d_name, true))
{
- ServerInstance->Logs->Log("MODULE", DEFAULT, this->LastError());
+ ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, this->LastError());
std::cout << std::endl << "[" << con_red << "*" << con_reset << "] " << this->LastError() << std::endl << std::endl;
ServerInstance->Exit(EXIT_STATUS_MODULE);
}
@@ -213,57 +150,6 @@ void ModuleManager::LoadAll()
closedir(library);
std::cout << std::endl;
}
-
- ConfigTagList tags = ServerInstance->Config->ConfTags("module");
- for(ConfigIter i = tags.first; i != tags.second; ++i)
- {
- ConfigTag* tag = i->second;
- std::string name = tag->getString("name");
- std::cout << "[" << con_green << "*" << con_reset << "] Loading module:\t" << con_green << name << con_reset << std::endl;
-
- if (!this->Load(name, true))
- {
- ServerInstance->Logs->Log("MODULE", DEFAULT, this->LastError());
- std::cout << std::endl << "[" << con_red << "*" << con_reset << "] " << this->LastError() << std::endl << std::endl;
- ServerInstance->Exit(EXIT_STATUS_MODULE);
- }
- }
-
- for(std::map<std::string, Module*>::iterator i = Modules.begin(); i != Modules.end(); i++)
- {
- Module* mod = i->second;
- try
- {
- ServerInstance->Logs->Log("MODULE", DEBUG, "Initializing %s", i->first.c_str());
- mod->init();
- }
- catch (CoreException& modexcept)
- {
- LastModuleError = "Unable to initialize " + mod->ModuleSourceFile + ": " + modexcept.GetReason();
- ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError);
- std::cout << std::endl << "[" << con_red << "*" << con_reset << "] " << LastModuleError << std::endl << std::endl;
- ServerInstance->Exit(EXIT_STATUS_MODULE);
- }
- }
-
- /* We give every module a chance to re-prioritize when we introduce a new one,
- * not just the one thats loading, as the new module could affect the preference
- * of others
- */
- for(int tries = 0; tries < 20; tries++)
- {
- prioritizationState = tries > 0 ? PRIO_STATE_LAST : PRIO_STATE_FIRST;
- for (std::map<std::string, Module*>::iterator n = Modules.begin(); n != Modules.end(); ++n)
- n->second->Prioritize();
-
- if (prioritizationState == PRIO_STATE_LAST)
- break;
- if (tries == 19)
- {
- ServerInstance->Logs->Log("MODULE", DEFAULT, "Hook priority dependency loop detected");
- ServerInstance->Exit(EXIT_STATUS_MODULE);
- }
- }
}
#endif
diff --git a/src/modmanager_static.cpp b/src/modmanager_static.cpp
index c5b1e1062..ac127b703 100644
--- a/src/modmanager_static.cpp
+++ b/src/modmanager_static.cpp
@@ -17,7 +17,7 @@
*/
-#define MODNAME cmd_all
+#define MODNAME "cmd_all"
#include "inspircd.h"
#include "exitcodes.h"
@@ -58,7 +58,6 @@ class AllModule : public Module
{
Command* c = (*i)(this);
cmds.push_back(c);
- ServerInstance->AddCommand(c);
}
}
catch (...)
@@ -70,8 +69,7 @@ class AllModule : public Module
~AllModule()
{
- for(std::vector<Command*>::iterator i = cmds.begin(); i != cmds.end(); ++i)
- delete *i;
+ stdalgo::delete_all(cmds);
}
Version GetVersion()
@@ -88,6 +86,11 @@ bool ModuleManager::Load(const std::string& name, bool defer)
if (it == modlist->end())
return false;
Module* mod = NULL;
+
+ ServiceList newservices;
+ if (!defer)
+ this->NewServices = &newservices;
+
try
{
mod = (*it->second->init)();
@@ -95,146 +98,50 @@ bool ModuleManager::Load(const std::string& name, bool defer)
mod->ModuleDLLManager = NULL;
mod->dying = false;
Modules[name] = mod;
+ this->NewServices = NULL;
if (defer)
{
- ServerInstance->Logs->Log("MODULE", DEFAULT,"New module introduced: %s", name.c_str());
+ ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "New module introduced: %s", name.c_str());
return true;
}
else
{
+ ConfigStatus confstatus;
+
+ AttachAll(mod);
+ AddServices(newservices);
mod->init();
+ mod->ReadConfig(confstatus);
}
}
catch (CoreException& modexcept)
{
+ this->NewServices = NULL;
+
if (mod)
DoSafeUnload(mod);
- ServerInstance->Logs->Log("MODULE", DEFAULT, "Unable to load " + name + ": " + modexcept.GetReason());
+ ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "Unable to load " + name + ": " + modexcept.GetReason());
return false;
}
- FOREACH_MOD(I_OnLoadModule,OnLoadModule(mod));
- /* We give every module a chance to re-prioritize when we introduce a new one,
- * not just the one thats loading, as the new module could affect the preference
- * of others
- */
- for(int tries = 0; tries < 20; tries++)
- {
- prioritizationState = tries > 0 ? PRIO_STATE_LAST : PRIO_STATE_FIRST;
- for (std::map<std::string, Module*>::iterator n = Modules.begin(); n != Modules.end(); ++n)
- n->second->Prioritize();
-
- if (prioritizationState == PRIO_STATE_LAST)
- break;
- if (tries == 19)
- ServerInstance->Logs->Log("MODULE", DEFAULT, "Hook priority dependency loop detected while loading " + name);
- }
-
- ServerInstance->BuildISupport();
- return true;
-}
-
-namespace {
- struct UnloadAction : public HandlerBase0<void>
- {
- Module* const mod;
- UnloadAction(Module* m) : mod(m) {}
- void Call()
- {
- ServerInstance->Modules->DoSafeUnload(mod);
- ServerInstance->GlobalCulls.Apply();
- ServerInstance->GlobalCulls.AddItem(this);
- }
- };
-
- struct ReloadAction : public HandlerBase0<void>
- {
- Module* const mod;
- HandlerBase1<void, bool>* const callback;
- ReloadAction(Module* m, HandlerBase1<void, bool>* c)
- : mod(m), callback(c) {}
- void Call()
- {
- std::string name = mod->ModuleSourceFile;
- ServerInstance->Modules->DoSafeUnload(mod);
- ServerInstance->GlobalCulls.Apply();
- bool rv = ServerInstance->Modules->Load(name.c_str());
- callback->Call(rv);
- ServerInstance->GlobalCulls.AddItem(this);
- }
- };
-}
-bool ModuleManager::Unload(Module* mod)
-{
- if (!CanUnload(mod))
- return false;
- ServerInstance->AtomicActions.AddAction(new UnloadAction(mod));
+ FOREACH_MOD(OnLoadModule, (mod));
+ PrioritizeHooks();
+ ServerInstance->ISupport.Build();
return true;
}
-void ModuleManager::Reload(Module* mod, HandlerBase1<void, bool>* callback)
+void ModuleManager::LoadCoreModules(std::map<std::string, ServiceList>& servicemap)
{
- if (CanUnload(mod))
- ServerInstance->AtomicActions.AddAction(new ReloadAction(mod, callback));
- else if (callback)
- callback->Call(false);
-}
-
-void ModuleManager::LoadAll()
-{
- Load("cmd_all", true);
- Load("cmd_whowas.so", true);
- Load("cmd_lusers.so", true);
-
- ConfigTagList tags = ServerInstance->Config->ConfTags("module");
- for(ConfigIter i = tags.first; i != tags.second; ++i)
- {
- ConfigTag* tag = i->second;
- std::string name = tag->getString("name");
- std::cout << "[" << con_green << "*" << con_reset << "] Loading module:\t" << con_green << name << con_reset << std::endl;
-
- if (!this->Load(name, true))
- {
- ServerInstance->Logs->Log("MODULE", DEFAULT, this->LastError());
- std::cout << std::endl << "[" << con_red << "*" << con_reset << "] " << this->LastError() << std::endl << std::endl;
- ServerInstance->Exit(EXIT_STATUS_MODULE);
- }
- }
-
- for(std::map<std::string, Module*>::iterator i = Modules.begin(); i != Modules.end(); i++)
+ for (modmap::const_iterator i = modlist->begin(); i != modlist->end(); ++i)
{
- Module* mod = i->second;
- try
- {
- mod->init();
- }
- catch (CoreException& modexcept)
- {
- LastModuleError = "Unable to initialize " + mod->ModuleSourceFile + ": " + modexcept.GetReason();
- ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError);
- std::cout << std::endl << "[" << con_red << "*" << con_reset << "] " << LastModuleError << std::endl << std::endl;
- ServerInstance->Exit(EXIT_STATUS_MODULE);
- }
- }
-
- /* We give every module a chance to re-prioritize when we introduce a new one,
- * not just the one thats loading, as the new module could affect the preference
- * of others
- */
- for(int tries = 0; tries < 20; tries++)
- {
- prioritizationState = tries > 0 ? PRIO_STATE_LAST : PRIO_STATE_FIRST;
- for (std::map<std::string, Module*>::iterator n = Modules.begin(); n != Modules.end(); ++n)
- n->second->Prioritize();
-
- if (prioritizationState == PRIO_STATE_LAST)
- break;
- if (tries == 19)
+ const std::string modname = i->first;
+ if (modname[0] == 'c')
{
- ServerInstance->Logs->Log("MODULE", DEFAULT, "Hook priority dependency loop detected");
- ServerInstance->Exit(EXIT_STATUS_MODULE);
+ this->NewServices = &servicemap[modname];
+ Load(modname, true);
}
}
+ this->NewServices = NULL;
}
#endif
diff --git a/src/modules.cpp b/src/modules.cpp
index b2d2f23c6..42a9e8010 100644
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@ -24,26 +24,22 @@
*/
+#include <iostream>
#include "inspircd.h"
-#include "xline.h"
-#include "socket.h"
-#include "socketengine.h"
-#include "command_parse.h"
-#include "dns.h"
#include "exitcodes.h"
#ifndef _WIN32
#include <dirent.h>
#endif
-static std::vector<dynamic_reference_base*>* dynrefs = NULL;
+static intrusive_list<dynamic_reference_base>* dynrefs = NULL;
void dynamic_reference_base::reset_all()
{
if (!dynrefs)
return;
- for(unsigned int i = 0; i < dynrefs->size(); i++)
- (*dynrefs)[i]->ClearCache();
+ for (intrusive_list<dynamic_reference_base>::iterator i = dynrefs->begin(); i != dynrefs->end(); ++i)
+ (*i)->resolve();
}
// Version is a simple class for holding a modules version number
@@ -56,22 +52,11 @@ Version::Version(const std::string &desc, int flags, const std::string& linkdata
{
}
-Request::Request(Module* src, Module* dst, const char* idstr)
-: id(idstr), source(src), dest(dst)
-{
-}
-
-void Request::Send()
-{
- if (dest)
- dest->OnRequest(*this);
-}
-
Event::Event(Module* src, const std::string &eventid) : source(src), id(eventid) { }
void Event::Send()
{
- FOREACH_MOD(I_OnEvent,OnEvent(*this));
+ FOREACH_MOD(OnEvent, (*this));
}
// These declarations define the behavours of the base class Module (which does nothing at all)
@@ -85,100 +70,110 @@ Module::~Module()
{
}
-ModResult Module::OnSendSnotice(char &snomask, std::string &type, const std::string &message) { return MOD_RES_PASSTHRU; }
-void Module::OnUserConnect(LocalUser*) { }
-void Module::OnUserQuit(User*, const std::string&, const std::string&) { }
-void Module::OnUserDisconnect(LocalUser*) { }
-void Module::OnUserJoin(Membership*, bool, bool, CUList&) { }
-void Module::OnPostJoin(Membership*) { }
-void Module::OnUserPart(Membership*, std::string&, CUList&) { }
-void Module::OnPreRehash(User*, const std::string&) { }
-void Module::OnModuleRehash(User*, const std::string&) { }
-void Module::OnRehash(User*) { }
-ModResult Module::OnUserPreJoin(User*, Channel*, const char*, std::string&, const std::string&) { return MOD_RES_PASSTHRU; }
-void Module::OnMode(User*, void*, int, const std::vector<std::string>&, const std::vector<TranslateType>&) { }
-void Module::OnOper(User*, const std::string&) { }
-void Module::OnPostOper(User*, const std::string&, const std::string &) { }
-void Module::OnInfo(User*) { }
-void Module::OnWhois(User*, User*) { }
-ModResult Module::OnUserPreInvite(User*, User*, Channel*, time_t) { return MOD_RES_PASSTHRU; }
-ModResult Module::OnUserPreMessage(User*, void*, int, std::string&, char, CUList&) { return MOD_RES_PASSTHRU; }
-ModResult Module::OnUserPreNotice(User*, void*, int, std::string&, char, CUList&) { return MOD_RES_PASSTHRU; }
-ModResult Module::OnUserPreNick(User*, const std::string&) { return MOD_RES_PASSTHRU; }
-void Module::OnUserPostNick(User*, const std::string&) { }
-ModResult Module::OnPreMode(User*, User*, Channel*, const std::vector<std::string>&) { return MOD_RES_PASSTHRU; }
-void Module::On005Numeric(std::string&) { }
-ModResult Module::OnKill(User*, User*, const std::string&) { return MOD_RES_PASSTHRU; }
-void Module::OnLoadModule(Module*) { }
-void Module::OnUnloadModule(Module*) { }
-void Module::OnBackgroundTimer(time_t) { }
-ModResult Module::OnPreCommand(std::string&, std::vector<std::string>&, LocalUser*, bool, const std::string&) { return MOD_RES_PASSTHRU; }
-void Module::OnPostCommand(const std::string&, const std::vector<std::string>&, LocalUser*, CmdResult, const std::string&) { }
-void Module::OnUserInit(LocalUser*) { }
-ModResult Module::OnCheckReady(LocalUser*) { return MOD_RES_PASSTHRU; }
-ModResult Module::OnUserRegister(LocalUser*) { return MOD_RES_PASSTHRU; }
-ModResult Module::OnUserPreKick(User*, Membership*, const std::string&) { return MOD_RES_PASSTHRU; }
-void Module::OnUserKick(User*, Membership*, const std::string&, CUList&) { }
-ModResult Module::OnRawMode(User*, Channel*, const char, const std::string &, bool, int) { return MOD_RES_PASSTHRU; }
-ModResult Module::OnCheckInvite(User*, Channel*) { return MOD_RES_PASSTHRU; }
-ModResult Module::OnCheckKey(User*, Channel*, const std::string&) { return MOD_RES_PASSTHRU; }
-ModResult Module::OnCheckLimit(User*, Channel*) { return MOD_RES_PASSTHRU; }
-ModResult Module::OnCheckChannelBan(User*, Channel*) { return MOD_RES_PASSTHRU; }
-ModResult Module::OnCheckBan(User*, Channel*, const std::string&) { return MOD_RES_PASSTHRU; }
-ModResult Module::OnExtBanCheck(User*, Channel*, char) { return MOD_RES_PASSTHRU; }
-ModResult Module::OnStats(char, User*, string_list&) { return MOD_RES_PASSTHRU; }
-ModResult Module::OnChangeLocalUserHost(LocalUser*, const std::string&) { return MOD_RES_PASSTHRU; }
-ModResult Module::OnChangeLocalUserGECOS(LocalUser*, const std::string&) { return MOD_RES_PASSTHRU; }
-ModResult Module::OnPreTopicChange(User*, Channel*, const std::string&) { return MOD_RES_PASSTHRU; }
-void Module::OnEvent(Event&) { }
-void Module::OnRequest(Request&) { }
-ModResult Module::OnPassCompare(Extensible* ex, const std::string &password, const std::string &input, const std::string& hashtype) { return MOD_RES_PASSTHRU; }
-void Module::OnGlobalOper(User*) { }
-void Module::OnPostConnect(User*) { }
-ModResult Module::OnAddBan(User*, Channel*, const std::string &) { return MOD_RES_PASSTHRU; }
-ModResult Module::OnDelBan(User*, Channel*, const std::string &) { return MOD_RES_PASSTHRU; }
-void Module::OnStreamSocketAccept(StreamSocket*, irc::sockets::sockaddrs*, irc::sockets::sockaddrs*) { }
-int Module::OnStreamSocketWrite(StreamSocket*, std::string&) { return -1; }
-void Module::OnStreamSocketClose(StreamSocket*) { }
-void Module::OnStreamSocketConnect(StreamSocket*) { }
-int Module::OnStreamSocketRead(StreamSocket*, std::string&) { return -1; }
-void Module::OnUserMessage(User*, void*, int, const std::string&, char, const CUList&) { }
-void Module::OnUserNotice(User*, void*, int, const std::string&, char, const CUList&) { }
-void Module::OnRemoteKill(User*, User*, const std::string&, const std::string&) { }
-void Module::OnUserInvite(User*, User*, Channel*, time_t) { }
-void Module::OnPostTopicChange(User*, Channel*, const std::string&) { }
-void Module::OnGetServerDescription(const std::string&, std::string&) { }
-void Module::OnSyncUser(User*, Module*, void*) { }
-void Module::OnSyncChannel(Channel*, Module*, void*) { }
-void Module::OnSyncNetwork(Module*, void*) { }
-void Module::ProtoSendMode(void*, TargetTypeFlags, void*, const std::vector<std::string>&, const std::vector<TranslateType>&) { }
-void Module::OnDecodeMetaData(Extensible*, const std::string&, const std::string&) { }
-void Module::ProtoSendMetaData(void*, Extensible*, const std::string&, const std::string&) { }
-void Module::OnWallops(User*, const std::string&) { }
-void Module::OnChangeHost(User*, const std::string&) { }
-void Module::OnChangeName(User*, const std::string&) { }
-void Module::OnChangeIdent(User*, const std::string&) { }
-void Module::OnAddLine(User*, XLine*) { }
-void Module::OnDelLine(User*, XLine*) { }
-void Module::OnExpireLine(XLine*) { }
+void Module::DetachEvent(Implementation i)
+{
+ ServerInstance->Modules->Detach(i, this);
+}
+
+void Module::ReadConfig(ConfigStatus& status) { }
+ModResult Module::OnSendSnotice(char &snomask, std::string &type, const std::string &message) { DetachEvent(I_OnSendSnotice); return MOD_RES_PASSTHRU; }
+void Module::OnUserConnect(LocalUser*) { DetachEvent(I_OnUserConnect); }
+void Module::OnUserQuit(User*, const std::string&, const std::string&) { DetachEvent(I_OnUserQuit); }
+void Module::OnUserDisconnect(LocalUser*) { DetachEvent(I_OnUserDisconnect); }
+void Module::OnUserJoin(Membership*, bool, bool, CUList&) { DetachEvent(I_OnUserJoin); }
+void Module::OnPostJoin(Membership*) { DetachEvent(I_OnPostJoin); }
+void Module::OnUserPart(Membership*, std::string&, CUList&) { DetachEvent(I_OnUserPart); }
+void Module::OnPreRehash(User*, const std::string&) { DetachEvent(I_OnPreRehash); }
+void Module::OnModuleRehash(User*, const std::string&) { DetachEvent(I_OnModuleRehash); }
+ModResult Module::OnUserPreJoin(LocalUser*, Channel*, const std::string&, std::string&, const std::string&) { DetachEvent(I_OnUserPreJoin); return MOD_RES_PASSTHRU; }
+void Module::OnMode(User*, User*, Channel*, const std::vector<std::string>&, const std::vector<TranslateType>&) { DetachEvent(I_OnMode); }
+void Module::OnOper(User*, const std::string&) { DetachEvent(I_OnOper); }
+void Module::OnPostOper(User*, const std::string&, const std::string &) { DetachEvent(I_OnPostOper); }
+void Module::OnInfo(User*) { DetachEvent(I_OnInfo); }
+void Module::OnWhois(User*, User*) { DetachEvent(I_OnWhois); }
+ModResult Module::OnUserPreInvite(User*, User*, Channel*, time_t) { DetachEvent(I_OnUserPreInvite); return MOD_RES_PASSTHRU; }
+ModResult Module::OnUserPreMessage(User*, void*, int, std::string&, char, CUList&, MessageType) { DetachEvent(I_OnUserPreMessage); return MOD_RES_PASSTHRU; }
+ModResult Module::OnUserPreNick(LocalUser*, const std::string&) { DetachEvent(I_OnUserPreNick); return MOD_RES_PASSTHRU; }
+void Module::OnUserPostNick(User*, const std::string&) { DetachEvent(I_OnUserPostNick); }
+ModResult Module::OnPreMode(User*, User*, Channel*, const std::vector<std::string>&) { DetachEvent(I_OnPreMode); return MOD_RES_PASSTHRU; }
+void Module::On005Numeric(std::map<std::string, std::string>&) { DetachEvent(I_On005Numeric); }
+ModResult Module::OnKill(User*, User*, const std::string&) { DetachEvent(I_OnKill); return MOD_RES_PASSTHRU; }
+void Module::OnLoadModule(Module*) { DetachEvent(I_OnLoadModule); }
+void Module::OnUnloadModule(Module*) { DetachEvent(I_OnUnloadModule); }
+void Module::OnBackgroundTimer(time_t) { DetachEvent(I_OnBackgroundTimer); }
+ModResult Module::OnPreCommand(std::string&, std::vector<std::string>&, LocalUser*, bool, const std::string&) { DetachEvent(I_OnPreCommand); return MOD_RES_PASSTHRU; }
+void Module::OnPostCommand(Command*, const std::vector<std::string>&, LocalUser*, CmdResult, const std::string&) { DetachEvent(I_OnPostCommand); }
+void Module::OnUserInit(LocalUser*) { DetachEvent(I_OnUserInit); }
+ModResult Module::OnCheckReady(LocalUser*) { DetachEvent(I_OnCheckReady); return MOD_RES_PASSTHRU; }
+ModResult Module::OnUserRegister(LocalUser*) { DetachEvent(I_OnUserRegister); return MOD_RES_PASSTHRU; }
+ModResult Module::OnUserPreKick(User*, Membership*, const std::string&) { DetachEvent(I_OnUserPreKick); return MOD_RES_PASSTHRU; }
+void Module::OnUserKick(User*, Membership*, const std::string&, CUList&) { DetachEvent(I_OnUserKick); }
+ModResult Module::OnRawMode(User*, Channel*, ModeHandler*, const std::string&, bool) { DetachEvent(I_OnRawMode); return MOD_RES_PASSTHRU; }
+ModResult Module::OnCheckInvite(User*, Channel*) { DetachEvent(I_OnCheckInvite); return MOD_RES_PASSTHRU; }
+ModResult Module::OnCheckKey(User*, Channel*, const std::string&) { DetachEvent(I_OnCheckKey); return MOD_RES_PASSTHRU; }
+ModResult Module::OnCheckLimit(User*, Channel*) { DetachEvent(I_OnCheckLimit); return MOD_RES_PASSTHRU; }
+ModResult Module::OnCheckChannelBan(User*, Channel*) { DetachEvent(I_OnCheckChannelBan); return MOD_RES_PASSTHRU; }
+ModResult Module::OnCheckBan(User*, Channel*, const std::string&) { DetachEvent(I_OnCheckBan); return MOD_RES_PASSTHRU; }
+ModResult Module::OnExtBanCheck(User*, Channel*, char) { DetachEvent(I_OnExtBanCheck); return MOD_RES_PASSTHRU; }
+ModResult Module::OnStats(char, User*, string_list&) { DetachEvent(I_OnStats); return MOD_RES_PASSTHRU; }
+ModResult Module::OnChangeLocalUserHost(LocalUser*, const std::string&) { DetachEvent(I_OnChangeLocalUserHost); return MOD_RES_PASSTHRU; }
+ModResult Module::OnChangeLocalUserGECOS(LocalUser*, const std::string&) { DetachEvent(I_OnChangeLocalUserGECOS); return MOD_RES_PASSTHRU; }
+ModResult Module::OnPreTopicChange(User*, Channel*, const std::string&) { DetachEvent(I_OnPreTopicChange); return MOD_RES_PASSTHRU; }
+void Module::OnEvent(Event&) { DetachEvent(I_OnEvent); }
+ModResult Module::OnPassCompare(Extensible* ex, const std::string &password, const std::string &input, const std::string& hashtype) { DetachEvent(I_OnPassCompare); return MOD_RES_PASSTHRU; }
+void Module::OnGlobalOper(User*) { DetachEvent(I_OnGlobalOper); }
+void Module::OnPostConnect(User*) { DetachEvent(I_OnPostConnect); }
+void Module::OnUserMessage(User*, void*, int, const std::string&, char, const CUList&, MessageType) { DetachEvent(I_OnUserMessage); }
+void Module::OnUserInvite(User*, User*, Channel*, time_t) { DetachEvent(I_OnUserInvite); }
+void Module::OnPostTopicChange(User*, Channel*, const std::string&) { DetachEvent(I_OnPostTopicChange); }
+void Module::OnSyncUser(User*, ProtocolInterface::Server&) { DetachEvent(I_OnSyncUser); }
+void Module::OnSyncChannel(Channel*, ProtocolInterface::Server&) { DetachEvent(I_OnSyncChannel); }
+void Module::OnSyncNetwork(ProtocolInterface::Server&) { DetachEvent(I_OnSyncNetwork); }
+void Module::OnDecodeMetaData(Extensible*, const std::string&, const std::string&) { DetachEvent(I_OnDecodeMetaData); }
+void Module::OnChangeHost(User*, const std::string&) { DetachEvent(I_OnChangeHost); }
+void Module::OnChangeName(User*, const std::string&) { DetachEvent(I_OnChangeName); }
+void Module::OnChangeIdent(User*, const std::string&) { DetachEvent(I_OnChangeIdent); }
+void Module::OnAddLine(User*, XLine*) { DetachEvent(I_OnAddLine); }
+void Module::OnDelLine(User*, XLine*) { DetachEvent(I_OnDelLine); }
+void Module::OnExpireLine(XLine*) { DetachEvent(I_OnExpireLine); }
void Module::OnCleanup(int, void*) { }
-ModResult Module::OnChannelPreDelete(Channel*) { return MOD_RES_PASSTHRU; }
-void Module::OnChannelDelete(Channel*) { }
-ModResult Module::OnSetAway(User*, const std::string &) { return MOD_RES_PASSTHRU; }
-ModResult Module::OnWhoisLine(User*, User*, int&, std::string&) { return MOD_RES_PASSTHRU; }
-void Module::OnBuildNeighborList(User*, UserChanList&, std::map<User*,bool>&) { }
-void Module::OnGarbageCollect() { }
-ModResult Module::OnSetConnectClass(LocalUser* user, ConnectClass* myclass) { return MOD_RES_PASSTHRU; }
-void Module::OnText(User*, void*, int, const std::string&, char, CUList&) { }
+ModResult Module::OnChannelPreDelete(Channel*) { DetachEvent(I_OnChannelPreDelete); return MOD_RES_PASSTHRU; }
+void Module::OnChannelDelete(Channel*) { DetachEvent(I_OnChannelDelete); }
+ModResult Module::OnSetAway(User*, const std::string &) { DetachEvent(I_OnSetAway); return MOD_RES_PASSTHRU; }
+ModResult Module::OnWhoisLine(User*, User*, int&, std::string&) { DetachEvent(I_OnWhoisLine); return MOD_RES_PASSTHRU; }
+void Module::OnBuildNeighborList(User*, IncludeChanList&, std::map<User*,bool>&) { DetachEvent(I_OnBuildNeighborList); }
+void Module::OnGarbageCollect() { DetachEvent(I_OnGarbageCollect); }
+ModResult Module::OnSetConnectClass(LocalUser* user, ConnectClass* myclass) { DetachEvent(I_OnSetConnectClass); return MOD_RES_PASSTHRU; }
+void Module::OnText(User*, void*, int, const std::string&, char, CUList&) { DetachEvent(I_OnText); }
+ModResult Module::OnNamesListItem(User*, Membership*, std::string&, std::string&) { DetachEvent(I_OnNamesListItem); return MOD_RES_PASSTHRU; }
+ModResult Module::OnNumeric(User*, unsigned int, const std::string&) { DetachEvent(I_OnNumeric); return MOD_RES_PASSTHRU; }
+ModResult Module::OnAcceptConnection(int, ListenSocket*, irc::sockets::sockaddrs*, irc::sockets::sockaddrs*) { DetachEvent(I_OnAcceptConnection); return MOD_RES_PASSTHRU; }
+void Module::OnSendWhoLine(User*, const std::vector<std::string>&, User*, Membership*, std::string&) { DetachEvent(I_OnSendWhoLine); }
+void Module::OnSetUserIP(LocalUser*) { DetachEvent(I_OnSetUserIP); }
+
+#ifdef INSPIRCD_ENABLE_TESTSUITE
void Module::OnRunTestSuite() { }
-void Module::OnNamesListItem(User*, Membership*, std::string&, std::string&) { }
-ModResult Module::OnNumeric(User*, unsigned int, const std::string&) { return MOD_RES_PASSTHRU; }
-void Module::OnHookIO(StreamSocket*, ListenSocket*) { }
-ModResult Module::OnAcceptConnection(int, ListenSocket*, irc::sockets::sockaddrs*, irc::sockets::sockaddrs*) { return MOD_RES_PASSTHRU; }
-void Module::OnSendWhoLine(User*, const std::vector<std::string>&, User*, std::string&) { }
-void Module::OnSetUserIP(LocalUser*) { }
+#endif
+
+ServiceProvider::ServiceProvider(Module* Creator, const std::string& Name, ServiceType Type)
+ : creator(Creator), name(Name), service(Type)
+{
+ if ((ServerInstance) && (ServerInstance->Modules->NewServices))
+ ServerInstance->Modules->NewServices->push_back(this);
+}
+
+void ServiceProvider::DisableAutoRegister()
+{
+ if ((ServerInstance) && (ServerInstance->Modules->NewServices))
+ {
+ ModuleManager::ServiceList& list = *ServerInstance->Modules->NewServices;
+ ModuleManager::ServiceList::iterator it = std::find(list.begin(), list.end(), this);
+ if (it != list.end())
+ list.erase(it);
+ }
+}
-ModuleManager::ModuleManager() : ModCount(0)
+ModuleManager::ModuleManager()
{
}
@@ -212,6 +207,12 @@ void ModuleManager::Attach(Implementation* i, Module* mod, size_t sz)
Attach(i[n], mod);
}
+void ModuleManager::AttachAll(Module* mod)
+{
+ for (size_t i = I_BEGIN + 1; i != I_END; ++i)
+ Attach((Implementation)i, mod);
+}
+
void ModuleManager::DetachAll(Module* mod)
{
for (size_t n = I_BEGIN + 1; n != I_END; ++n)
@@ -254,22 +255,25 @@ bool ModuleManager::SetPriority(Module* mod, Implementation i, Priority s, Modul
return false;
found_src:
+ // The modules registered for a hook are called in reverse order (to allow for easier removal
+ // of list entries while looping), meaning that the Priority given to us has the exact opposite effect
+ // on the list, e.g.: PRIORITY_BEFORE will actually put 'mod' after 'which', etc.
size_t swap_pos = my_pos;
switch (s)
{
- case PRIORITY_FIRST:
+ case PRIORITY_LAST:
if (prioritizationState != PRIO_STATE_FIRST)
return true;
else
swap_pos = 0;
break;
- case PRIORITY_LAST:
+ case PRIORITY_FIRST:
if (prioritizationState != PRIO_STATE_FIRST)
return true;
else
swap_pos = EventHandlers[i].size() - 1;
break;
- case PRIORITY_AFTER:
+ case PRIORITY_BEFORE:
{
/* Find the latest possible position, only searching AFTER our position */
for (size_t x = EventHandlers[i].size() - 1; x > my_pos; --x)
@@ -284,7 +288,7 @@ found_src:
return true;
}
/* Place this module before a set of other modules */
- case PRIORITY_BEFORE:
+ case PRIORITY_AFTER:
{
for (size_t x = 0; x < my_pos; ++x)
{
@@ -324,6 +328,29 @@ swap_now:
return true;
}
+bool ModuleManager::PrioritizeHooks()
+{
+ /* We give every module a chance to re-prioritize when we introduce a new one,
+ * not just the one thats loading, as the new module could affect the preference
+ * of others
+ */
+ for (int tries = 0; tries < 20; tries++)
+ {
+ prioritizationState = tries > 0 ? PRIO_STATE_LAST : PRIO_STATE_FIRST;
+ for (std::map<std::string, Module*>::iterator n = Modules.begin(); n != Modules.end(); ++n)
+ n->second->Prioritize();
+
+ if (prioritizationState == PRIO_STATE_LAST)
+ break;
+ if (tries == 19)
+ {
+ ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "Hook priority dependency loop detected");
+ return false;
+ }
+ }
+ return true;
+}
+
bool ModuleManager::CanUnload(Module* mod)
{
std::map<std::string, Module*>::iterator modfind = Modules.find(mod->ModuleSourceFile);
@@ -331,13 +358,13 @@ bool ModuleManager::CanUnload(Module* mod)
if ((modfind == Modules.end()) || (modfind->second != mod) || (mod->dying))
{
LastModuleError = "Module " + mod->ModuleSourceFile + " is not loaded, cannot unload it!";
- ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError);
+ ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError);
return false;
}
if (mod->GetVersion().Flags & VF_STATIC)
{
LastModuleError = "Module " + mod->ModuleSourceFile + " not unloadable (marked static)";
- ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError);
+ ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError);
return false;
}
@@ -347,22 +374,30 @@ bool ModuleManager::CanUnload(Module* mod)
void ModuleManager::DoSafeUnload(Module* mod)
{
+ // First, notify all modules that a module is about to be unloaded, so in case
+ // they pass execution to the soon to be unloaded module, it will happen now,
+ // i.e. before we unregister the services of the module being unloaded
+ FOREACH_MOD(OnUnloadModule, (mod));
+
std::map<std::string, Module*>::iterator modfind = Modules.find(mod->ModuleSourceFile);
std::vector<reference<ExtensionItem> > items;
ServerInstance->Extensions.BeginUnregister(modfind->second, items);
/* Give the module a chance to tidy out all its metadata */
- for (chan_hash::iterator c = ServerInstance->chanlist->begin(); c != ServerInstance->chanlist->end(); )
+ const chan_hash& chans = ServerInstance->GetChans();
+ for (chan_hash::const_iterator c = chans.begin(); c != chans.end(); )
{
Channel* chan = c->second;
++c;
mod->OnCleanup(TYPE_CHANNEL, chan);
chan->doUnhookExtensions(items);
- const UserMembList* users = chan->GetUsers();
- for(UserMembCIter mi = users->begin(); mi != users->end(); mi++)
+ const Channel::MemberMap& users = chan->GetUsers();
+ for (Channel::MemberMap::const_iterator mi = users.begin(); mi != users.end(); ++mi)
mi->second->doUnhookExtensions(items);
}
- for (user_hash::iterator u = ServerInstance->Users->clientlist->begin(); u != ServerInstance->Users->clientlist->end(); )
+
+ const user_hash& users = ServerInstance->Users->GetUsers();
+ for (user_hash::const_iterator u = users.begin(); u != users.end(); )
{
User* user = u->second;
// The module may quit the user (e.g. SSL mod unloading) and that will remove it from the container
@@ -370,16 +405,25 @@ void ModuleManager::DoSafeUnload(Module* mod)
mod->OnCleanup(TYPE_USER, user);
user->doUnhookExtensions(items);
}
- for(char m='A'; m <= 'z'; m++)
+
+ const ModeParser::ModeHandlerMap& usermodes = ServerInstance->Modes->GetModes(MODETYPE_USER);
+ for (ModeParser::ModeHandlerMap::const_iterator i = usermodes.begin(); i != usermodes.end(); )
+ {
+ ModeHandler* mh = i->second;
+ ++i;
+ if (mh->creator == mod)
+ this->DelService(*mh);
+ }
+
+ const ModeParser::ModeHandlerMap& chanmodes = ServerInstance->Modes->GetModes(MODETYPE_CHANNEL);
+ for (ModeParser::ModeHandlerMap::const_iterator i = chanmodes.begin(); i != chanmodes.end(); )
{
- ModeHandler* mh;
- mh = ServerInstance->Modes->FindMode(m, MODETYPE_USER);
- if (mh && mh->creator == mod)
- ServerInstance->Modes->DelMode(mh);
- mh = ServerInstance->Modes->FindMode(m, MODETYPE_CHANNEL);
- if (mh && mh->creator == mod)
- ServerInstance->Modes->DelMode(mh);
+ ModeHandler* mh = i->second;
+ ++i;
+ if (mh->creator == mod)
+ this->DelService(*mh);
}
+
for(std::multimap<std::string, ServiceProvider*>::iterator i = DataProviders.begin(); i != DataProviders.end(); )
{
std::multimap<std::string, ServiceProvider*>::iterator curr = i++;
@@ -389,19 +433,13 @@ void ModuleManager::DoSafeUnload(Module* mod)
dynamic_reference_base::reset_all();
- /* Tidy up any dangling resolvers */
- ServerInstance->Res->CleanResolvers(mod);
-
- FOREACH_MOD(I_OnUnloadModule,OnUnloadModule(mod));
-
DetachAll(mod);
Modules.erase(modfind);
ServerInstance->GlobalCulls.AddItem(mod);
- ServerInstance->Logs->Log("MODULE", DEFAULT,"Module %s unloaded",mod->ModuleSourceFile.c_str());
- this->ModCount--;
- ServerInstance->BuildISupport();
+ ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "Module %s unloaded",mod->ModuleSourceFile.c_str());
+ ServerInstance->ISupport.Build();
}
void ModuleManager::UnloadAll()
@@ -427,19 +465,121 @@ void ModuleManager::UnloadAll()
}
}
-std::string& ModuleManager::LastError()
+namespace
{
- return LastModuleError;
+ struct UnloadAction : public HandlerBase0<void>
+ {
+ Module* const mod;
+ UnloadAction(Module* m) : mod(m) {}
+ void Call()
+ {
+ DLLManager* dll = mod->ModuleDLLManager;
+ ServerInstance->Modules->DoSafeUnload(mod);
+ ServerInstance->GlobalCulls.Apply();
+ // In pure static mode this is always NULL
+ delete dll;
+ ServerInstance->GlobalCulls.AddItem(this);
+ }
+ };
+
+ struct ReloadAction : public HandlerBase0<void>
+ {
+ Module* const mod;
+ HandlerBase1<void, bool>* const callback;
+ ReloadAction(Module* m, HandlerBase1<void, bool>* c)
+ : mod(m), callback(c) {}
+ void Call()
+ {
+ DLLManager* dll = mod->ModuleDLLManager;
+ std::string name = mod->ModuleSourceFile;
+ ServerInstance->Modules->DoSafeUnload(mod);
+ ServerInstance->GlobalCulls.Apply();
+ delete dll;
+ bool rv = ServerInstance->Modules->Load(name);
+ if (callback)
+ callback->Call(rv);
+ ServerInstance->GlobalCulls.AddItem(this);
+ }
+ };
}
-CmdResult InspIRCd::CallCommandHandler(const std::string &commandname, const std::vector<std::string>& parameters, User* user)
+bool ModuleManager::Unload(Module* mod)
{
- return this->Parser->CallHandler(commandname, parameters, user);
+ if (!CanUnload(mod))
+ return false;
+ ServerInstance->AtomicActions.AddAction(new UnloadAction(mod));
+ return true;
}
-bool InspIRCd::IsValidModuleCommand(const std::string &commandname, int pcnt, User* user)
+void ModuleManager::Reload(Module* mod, HandlerBase1<void, bool>* callback)
{
- return this->Parser->IsValidCommand(commandname, pcnt, user);
+ if (CanUnload(mod))
+ ServerInstance->AtomicActions.AddAction(new ReloadAction(mod, callback));
+ else if (callback)
+ callback->Call(false);
+}
+
+void ModuleManager::LoadAll()
+{
+ std::map<std::string, ServiceList> servicemap;
+ LoadCoreModules(servicemap);
+
+ ConfigTagList tags = ServerInstance->Config->ConfTags("module");
+ for (ConfigIter i = tags.first; i != tags.second; ++i)
+ {
+ ConfigTag* tag = i->second;
+ std::string name = tag->getString("name");
+ this->NewServices = &servicemap[name];
+ std::cout << "[" << con_green << "*" << con_reset << "] Loading module:\t" << con_green << name << con_reset << std::endl;
+
+ if (!this->Load(name, true))
+ {
+ ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, this->LastError());
+ std::cout << std::endl << "[" << con_red << "*" << con_reset << "] " << this->LastError() << std::endl << std::endl;
+ ServerInstance->Exit(EXIT_STATUS_MODULE);
+ }
+ }
+
+ ConfigStatus confstatus;
+
+ for (ModuleMap::const_iterator i = Modules.begin(); i != Modules.end(); ++i)
+ {
+ Module* mod = i->second;
+ try
+ {
+ ServerInstance->Logs->Log("MODULE", LOG_DEBUG, "Initializing %s", i->first.c_str());
+ AttachAll(mod);
+ AddServices(servicemap[i->first]);
+ mod->init();
+ mod->ReadConfig(confstatus);
+ }
+ catch (CoreException& modexcept)
+ {
+ LastModuleError = "Unable to initialize " + mod->ModuleSourceFile + ": " + modexcept.GetReason();
+ ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError);
+ std::cout << std::endl << "[" << con_red << "*" << con_reset << "] " << LastModuleError << std::endl << std::endl;
+ ServerInstance->Exit(EXIT_STATUS_MODULE);
+ }
+ }
+
+ this->NewServices = NULL;
+
+ if (!PrioritizeHooks())
+ ServerInstance->Exit(EXIT_STATUS_MODULE);
+}
+
+std::string& ModuleManager::LastError()
+{
+ return LastModuleError;
+}
+
+void ModuleManager::AddServices(const ServiceList& list)
+{
+ for (ServiceList::const_iterator i = list.begin(); i != list.end(); ++i)
+ {
+ ServiceProvider& s = **i;
+ AddService(s);
+ }
}
void ModuleManager::AddService(ServiceProvider& item)
@@ -447,13 +587,17 @@ void ModuleManager::AddService(ServiceProvider& item)
switch (item.service)
{
case SERVICE_COMMAND:
- if (!ServerInstance->Parser->AddCommand(static_cast<Command*>(&item)))
+ if (!ServerInstance->Parser.AddCommand(static_cast<Command*>(&item)))
throw ModuleException("Command "+std::string(item.name)+" already exists.");
return;
case SERVICE_MODE:
- if (!ServerInstance->Modes->AddMode(static_cast<ModeHandler*>(&item)))
- throw ModuleException("Mode "+std::string(item.name)+" already exists.");
+ {
+ ModeHandler* mh = static_cast<ModeHandler*>(&item);
+ ServerInstance->Modes->AddMode(mh);
+ DataProviders.insert(std::make_pair((mh->GetModeType() == MODETYPE_CHANNEL ? "mode/" : "umode/") + item.name, &item));
+ dynamic_reference_base::reset_all();
return;
+ }
case SERVICE_METADATA:
if (!ServerInstance->Extensions.Register(static_cast<ExtensionItem*>(&item)))
throw ModuleException("Extension " + std::string(item.name) + " already exists.");
@@ -461,6 +605,9 @@ void ModuleManager::AddService(ServiceProvider& item)
case SERVICE_DATA:
case SERVICE_IOHOOK:
{
+ if ((!item.name.compare(0, 5, "mode/", 5)) || (!item.name.compare(0, 6, "umode/", 6)))
+ throw ModuleException("The \"mode/\" and the \"umode\" service name prefixes are reserved.");
+
DataProviders.insert(std::make_pair(item.name, &item));
std::string::size_type slash = item.name.find('/');
if (slash != std::string::npos)
@@ -468,6 +615,7 @@ void ModuleManager::AddService(ServiceProvider& item)
DataProviders.insert(std::make_pair(item.name.substr(0, slash), &item));
DataProviders.insert(std::make_pair(item.name.substr(slash + 1), &item));
}
+ dynamic_reference_base::reset_all();
return;
}
default:
@@ -482,7 +630,7 @@ void ModuleManager::DelService(ServiceProvider& item)
case SERVICE_MODE:
if (!ServerInstance->Modes->DelMode(static_cast<ModeHandler*>(&item)))
throw ModuleException("Mode "+std::string(item.name)+" does not exist.");
- return;
+ // Fall through
case SERVICE_DATA:
case SERVICE_IOHOOK:
{
@@ -522,76 +670,37 @@ dynamic_reference_base::dynamic_reference_base(Module* Creator, const std::strin
: name(Name), value(NULL), creator(Creator)
{
if (!dynrefs)
- dynrefs = new std::vector<dynamic_reference_base*>;
- dynrefs->push_back(this);
+ dynrefs = new intrusive_list<dynamic_reference_base>;
+ dynrefs->push_front(this);
+
+ // Resolve unless there is no ModuleManager (part of class InspIRCd)
+ if (ServerInstance)
+ resolve();
}
dynamic_reference_base::~dynamic_reference_base()
{
- for(unsigned int i = 0; i < dynrefs->size(); i++)
+ dynrefs->erase(this);
+ if (dynrefs->empty())
{
- if (dynrefs->at(i) == this)
- {
- unsigned int last = dynrefs->size() - 1;
- if (i != last)
- dynrefs->at(i) = dynrefs->at(last);
- dynrefs->erase(dynrefs->begin() + last);
- if (dynrefs->empty())
- {
- delete dynrefs;
- dynrefs = NULL;
- }
- return;
- }
+ delete dynrefs;
+ dynrefs = NULL;
}
}
void dynamic_reference_base::SetProvider(const std::string& newname)
{
name = newname;
- ClearCache();
-}
-
-void dynamic_reference_base::lookup()
-{
- if (!*this)
- throw ModuleException("Dynamic reference to '" + name + "' failed to resolve");
+ resolve();
}
-dynamic_reference_base::operator bool()
+void dynamic_reference_base::resolve()
{
- if (!value)
- {
- std::multimap<std::string, ServiceProvider*>::iterator i = ServerInstance->Modules->DataProviders.find(name);
- if (i != ServerInstance->Modules->DataProviders.end())
- value = static_cast<DataProvider*>(i->second);
- }
- return (value != NULL);
-}
-
-void InspIRCd::SendMode(const std::vector<std::string>& parameters, User *user)
-{
- this->Modes->Process(parameters, user);
-}
-
-
-void InspIRCd::SendGlobalMode(const std::vector<std::string>& parameters, User *user)
-{
- Modes->Process(parameters, user);
- if (!Modes->GetLastParse().empty())
- this->PI->SendMode(parameters[0], Modes->GetLastParseParams(), Modes->GetLastParseTranslate());
-}
-
-bool InspIRCd::AddResolver(Resolver* r, bool cached)
-{
- if (!cached)
- return this->Res->AddResolverClass(r);
+ std::multimap<std::string, ServiceProvider*>::iterator i = ServerInstance->Modules->DataProviders.find(name);
+ if (i != ServerInstance->Modules->DataProviders.end())
+ value = static_cast<DataProvider*>(i->second);
else
- {
- r->TriggerCachedResult();
- delete r;
- return true;
- }
+ value = NULL;
}
Module* ModuleManager::Find(const std::string &name)
@@ -603,179 +712,3 @@ Module* ModuleManager::Find(const std::string &name)
else
return modfind->second;
}
-
-const std::vector<std::string> ModuleManager::GetAllModuleNames(int filter)
-{
- std::vector<std::string> retval;
- for (std::map<std::string, Module*>::iterator x = Modules.begin(); x != Modules.end(); ++x)
- if (!filter || (x->second->GetVersion().Flags & filter))
- retval.push_back(x->first);
- return retval;
-}
-
-ConfigReader::ConfigReader()
-{
- this->error = 0;
- ServerInstance->Logs->Log("MODULE", DEBUG, "ConfigReader is deprecated in 2.0; "
- "use ServerInstance->Config->ConfValue(\"key\") or ->ConfTags(\"key\") instead");
-}
-
-
-ConfigReader::~ConfigReader()
-{
-}
-
-static ConfigTag* SlowGetTag(const std::string &tag, int index)
-{
- ConfigTagList tags = ServerInstance->Config->ConfTags(tag);
- while (tags.first != tags.second)
- {
- if (!index)
- return tags.first->second;
- tags.first++;
- index--;
- }
- return NULL;
-}
-
-std::string ConfigReader::ReadValue(const std::string &tag, const std::string &name, const std::string &default_value, int index, bool allow_linefeeds)
-{
- std::string result = default_value;
- if (!SlowGetTag(tag, index)->readString(name, result, allow_linefeeds))
- {
- this->error = CONF_VALUE_NOT_FOUND;
- }
- return result;
-}
-
-std::string ConfigReader::ReadValue(const std::string &tag, const std::string &name, int index, bool allow_linefeeds)
-{
- return ReadValue(tag, name, "", index, allow_linefeeds);
-}
-
-bool ConfigReader::ReadFlag(const std::string &tag, const std::string &name, const std::string &default_value, int index)
-{
- bool def = (default_value == "yes");
- return SlowGetTag(tag, index)->getBool(name, def);
-}
-
-bool ConfigReader::ReadFlag(const std::string &tag, const std::string &name, int index)
-{
- return ReadFlag(tag, name, "", index);
-}
-
-
-int ConfigReader::ReadInteger(const std::string &tag, const std::string &name, const std::string &default_value, int index, bool need_positive)
-{
- int v = atoi(default_value.c_str());
- int result = SlowGetTag(tag, index)->getInt(name, v);
-
- if ((need_positive) && (result < 0))
- {
- this->error = CONF_INT_NEGATIVE;
- return 0;
- }
-
- return result;
-}
-
-int ConfigReader::ReadInteger(const std::string &tag, const std::string &name, int index, bool need_positive)
-{
- return ReadInteger(tag, name, "", index, need_positive);
-}
-
-long ConfigReader::GetError()
-{
- long olderr = this->error;
- this->error = 0;
- return olderr;
-}
-
-int ConfigReader::Enumerate(const std::string &tag)
-{
- ServerInstance->Logs->Log("MODULE", DEBUG, "Module is using ConfigReader::Enumerate on %s; this is slow!",
- tag.c_str());
- int i=0;
- while (SlowGetTag(tag, i)) i++;
- return i;
-}
-
-FileReader::FileReader(const std::string &filename)
-{
- LoadFile(filename);
-}
-
-FileReader::FileReader()
-{
-}
-
-std::string FileReader::Contents()
-{
- std::string x;
- for (file_cache::iterator a = this->fc.begin(); a != this->fc.end(); a++)
- {
- x.append(*a);
- x.append("\r\n");
- }
- return x;
-}
-
-unsigned long FileReader::ContentSize()
-{
- return this->contentsize;
-}
-
-void FileReader::CalcSize()
-{
- unsigned long n = 0;
- for (file_cache::iterator a = this->fc.begin(); a != this->fc.end(); a++)
- n += (a->length() + 2);
- this->contentsize = n;
-}
-
-void FileReader::LoadFile(const std::string &filename)
-{
- std::map<std::string, file_cache>::iterator file = ServerInstance->Config->Files.find(filename);
- if (file != ServerInstance->Config->Files.end())
- {
- this->fc = file->second;
- }
- else
- {
- fc.clear();
- FILE* f = fopen(filename.c_str(), "r");
- if (!f)
- return;
- char linebuf[MAXBUF*10];
- while (fgets(linebuf, sizeof(linebuf), f))
- {
- int len = strlen(linebuf);
- if (len)
- fc.push_back(std::string(linebuf, len - 1));
- }
- fclose(f);
- }
- CalcSize();
-}
-
-
-FileReader::~FileReader()
-{
-}
-
-bool FileReader::Exists()
-{
- return (!(fc.size() == 0));
-}
-
-std::string FileReader::GetLine(int x)
-{
- if ((x<0) || ((unsigned)x>=fc.size()))
- return "";
- return fc[x];
-}
-
-int FileReader::FileSize()
-{
- return fc.size();
-}
diff --git a/src/modules/extra/m_geoip.cpp b/src/modules/extra/m_geoip.cpp
index a36c39bc8..3561d1a5d 100644
--- a/src/modules/extra/m_geoip.cpp
+++ b/src/modules/extra/m_geoip.cpp
@@ -27,7 +27,6 @@
# pragma comment(lib, "GeoIP.lib")
#endif
-/* $ModDesc: Provides a way to restrict users by country using GeoIP lookup */
/* $LinkerFlags: -lGeoIP */
class ModuleGeoIP : public Module
@@ -37,7 +36,7 @@ class ModuleGeoIP : public Module
std::string* SetExt(LocalUser* user)
{
- const char* c = GeoIP_country_code_by_addr(gi, user->GetIPString());
+ const char* c = GeoIP_country_code_by_addr(gi, user->GetIPString().c_str());
if (!c)
c = "UNK";
@@ -51,17 +50,14 @@ class ModuleGeoIP : public Module
{
}
- void init()
+ void init() CXX11_OVERRIDE
{
gi = GeoIP_new(GEOIP_STANDARD);
if (gi == NULL)
throw ModuleException("Unable to initialize geoip, are you missing GeoIP.dat?");
- ServerInstance->Modules->AddService(ext);
- Implementation eventlist[] = { I_OnSetConnectClass, I_OnStats };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
-
- for (LocalUserList::const_iterator i = ServerInstance->Users->local_users.begin(); i != ServerInstance->Users->local_users.end(); ++i)
+ const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers();
+ for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i)
{
LocalUser* user = *i;
if ((user->registered == REG_ALL) && (!ext.get(user)))
@@ -77,12 +73,12 @@ class ModuleGeoIP : public Module
GeoIP_delete(gi);
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides a way to assign users to connect classes by country using GeoIP lookup", VF_VENDOR);
}
- ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass)
+ ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass) CXX11_OVERRIDE
{
std::string* cc = ext.get(user);
if (!cc)
@@ -99,14 +95,16 @@ class ModuleGeoIP : public Module
return MOD_RES_DENY;
}
- ModResult OnStats(char symbol, User* user, string_list &out)
+ ModResult OnStats(char symbol, User* user, string_list &out) CXX11_OVERRIDE
{
if (symbol != 'G')
return MOD_RES_PASSTHRU;
unsigned int unknown = 0;
std::map<std::string, unsigned int> results;
- for (LocalUserList::const_iterator i = ServerInstance->Users->local_users.begin(); i != ServerInstance->Users->local_users.end(); ++i)
+
+ const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers();
+ for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i)
{
std::string* cc = ext.get(*i);
if (cc)
@@ -115,7 +113,7 @@ class ModuleGeoIP : public Module
unknown++;
}
- std::string p = ServerInstance->Config->ServerName + " 801 " + user->nick + " :GeoIPSTATS ";
+ std::string p = "801 " + user->nick + " :GeoIPSTATS ";
for (std::map<std::string, unsigned int>::const_iterator i = results.begin(); i != results.end(); ++i)
{
out.push_back(p + i->first + " " + ConvToStr(i->second));
@@ -129,4 +127,3 @@ class ModuleGeoIP : public Module
};
MODULE_INIT(ModuleGeoIP)
-
diff --git a/src/modules/extra/m_ldap.cpp b/src/modules/extra/m_ldap.cpp
new file mode 100644
index 000000000..9f8d68427
--- /dev/null
+++ b/src/modules/extra/m_ldap.cpp
@@ -0,0 +1,628 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2013-2014 Adam <Adam@anope.org>
+ * Copyright (C) 2003-2014 Anope Team <team@anope.org>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "inspircd.h"
+#include "modules/ldap.h"
+
+#include <ldap.h>
+
+#ifdef _WIN32
+# pragma comment(lib, "libldap.lib")
+# pragma comment(lib, "liblber.lib")
+#endif
+
+/* $LinkerFlags: -lldap */
+
+class LDAPService : public LDAPProvider, public SocketThread
+{
+ LDAP* con;
+ reference<ConfigTag> config;
+ time_t last_connect;
+ int searchscope;
+ time_t timeout;
+ time_t last_timeout_check;
+
+ LDAPMod** BuildMods(const LDAPMods& attributes)
+ {
+ LDAPMod** mods = new LDAPMod*[attributes.size() + 1];
+ memset(mods, 0, sizeof(LDAPMod*) * (attributes.size() + 1));
+ for (unsigned int x = 0; x < attributes.size(); ++x)
+ {
+ const LDAPModification& l = attributes[x];
+ LDAPMod* mod = new LDAPMod;
+ mods[x] = mod;
+
+ if (l.op == LDAPModification::LDAP_ADD)
+ mod->mod_op = LDAP_MOD_ADD;
+ else if (l.op == LDAPModification::LDAP_DEL)
+ mod->mod_op = LDAP_MOD_DELETE;
+ else if (l.op == LDAPModification::LDAP_REPLACE)
+ mod->mod_op = LDAP_MOD_REPLACE;
+ else if (l.op != 0)
+ {
+ FreeMods(mods);
+ throw LDAPException("Unknown LDAP operation");
+ }
+ mod->mod_type = strdup(l.name.c_str());
+ mod->mod_values = new char*[l.values.size() + 1];
+ memset(mod->mod_values, 0, sizeof(char*) * (l.values.size() + 1));
+ for (unsigned int j = 0, c = 0; j < l.values.size(); ++j)
+ if (!l.values[j].empty())
+ mod->mod_values[c++] = strdup(l.values[j].c_str());
+ }
+ return mods;
+ }
+
+ void FreeMods(LDAPMod** mods)
+ {
+ for (unsigned int i = 0; mods[i] != NULL; ++i)
+ {
+ LDAPMod* mod = mods[i];
+ if (mod->mod_type != NULL)
+ free(mod->mod_type);
+ if (mod->mod_values != NULL)
+ {
+ for (unsigned int j = 0; mod->mod_values[j] != NULL; ++j)
+ free(mod->mod_values[j]);
+ delete[] mod->mod_values;
+ }
+ }
+ delete[] mods;
+ }
+
+ void Reconnect()
+ {
+ // Only try one connect a minute. It is an expensive blocking operation
+ if (last_connect > ServerInstance->Time() - 60)
+ throw LDAPException("Unable to connect to LDAP service " + this->name + ": reconnecting too fast");
+ last_connect = ServerInstance->Time();
+
+ ldap_unbind_ext(this->con, NULL, NULL);
+ Connect();
+ }
+
+ void SaveInterface(LDAPInterface* i, LDAPQuery msgid)
+ {
+ if (i != NULL)
+ {
+ this->LockQueue();
+ this->queries[msgid] = std::make_pair(ServerInstance->Time(), i);
+ this->UnlockQueueWakeup();
+ }
+ }
+
+ void Timeout()
+ {
+ if (last_timeout_check == ServerInstance->Time())
+ return;
+ last_timeout_check = ServerInstance->Time();
+
+ for (query_queue::iterator it = this->queries.begin(); it != this->queries.end(); )
+ {
+ LDAPQuery msgid = it->first;
+ time_t created = it->second.first;
+ LDAPInterface* i = it->second.second;
+ ++it;
+
+ if (ServerInstance->Time() > created + timeout)
+ {
+ LDAPResult* ldap_result = new LDAPResult();
+ ldap_result->id = msgid;
+ ldap_result->error = "Query timed out";
+
+ this->queries.erase(msgid);
+ this->results.push_back(std::make_pair(i, ldap_result));
+
+ this->NotifyParent();
+ }
+ }
+ }
+
+ public:
+ typedef std::map<LDAPQuery, std::pair<time_t, LDAPInterface*> > query_queue;
+ typedef std::vector<std::pair<LDAPInterface*, LDAPResult*> > result_queue;
+ query_queue queries;
+ result_queue results;
+
+ LDAPService(Module* c, ConfigTag* tag)
+ : LDAPProvider(c, "LDAP/" + tag->getString("id"))
+ , con(NULL), config(tag), last_connect(0), last_timeout_check(0)
+ {
+ std::string scope = config->getString("searchscope");
+ if (scope == "base")
+ searchscope = LDAP_SCOPE_BASE;
+ else if (scope == "onelevel")
+ searchscope = LDAP_SCOPE_ONELEVEL;
+ else
+ searchscope = LDAP_SCOPE_SUBTREE;
+ timeout = config->getInt("timeout", 5);
+
+ Connect();
+ }
+
+ ~LDAPService()
+ {
+ this->LockQueue();
+
+ for (query_queue::iterator i = this->queries.begin(); i != this->queries.end(); ++i)
+ {
+ LDAPQuery msgid = i->first;
+ LDAPInterface* inter = i->second.second;
+
+ ldap_abandon_ext(this->con, msgid, NULL, NULL);
+
+ if (inter)
+ {
+ LDAPResult r;
+ r.error = "LDAP Interface is going away";
+ inter->OnError(r);
+ }
+ }
+ this->queries.clear();
+
+ for (result_queue::iterator i = this->results.begin(); i != this->results.end(); ++i)
+ {
+ LDAPInterface* inter = i->first;
+ LDAPResult* r = i->second;
+
+ r->error = "LDAP Interface is going away";
+ if (inter)
+ inter->OnError(*r);
+ }
+ this->results.clear();
+
+ this->UnlockQueue();
+
+ ldap_unbind_ext(this->con, NULL, NULL);
+ }
+
+ void Connect()
+ {
+ std::string server = config->getString("server");
+ int i = ldap_initialize(&this->con, server.c_str());
+ if (i != LDAP_SUCCESS)
+ throw LDAPException("Unable to connect to LDAP service " + this->name + ": " + ldap_err2string(i));
+
+ const int version = LDAP_VERSION3;
+ i = ldap_set_option(this->con, LDAP_OPT_PROTOCOL_VERSION, &version);
+ if (i != LDAP_OPT_SUCCESS)
+ {
+ ldap_unbind_ext(this->con, NULL, NULL);
+ this->con = NULL;
+ throw LDAPException("Unable to set protocol version for " + this->name + ": " + ldap_err2string(i));
+ }
+
+ const struct timeval tv = { 0, 0 };
+ i = ldap_set_option(this->con, LDAP_OPT_NETWORK_TIMEOUT, &tv);
+ if (i != LDAP_OPT_SUCCESS)
+ {
+ ldap_unbind_ext(this->con, NULL, NULL);
+ this->con = NULL;
+ throw LDAPException("Unable to set timeout for " + this->name + ": " + ldap_err2string(i));
+ }
+ }
+
+ LDAPQuery BindAsManager(LDAPInterface* i) CXX11_OVERRIDE
+ {
+ std::string binddn = config->getString("binddn");
+ std::string bindauth = config->getString("bindauth");
+ return this->Bind(i, binddn, bindauth);
+ }
+
+ LDAPQuery Bind(LDAPInterface* i, const std::string& who, const std::string& pass) CXX11_OVERRIDE
+ {
+ berval cred;
+ cred.bv_val = strdup(pass.c_str());
+ cred.bv_len = pass.length();
+
+ LDAPQuery msgid;
+ int ret = ldap_sasl_bind(con, who.c_str(), LDAP_SASL_SIMPLE, &cred, NULL, NULL, &msgid);
+ free(cred.bv_val);
+ if (ret != LDAP_SUCCESS)
+ {
+ if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT)
+ {
+ this->Reconnect();
+ return this->Bind(i, who, pass);
+ }
+ else
+ throw LDAPException(ldap_err2string(ret));
+ }
+
+ SaveInterface(i, msgid);
+ return msgid;
+ }
+
+ LDAPQuery Search(LDAPInterface* i, const std::string& base, const std::string& filter) CXX11_OVERRIDE
+ {
+ if (i == NULL)
+ throw LDAPException("No interface");
+
+ LDAPQuery msgid;
+ int ret = ldap_search_ext(this->con, base.c_str(), searchscope, filter.c_str(), NULL, 0, NULL, NULL, NULL, 0, &msgid);
+ if (ret != LDAP_SUCCESS)
+ {
+ if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT)
+ {
+ this->Reconnect();
+ return this->Search(i, base, filter);
+ }
+ else
+ throw LDAPException(ldap_err2string(ret));
+ }
+
+ SaveInterface(i, msgid);
+ return msgid;
+ }
+
+ LDAPQuery Add(LDAPInterface* i, const std::string& dn, LDAPMods& attributes) CXX11_OVERRIDE
+ {
+ LDAPMod** mods = this->BuildMods(attributes);
+ LDAPQuery msgid;
+ int ret = ldap_add_ext(this->con, dn.c_str(), mods, NULL, NULL, &msgid);
+ this->FreeMods(mods);
+
+ if (ret != LDAP_SUCCESS)
+ {
+ if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT)
+ {
+ this->Reconnect();
+ return this->Add(i, dn, attributes);
+ }
+ else
+ throw LDAPException(ldap_err2string(ret));
+ }
+
+ SaveInterface(i, msgid);
+ return msgid;
+ }
+
+ LDAPQuery Del(LDAPInterface* i, const std::string& dn) CXX11_OVERRIDE
+ {
+ LDAPQuery msgid;
+ int ret = ldap_delete_ext(this->con, dn.c_str(), NULL, NULL, &msgid);
+
+ if (ret != LDAP_SUCCESS)
+ {
+ if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT)
+ {
+ this->Reconnect();
+ return this->Del(i, dn);
+ }
+ else
+ throw LDAPException(ldap_err2string(ret));
+ }
+
+ SaveInterface(i, msgid);
+ return msgid;
+ }
+
+ LDAPQuery Modify(LDAPInterface* i, const std::string& base, LDAPMods& attributes) CXX11_OVERRIDE
+ {
+ LDAPMod** mods = this->BuildMods(attributes);
+ LDAPQuery msgid;
+ int ret = ldap_modify_ext(this->con, base.c_str(), mods, NULL, NULL, &msgid);
+ this->FreeMods(mods);
+
+ if (ret != LDAP_SUCCESS)
+ {
+ if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT)
+ {
+ this->Reconnect();
+ return this->Modify(i, base, attributes);
+ }
+ else
+ throw LDAPException(ldap_err2string(ret));
+ }
+
+ SaveInterface(i, msgid);
+ return msgid;
+ }
+
+ LDAPQuery Compare(LDAPInterface* i, const std::string& dn, const std::string& attr, const std::string& val) CXX11_OVERRIDE
+ {
+ berval cred;
+ cred.bv_val = strdup(val.c_str());
+ cred.bv_len = val.length();
+
+ LDAPQuery msgid;
+ int ret = ldap_compare_ext(con, dn.c_str(), attr.c_str(), &cred, NULL, NULL, &msgid);
+ free(cred.bv_val);
+
+ if (ret != LDAP_SUCCESS)
+ {
+ if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT)
+ {
+ this->Reconnect();
+ return this->Compare(i, dn, attr, val);
+ }
+ else
+ throw LDAPException(ldap_err2string(ret));
+ }
+
+ SaveInterface(i, msgid);
+ return msgid;
+ }
+
+ void Run() CXX11_OVERRIDE
+ {
+ while (!this->GetExitFlag())
+ {
+ this->LockQueue();
+ if (this->queries.empty())
+ {
+ this->WaitForQueue();
+ this->UnlockQueue();
+ continue;
+ }
+ this->Timeout();
+ this->UnlockQueue();
+
+ struct timeval tv = { 1, 0 };
+ LDAPMessage* result;
+ int rtype = ldap_result(this->con, LDAP_RES_ANY, 1, &tv, &result);
+ if (rtype <= 0 || this->GetExitFlag())
+ continue;
+
+ int cur_id = ldap_msgid(result);
+
+ this->LockQueue();
+
+ query_queue::iterator it = this->queries.find(cur_id);
+ if (it == this->queries.end())
+ {
+ this->UnlockQueue();
+ ldap_msgfree(result);
+ continue;
+ }
+ LDAPInterface* i = it->second.second;
+ this->queries.erase(it);
+
+ this->UnlockQueue();
+
+ LDAPResult* ldap_result = new LDAPResult();
+ ldap_result->id = cur_id;
+
+ for (LDAPMessage* cur = ldap_first_message(this->con, result); cur; cur = ldap_next_message(this->con, cur))
+ {
+ int cur_type = ldap_msgtype(cur);
+
+ LDAPAttributes attributes;
+
+ {
+ char* dn = ldap_get_dn(this->con, cur);
+ if (dn != NULL)
+ {
+ attributes["dn"].push_back(dn);
+ ldap_memfree(dn);
+ }
+ }
+
+ switch (cur_type)
+ {
+ case LDAP_RES_BIND:
+ ldap_result->type = LDAPResult::QUERY_BIND;
+ break;
+ case LDAP_RES_SEARCH_ENTRY:
+ ldap_result->type = LDAPResult::QUERY_SEARCH;
+ break;
+ case LDAP_RES_ADD:
+ ldap_result->type = LDAPResult::QUERY_ADD;
+ break;
+ case LDAP_RES_DELETE:
+ ldap_result->type = LDAPResult::QUERY_DELETE;
+ break;
+ case LDAP_RES_MODIFY:
+ ldap_result->type = LDAPResult::QUERY_MODIFY;
+ break;
+ case LDAP_RES_SEARCH_RESULT:
+ // If we get here and ldap_result->type is LDAPResult::QUERY_UNKNOWN
+ // then the result set is empty
+ ldap_result->type = LDAPResult::QUERY_SEARCH;
+ break;
+ case LDAP_RES_COMPARE:
+ ldap_result->type = LDAPResult::QUERY_COMPARE;
+ break;
+ default:
+ continue;
+ }
+
+ switch (cur_type)
+ {
+ case LDAP_RES_SEARCH_ENTRY:
+ {
+ BerElement* ber = NULL;
+ for (char* attr = ldap_first_attribute(this->con, cur, &ber); attr; attr = ldap_next_attribute(this->con, cur, ber))
+ {
+ berval** vals = ldap_get_values_len(this->con, cur, attr);
+ int count = ldap_count_values_len(vals);
+
+ std::vector<std::string> attrs;
+ for (int j = 0; j < count; ++j)
+ attrs.push_back(vals[j]->bv_val);
+ attributes[attr] = attrs;
+
+ ldap_value_free_len(vals);
+ ldap_memfree(attr);
+ }
+ if (ber != NULL)
+ ber_free(ber, 0);
+
+ break;
+ }
+ case LDAP_RES_BIND:
+ case LDAP_RES_ADD:
+ case LDAP_RES_DELETE:
+ case LDAP_RES_MODIFY:
+ case LDAP_RES_COMPARE:
+ {
+ int errcode = -1;
+ int parse_result = ldap_parse_result(this->con, cur, &errcode, NULL, NULL, NULL, NULL, 0);
+ if (parse_result != LDAP_SUCCESS)
+ {
+ ldap_result->error = ldap_err2string(parse_result);
+ }
+ else
+ {
+ if (cur_type == LDAP_RES_COMPARE)
+ {
+ if (errcode != LDAP_COMPARE_TRUE)
+ ldap_result->error = ldap_err2string(errcode);
+ }
+ else if (errcode != LDAP_SUCCESS)
+ ldap_result->error = ldap_err2string(errcode);
+ }
+ break;
+ }
+ default:
+ continue;
+ }
+
+ ldap_result->messages.push_back(attributes);
+ }
+
+ ldap_msgfree(result);
+
+ this->LockQueue();
+ this->results.push_back(std::make_pair(i, ldap_result));
+ this->UnlockQueueWakeup();
+
+ this->NotifyParent();
+ }
+ }
+
+ void OnNotify() CXX11_OVERRIDE
+ {
+ LDAPService::result_queue r;
+
+ this->LockQueue();
+ this->results.swap(r);
+ this->UnlockQueue();
+
+ for (LDAPService::result_queue::iterator i = r.begin(); i != r.end(); ++i)
+ {
+ LDAPInterface* li = i->first;
+ LDAPResult* res = i->second;
+
+ if (!res->error.empty())
+ li->OnError(*res);
+ else
+ li->OnResult(*res);
+
+ delete res;
+ }
+ }
+};
+
+class ModuleLDAP : public Module
+{
+ typedef std::map<std::string, LDAPService*> ServiceMap;
+ ServiceMap LDAPServices;
+
+ public:
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
+ {
+ ServiceMap conns;
+
+ ConfigTagList tags = ServerInstance->Config->ConfTags("database");
+ for (ConfigIter i = tags.first; i != tags.second; i++)
+ {
+ const reference<ConfigTag>& tag = i->second;
+
+ if (tag->getString("module") != "ldap")
+ continue;
+
+ std::string id = tag->getString("id");
+
+ ServiceMap::iterator curr = LDAPServices.find(id);
+ if (curr == LDAPServices.end())
+ {
+ LDAPService* conn = new LDAPService(this, tag);
+ conns[id] = conn;
+
+ ServerInstance->Modules->AddService(*conn);
+ ServerInstance->Threads.Start(conn);
+ }
+ else
+ {
+ conns.insert(*curr);
+ LDAPServices.erase(curr);
+ }
+ }
+
+ for (ServiceMap::iterator i = LDAPServices.begin(); i != LDAPServices.end(); ++i)
+ {
+ LDAPService* conn = i->second;
+ ServerInstance->Modules->DelService(*conn);
+ conn->join();
+ conn->OnNotify();
+ delete conn;
+ }
+
+ LDAPServices.swap(conns);
+ }
+
+ void OnUnloadModule(Module* m) CXX11_OVERRIDE
+ {
+ for (ServiceMap::iterator it = this->LDAPServices.begin(); it != this->LDAPServices.end(); ++it)
+ {
+ LDAPService* s = it->second;
+ s->LockQueue();
+ for (LDAPService::query_queue::iterator it2 = s->queries.begin(); it2 != s->queries.end();)
+ {
+ int msgid = it2->first;
+ LDAPInterface* i = it2->second.second;
+ ++it2;
+
+ if (i->creator == m)
+ s->queries.erase(msgid);
+ }
+ for (unsigned int i = s->results.size(); i > 0; --i)
+ {
+ LDAPInterface* li = s->results[i - 1].first;
+ LDAPResult* r = s->results[i - 1].second;
+
+ if (li->creator == m)
+ {
+ s->results.erase(s->results.begin() + i - 1);
+ delete r;
+ }
+ }
+ s->UnlockQueue();
+ }
+ }
+
+ ~ModuleLDAP()
+ {
+ for (std::map<std::string, LDAPService*>::iterator i = LDAPServices.begin(); i != LDAPServices.end(); ++i)
+ {
+ LDAPService* conn = i->second;
+ conn->join();
+ conn->OnNotify();
+ delete conn;
+ }
+ }
+
+ Version GetVersion() CXX11_OVERRIDE
+ {
+ return Version("LDAP support", VF_VENDOR);
+ }
+};
+
+MODULE_INIT(ModuleLDAP)
diff --git a/src/modules/extra/m_ldapauth.cpp b/src/modules/extra/m_ldapauth.cpp
deleted file mode 100644
index 6c765fb2e..000000000
--- a/src/modules/extra/m_ldapauth.cpp
+++ /dev/null
@@ -1,436 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2011 Pierre Carrier <pierre@spotify.com>
- * Copyright (C) 2009-2010 Robin Burchell <robin+git@viroteck.net>
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com>
- * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc>
- * Copyright (C) 2008 Dennis Friis <peavey@inspircd.org>
- * Copyright (C) 2007 Carsten Valdemar Munk <carsten.munk+inspircd@gmail.com>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-#include "users.h"
-#include "channels.h"
-#include "modules.h"
-
-#include <ldap.h>
-
-#ifdef _WIN32
-# pragma comment(lib, "libldap.lib")
-# pragma comment(lib, "liblber.lib")
-#endif
-
-/* $ModDesc: Allow/Deny connections based upon answer from LDAP server */
-/* $LinkerFlags: -lldap */
-
-struct RAIILDAPString
-{
- char *str;
-
- RAIILDAPString(char *Str)
- : str(Str)
- {
- }
-
- ~RAIILDAPString()
- {
- ldap_memfree(str);
- }
-
- operator char*()
- {
- return str;
- }
-
- operator std::string()
- {
- return str;
- }
-};
-
-struct RAIILDAPMessage
-{
- RAIILDAPMessage()
- {
- }
-
- ~RAIILDAPMessage()
- {
- dealloc();
- }
-
- void dealloc()
- {
- ldap_msgfree(msg);
- }
-
- operator LDAPMessage*()
- {
- return msg;
- }
-
- LDAPMessage **operator &()
- {
- return &msg;
- }
-
- LDAPMessage *msg;
-};
-
-class ModuleLDAPAuth : public Module
-{
- LocalIntExt ldapAuthed;
- LocalStringExt ldapVhost;
- std::string base;
- std::string attribute;
- std::string ldapserver;
- std::string allowpattern;
- std::string killreason;
- std::string username;
- std::string password;
- std::string vhost;
- std::vector<std::string> whitelistedcidrs;
- std::vector<std::pair<std::string, std::string> > requiredattributes;
- int searchscope;
- bool verbose;
- bool useusername;
- LDAP *conn;
-
-public:
- ModuleLDAPAuth()
- : ldapAuthed("ldapauth", this)
- , ldapVhost("ldapauth_vhost", this)
- {
- conn = NULL;
- }
-
- void init()
- {
- ServerInstance->Modules->AddService(ldapAuthed);
- ServerInstance->Modules->AddService(ldapVhost);
- Implementation eventlist[] = { I_OnCheckReady, I_OnRehash,I_OnUserRegister, I_OnUserConnect };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- OnRehash(NULL);
- }
-
- ~ModuleLDAPAuth()
- {
- if (conn)
- ldap_unbind_ext(conn, NULL, NULL);
- }
-
- void OnRehash(User* user)
- {
- ConfigTag* tag = ServerInstance->Config->ConfValue("ldapauth");
- whitelistedcidrs.clear();
- requiredattributes.clear();
-
- base = tag->getString("baserdn");
- attribute = tag->getString("attribute");
- ldapserver = tag->getString("server");
- allowpattern = tag->getString("allowpattern");
- killreason = tag->getString("killreason");
- std::string scope = tag->getString("searchscope");
- username = tag->getString("binddn");
- password = tag->getString("bindauth");
- vhost = tag->getString("host");
- verbose = tag->getBool("verbose"); /* Set to true if failed connects should be reported to operators */
- useusername = tag->getBool("userfield");
-
- ConfigTagList whitelisttags = ServerInstance->Config->ConfTags("ldapwhitelist");
-
- for (ConfigIter i = whitelisttags.first; i != whitelisttags.second; ++i)
- {
- std::string cidr = i->second->getString("cidr");
- if (!cidr.empty()) {
- whitelistedcidrs.push_back(cidr);
- }
- }
-
- ConfigTagList attributetags = ServerInstance->Config->ConfTags("ldaprequire");
-
- for (ConfigIter i = attributetags.first; i != attributetags.second; ++i)
- {
- const std::string attr = i->second->getString("attribute");
- const std::string val = i->second->getString("value");
-
- if (!attr.empty() && !val.empty())
- requiredattributes.push_back(make_pair(attr, val));
- }
-
- if (scope == "base")
- searchscope = LDAP_SCOPE_BASE;
- else if (scope == "onelevel")
- searchscope = LDAP_SCOPE_ONELEVEL;
- else searchscope = LDAP_SCOPE_SUBTREE;
-
- Connect();
- }
-
- bool Connect()
- {
- if (conn != NULL)
- ldap_unbind_ext(conn, NULL, NULL);
- int res, v = LDAP_VERSION3;
- res = ldap_initialize(&conn, ldapserver.c_str());
- if (res != LDAP_SUCCESS)
- {
- if (verbose)
- ServerInstance->SNO->WriteToSnoMask('c', "LDAP connection failed: %s", ldap_err2string(res));
- conn = NULL;
- return false;
- }
-
- res = ldap_set_option(conn, LDAP_OPT_PROTOCOL_VERSION, (void *)&v);
- if (res != LDAP_SUCCESS)
- {
- if (verbose)
- ServerInstance->SNO->WriteToSnoMask('c', "LDAP set protocol to v3 failed: %s", ldap_err2string(res));
- ldap_unbind_ext(conn, NULL, NULL);
- conn = NULL;
- return false;
- }
- return true;
- }
-
- std::string SafeReplace(const std::string &text, std::map<std::string,
- std::string> &replacements)
- {
- std::string result;
- result.reserve(MAXBUF);
-
- for (unsigned int i = 0; i < text.length(); ++i) {
- char c = text[i];
- if (c == '$') {
- // find the first nonalpha
- i++;
- unsigned int start = i;
-
- while (i < text.length() - 1 && isalpha(text[i + 1]))
- ++i;
-
- std::string key = text.substr(start, (i - start) + 1);
- result.append(replacements[key]);
- } else {
- result.push_back(c);
- }
- }
-
- return result;
- }
-
- virtual void OnUserConnect(LocalUser *user)
- {
- std::string* cc = ldapVhost.get(user);
- if (cc)
- {
- user->ChangeDisplayedHost(cc->c_str());
- ldapVhost.unset(user);
- }
- }
-
- ModResult OnUserRegister(LocalUser* user)
- {
- if ((!allowpattern.empty()) && (InspIRCd::Match(user->nick,allowpattern)))
- {
- ldapAuthed.set(user,1);
- return MOD_RES_PASSTHRU;
- }
-
- for (std::vector<std::string>::iterator i = whitelistedcidrs.begin(); i != whitelistedcidrs.end(); i++)
- {
- if (InspIRCd::MatchCIDR(user->GetIPString(), *i, ascii_case_insensitive_map))
- {
- ldapAuthed.set(user,1);
- return MOD_RES_PASSTHRU;
- }
- }
-
- if (!CheckCredentials(user))
- {
- ServerInstance->Users->QuitUser(user, killreason);
- return MOD_RES_DENY;
- }
- return MOD_RES_PASSTHRU;
- }
-
- bool CheckCredentials(LocalUser* user)
- {
- if (conn == NULL)
- if (!Connect())
- return false;
-
- if (user->password.empty())
- {
- if (verbose)
- ServerInstance->SNO->WriteToSnoMask('c', "Forbidden connection from %s (No password provided)", user->GetFullRealHost().c_str());
- return false;
- }
-
- int res;
- // bind anonymously if no bind DN and authentication are given in the config
- struct berval cred;
- cred.bv_val = const_cast<char*>(password.c_str());
- cred.bv_len = password.length();
-
- if ((res = ldap_sasl_bind_s(conn, username.c_str(), LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL)) != LDAP_SUCCESS)
- {
- if (res == LDAP_SERVER_DOWN)
- {
- // Attempt to reconnect if the connection dropped
- if (verbose)
- ServerInstance->SNO->WriteToSnoMask('a', "LDAP server has gone away - reconnecting...");
- Connect();
- res = ldap_sasl_bind_s(conn, username.c_str(), LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
- }
-
- if (res != LDAP_SUCCESS)
- {
- if (verbose)
- ServerInstance->SNO->WriteToSnoMask('c', "Forbidden connection from %s (LDAP bind failed: %s)", user->GetFullRealHost().c_str(), ldap_err2string(res));
- ldap_unbind_ext(conn, NULL, NULL);
- conn = NULL;
- return false;
- }
- }
-
- RAIILDAPMessage msg;
- std::string what = (attribute + "=" + (useusername ? user->ident : user->nick));
- if ((res = ldap_search_ext_s(conn, base.c_str(), searchscope, what.c_str(), NULL, 0, NULL, NULL, NULL, 0, &msg)) != LDAP_SUCCESS)
- {
- // Do a second search, based on password, if it contains a :
- // That is, PASS <user>:<password> will work.
- size_t pos = user->password.find(":");
- if (pos != std::string::npos)
- {
- // manpage says we must deallocate regardless of success or failure
- // since we're about to do another query (and reset msg), first
- // free the old one.
- msg.dealloc();
-
- std::string cutpassword = user->password.substr(0, pos);
- res = ldap_search_ext_s(conn, base.c_str(), searchscope, cutpassword.c_str(), NULL, 0, NULL, NULL, NULL, 0, &msg);
-
- if (res == LDAP_SUCCESS)
- {
- // Trim the user: prefix, leaving just 'pass' for later password check
- user->password = user->password.substr(pos + 1);
- }
- }
-
- // It may have found based on user:pass check above.
- if (res != LDAP_SUCCESS)
- {
- if (verbose)
- ServerInstance->SNO->WriteToSnoMask('c', "Forbidden connection from %s (LDAP search failed: %s)", user->GetFullRealHost().c_str(), ldap_err2string(res));
- return false;
- }
- }
- if (ldap_count_entries(conn, msg) > 1)
- {
- if (verbose)
- ServerInstance->SNO->WriteToSnoMask('c', "Forbidden connection from %s (LDAP search returned more than one result: %s)", user->GetFullRealHost().c_str(), ldap_err2string(res));
- return false;
- }
-
- LDAPMessage *entry;
- if ((entry = ldap_first_entry(conn, msg)) == NULL)
- {
- if (verbose)
- ServerInstance->SNO->WriteToSnoMask('c', "Forbidden connection from %s (LDAP search returned no results: %s)", user->GetFullRealHost().c_str(), ldap_err2string(res));
- return false;
- }
- cred.bv_val = (char*)user->password.data();
- cred.bv_len = user->password.length();
- RAIILDAPString DN(ldap_get_dn(conn, entry));
- if ((res = ldap_sasl_bind_s(conn, DN, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL)) != LDAP_SUCCESS)
- {
- if (verbose)
- ServerInstance->SNO->WriteToSnoMask('c', "Forbidden connection from %s (%s)", user->GetFullRealHost().c_str(), ldap_err2string(res));
- return false;
- }
-
- if (!requiredattributes.empty())
- {
- bool authed = false;
-
- for (std::vector<std::pair<std::string, std::string> >::const_iterator it = requiredattributes.begin(); it != requiredattributes.end(); ++it)
- {
- const std::string &attr = it->first;
- const std::string &val = it->second;
-
- struct berval attr_value;
- attr_value.bv_val = const_cast<char*>(val.c_str());
- attr_value.bv_len = val.length();
-
- ServerInstance->Logs->Log("m_ldapauth", DEBUG, "LDAP compare: %s=%s", attr.c_str(), val.c_str());
-
- authed = (ldap_compare_ext_s(conn, DN, attr.c_str(), &attr_value, NULL, NULL) == LDAP_COMPARE_TRUE);
-
- if (authed)
- break;
- }
-
- if (!authed)
- {
- if (verbose)
- ServerInstance->SNO->WriteToSnoMask('c', "Forbidden connection from %s (Lacks required LDAP attributes)", user->GetFullRealHost().c_str());
- return false;
- }
- }
-
- if (!vhost.empty())
- {
- irc::commasepstream stream(DN);
-
- // mashed map of key:value parts of the DN
- std::map<std::string, std::string> dnParts;
-
- std::string dnPart;
- while (stream.GetToken(dnPart))
- {
- std::string::size_type pos = dnPart.find('=');
- if (pos == std::string::npos) // malformed
- continue;
-
- std::string key = dnPart.substr(0, pos);
- std::string value = dnPart.substr(pos + 1, dnPart.length() - pos + 1); // +1s to skip the = itself
- dnParts[key] = value;
- }
-
- // change host according to config key
- ldapVhost.set(user, SafeReplace(vhost, dnParts));
- }
-
- ldapAuthed.set(user,1);
- return true;
- }
-
- ModResult OnCheckReady(LocalUser* user)
- {
- return ldapAuthed.get(user) ? MOD_RES_PASSTHRU : MOD_RES_DENY;
- }
-
- Version GetVersion()
- {
- return Version("Allow/Deny connections based upon answer from LDAP server", VF_VENDOR);
- }
-
-};
-
-MODULE_INIT(ModuleLDAPAuth)
diff --git a/src/modules/extra/m_ldapoper.cpp b/src/modules/extra/m_ldapoper.cpp
deleted file mode 100644
index 1f46361d4..000000000
--- a/src/modules/extra/m_ldapoper.cpp
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Robin Burchell <robin+git@viroteck.net>
- * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com>
- * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc>
- * Copyright (C) 2007 Carsten Valdemar Munk <carsten.munk+inspircd@gmail.com>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-#include "users.h"
-#include "channels.h"
-#include "modules.h"
-
-#include <ldap.h>
-
-#ifdef _WIN32
-# pragma comment(lib, "libldap.lib")
-# pragma comment(lib, "liblber.lib")
-#endif
-
-/* $ModDesc: Adds the ability to authenticate opers via LDAP */
-/* $LinkerFlags: -lldap */
-
-// Duplicated code, also found in cmd_oper and m_sqloper
-static bool OneOfMatches(const char* host, const char* ip, const std::string& hostlist)
-{
- std::stringstream hl(hostlist);
- std::string xhost;
- while (hl >> xhost)
- {
- if (InspIRCd::Match(host, xhost, ascii_case_insensitive_map) || InspIRCd::MatchCIDR(ip, xhost, ascii_case_insensitive_map))
- {
- return true;
- }
- }
- return false;
-}
-
-struct RAIILDAPString
-{
- char *str;
-
- RAIILDAPString(char *Str)
- : str(Str)
- {
- }
-
- ~RAIILDAPString()
- {
- ldap_memfree(str);
- }
-
- operator char*()
- {
- return str;
- }
-
- operator std::string()
- {
- return str;
- }
-};
-
-class ModuleLDAPAuth : public Module
-{
- std::string base;
- std::string ldapserver;
- std::string username;
- std::string password;
- std::string attribute;
- int searchscope;
- LDAP *conn;
-
- bool HandleOper(LocalUser* user, const std::string& opername, const std::string& inputpass)
- {
- OperIndex::iterator it = ServerInstance->Config->oper_blocks.find(opername);
- if (it == ServerInstance->Config->oper_blocks.end())
- return false;
-
- ConfigTag* tag = it->second->oper_block;
- if (!tag)
- return false;
-
- std::string acceptedhosts = tag->getString("host");
- std::string hostname = user->ident + "@" + user->host;
- if (!OneOfMatches(hostname.c_str(), user->GetIPString(), acceptedhosts))
- return false;
-
- if (!LookupOper(opername, inputpass))
- return false;
-
- user->Oper(it->second);
- return true;
- }
-
-public:
- ModuleLDAPAuth()
- : conn(NULL)
- {
- }
-
- void init()
- {
- Implementation eventlist[] = { I_OnRehash, I_OnPreCommand };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- OnRehash(NULL);
- }
-
- virtual ~ModuleLDAPAuth()
- {
- if (conn)
- ldap_unbind_ext(conn, NULL, NULL);
- }
-
- virtual void OnRehash(User* user)
- {
- ConfigTag* tag = ServerInstance->Config->ConfValue("ldapoper");
-
- base = tag->getString("baserdn");
- ldapserver = tag->getString("server");
- std::string scope = tag->getString("searchscope");
- username = tag->getString("binddn");
- password = tag->getString("bindauth");
- attribute = tag->getString("attribute");
-
- if (scope == "base")
- searchscope = LDAP_SCOPE_BASE;
- else if (scope == "onelevel")
- searchscope = LDAP_SCOPE_ONELEVEL;
- else searchscope = LDAP_SCOPE_SUBTREE;
-
- Connect();
- }
-
- bool Connect()
- {
- if (conn != NULL)
- ldap_unbind_ext(conn, NULL, NULL);
- int res, v = LDAP_VERSION3;
- res = ldap_initialize(&conn, ldapserver.c_str());
- if (res != LDAP_SUCCESS)
- {
- conn = NULL;
- return false;
- }
-
- res = ldap_set_option(conn, LDAP_OPT_PROTOCOL_VERSION, (void *)&v);
- if (res != LDAP_SUCCESS)
- {
- ldap_unbind_ext(conn, NULL, NULL);
- conn = NULL;
- return false;
- }
- return true;
- }
-
- ModResult OnPreCommand(std::string& command, std::vector<std::string>& parameters, LocalUser* user, bool validated, const std::string& original_line)
- {
- if (validated && command == "OPER" && parameters.size() >= 2)
- {
- if (HandleOper(user, parameters[0], parameters[1]))
- return MOD_RES_DENY;
- }
- return MOD_RES_PASSTHRU;
- }
-
- bool LookupOper(const std::string& opername, const std::string& opassword)
- {
- if (conn == NULL)
- if (!Connect())
- return false;
-
- int res;
- char* authpass = strdup(password.c_str());
- // bind anonymously if no bind DN and authentication are given in the config
- struct berval cred;
- cred.bv_val = authpass;
- cred.bv_len = password.length();
-
- if ((res = ldap_sasl_bind_s(conn, username.c_str(), LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL)) != LDAP_SUCCESS)
- {
- if (res == LDAP_SERVER_DOWN)
- {
- // Attempt to reconnect if the connection dropped
- ServerInstance->SNO->WriteToSnoMask('a', "LDAP server has gone away - reconnecting...");
- Connect();
- res = ldap_sasl_bind_s(conn, username.c_str(), LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
- }
-
- if (res != LDAP_SUCCESS)
- {
- free(authpass);
- ldap_unbind_ext(conn, NULL, NULL);
- conn = NULL;
- return false;
- }
- }
- free(authpass);
-
- LDAPMessage *msg, *entry;
- std::string what = attribute + "=" + opername;
- if ((res = ldap_search_ext_s(conn, base.c_str(), searchscope, what.c_str(), NULL, 0, NULL, NULL, NULL, 0, &msg)) != LDAP_SUCCESS)
- {
- return false;
- }
- if (ldap_count_entries(conn, msg) > 1)
- {
- ldap_msgfree(msg);
- return false;
- }
- if ((entry = ldap_first_entry(conn, msg)) == NULL)
- {
- ldap_msgfree(msg);
- return false;
- }
- authpass = strdup(opassword.c_str());
- cred.bv_val = authpass;
- cred.bv_len = opassword.length();
- RAIILDAPString DN(ldap_get_dn(conn, entry));
- if ((res = ldap_sasl_bind_s(conn, DN, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL)) == LDAP_SUCCESS)
- {
- free(authpass);
- ldap_msgfree(msg);
- return true;
- }
- else
- {
- free(authpass);
- ldap_msgfree(msg);
- return false;
- }
- }
-
- virtual Version GetVersion()
- {
- return Version("Adds the ability to authenticate opers via LDAP", VF_VENDOR);
- }
-
-};
-
-MODULE_INIT(ModuleLDAPAuth)
diff --git a/src/modules/extra/m_mssql.cpp b/src/modules/extra/m_mssql.cpp
index 598f9aac9..725a647c0 100644
--- a/src/modules/extra/m_mssql.cpp
+++ b/src/modules/extra/m_mssql.cpp
@@ -24,16 +24,11 @@
#include "inspircd.h"
#include <tds.h>
#include <tdsconvert.h>
-#include "users.h"
-#include "channels.h"
-#include "modules.h"
#include "m_sqlv2.h"
-/* $ModDesc: MsSQL provider */
/* $CompileFlags: exec("grep VERSION_NO /usr/include/tdsver.h 2>/dev/null | perl -e 'print "-D_TDSVER=".((<> =~ /freetds v(\d+\.\d+)/i) ? $1*100 : 0);'") */
/* $LinkerFlags: -ltds */
-/* $ModDep: m_sqlv2.h */
class SQLConn;
class MsSQLResult;
@@ -64,8 +59,8 @@ class QueryThread : public SocketThread
public:
QueryThread(ModuleMsSQL* mod) : Parent(mod) { }
~QueryThread() { }
- virtual void Run();
- virtual void OnNotify();
+ void Run();
+ void OnNotify();
};
class MsSQLResult : public SQLresult
@@ -88,10 +83,6 @@ class MsSQLResult : public SQLresult
{
}
- ~MsSQLResult()
- {
- }
-
void AddRow(int colsnum, char **dat, char **colname)
{
colnames.clear();
@@ -111,17 +102,17 @@ class MsSQLResult : public SQLresult
rows++;
}
- virtual int Rows()
+ int Rows()
{
return rows;
}
- virtual int Cols()
+ int Cols()
{
return cols;
}
- virtual std::string ColName(int column)
+ std::string ColName(int column)
{
if (column < (int)colnames.size())
{
@@ -134,7 +125,7 @@ class MsSQLResult : public SQLresult
return "";
}
- virtual int ColNum(const std::string &column)
+ int ColNum(const std::string &column)
{
for (unsigned int i = 0; i < colnames.size(); i++)
{
@@ -145,7 +136,7 @@ class MsSQLResult : public SQLresult
return 0;
}
- virtual SQLfield GetValue(int row, int column)
+ SQLfield GetValue(int row, int column)
{
if ((row >= 0) && (row < rows) && (column >= 0) && (column < Cols()))
{
@@ -158,7 +149,7 @@ class MsSQLResult : public SQLresult
return SQLfield("",true);
}
- virtual SQLfieldList& GetRow()
+ SQLfieldList& GetRow()
{
if (currentrow < rows)
return fieldlists[currentrow];
@@ -166,7 +157,7 @@ class MsSQLResult : public SQLresult
return emptyfieldlist;
}
- virtual SQLfieldMap& GetRowMap()
+ SQLfieldMap& GetRowMap()
{
/* In an effort to reduce overhead we don't actually allocate the map
* until the first time it's needed...so...
@@ -192,7 +183,7 @@ class MsSQLResult : public SQLresult
return *fieldmap;
}
- virtual SQLfieldList* GetRowPtr()
+ SQLfieldList* GetRowPtr()
{
fieldlist = new SQLfieldList();
@@ -207,7 +198,7 @@ class MsSQLResult : public SQLresult
return fieldlist;
}
- virtual SQLfieldMap* GetRowMapPtr()
+ SQLfieldMap* GetRowMapPtr()
{
fieldmap = new SQLfieldMap();
@@ -223,12 +214,12 @@ class MsSQLResult : public SQLresult
return fieldmap;
}
- virtual void Free(SQLfieldMap* fm)
+ void Free(SQLfieldMap* fm)
{
delete fm;
}
- virtual void Free(SQLfieldList* fl)
+ void Free(SQLfieldList* fl)
{
delete fl;
}
@@ -258,7 +249,7 @@ class SQLConn : public classbase
if (tds_process_simple_query(sock) != TDS_SUCCEED)
{
LoggingMutex->Lock();
- ServerInstance->Logs->Log("m_mssql",DEFAULT, "WARNING: Could not select database " + host.name + " for DB with id: " + host.id);
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "WARNING: Could not select database " + host.name + " for DB with id: " + host.id);
LoggingMutex->Unlock();
CloseDB();
}
@@ -266,7 +257,7 @@ class SQLConn : public classbase
else
{
LoggingMutex->Lock();
- ServerInstance->Logs->Log("m_mssql",DEFAULT, "WARNING: Could not select database " + host.name + " for DB with id: " + host.id);
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "WARNING: Could not select database " + host.name + " for DB with id: " + host.id);
LoggingMutex->Unlock();
CloseDB();
}
@@ -274,7 +265,7 @@ class SQLConn : public classbase
else
{
LoggingMutex->Lock();
- ServerInstance->Logs->Log("m_mssql",DEFAULT, "WARNING: Could not connect to DB with id: " + host.id);
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "WARNING: Could not connect to DB with id: " + host.id);
LoggingMutex->Unlock();
CloseDB();
}
@@ -433,7 +424,7 @@ class SQLConn : public classbase
char* msquery = strdup(req->query.q.data());
LoggingMutex->Lock();
- ServerInstance->Logs->Log("m_mssql",DEBUG,"doing Query: %s",msquery);
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "doing Query: %s",msquery);
LoggingMutex->Unlock();
if (tds_submit_query(sock, msquery) != TDS_SUCCEED)
{
@@ -449,8 +440,8 @@ class SQLConn : public classbase
int tds_res;
while (tds_process_tokens(sock, &tds_res, NULL, TDS_TOKEN_RESULTS) == TDS_SUCCEED)
{
- //ServerInstance->Logs->Log("m_mssql",DEBUG,"<******> result type: %d", tds_res);
- //ServerInstance->Logs->Log("m_mssql",DEBUG,"AFFECTED ROWS: %d", sock->rows_affected);
+ //ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "<******> result type: %d", tds_res);
+ //ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "AFFECTED ROWS: %d", sock->rows_affected);
switch (tds_res)
{
case TDS_ROWFMT_RESULT:
@@ -476,8 +467,8 @@ class SQLConn : public classbase
if (sock->res_info->row_count > 0)
{
int cols = sock->res_info->num_cols;
- char** name = new char*[MAXBUF];
- char** data = new char*[MAXBUF];
+ char** name = new char*[512];
+ char** data = new char*[512];
for (int j=0; j<cols; j++)
{
TDSCOLUMN* col = sock->current_results->columns[j];
@@ -516,7 +507,7 @@ class SQLConn : public classbase
{
SQLConn* sc = (SQLConn*)pContext->parent;
LoggingMutex->Lock();
- ServerInstance->Logs->Log("m_mssql", DEBUG, "Message for DB with id: %s -> %s", sc->host.id.c_str(), pMessage->message);
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Message for DB with id: %s -> %s", sc->host.id.c_str(), pMessage->message);
LoggingMutex->Unlock();
return 0;
}
@@ -525,7 +516,7 @@ class SQLConn : public classbase
{
SQLConn* sc = (SQLConn*)pContext->parent;
LoggingMutex->Lock();
- ServerInstance->Logs->Log("m_mssql", DEFAULT, "Error for DB with id: %s -> %s", sc->host.id.c_str(), pMessage->message);
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Error for DB with id: %s -> %s", sc->host.id.c_str(), pMessage->message);
LoggingMutex->Unlock();
return 0;
}
@@ -657,18 +648,14 @@ class ModuleMsSQL : public Module
queryDispatcher = new QueryThread(this);
}
- void init()
+ void init() CXX11_OVERRIDE
{
ReadConf();
- ServerInstance->Threads->Start(queryDispatcher);
-
- Implementation eventlist[] = { I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- ServerInstance->Modules->AddService(sqlserv);
+ ServerInstance->Threads.Start(queryDispatcher);
}
- virtual ~ModuleMsSQL()
+ ~ModuleMsSQL()
{
queryDispatcher->join();
delete queryDispatcher;
@@ -753,7 +740,7 @@ class ModuleMsSQL : public Module
if (HasHost(hi))
{
LoggingMutex->Lock();
- ServerInstance->Logs->Log("m_mssql",DEFAULT, "WARNING: A MsSQL connection with id: %s already exists. Aborting database open attempt.", hi.id.c_str());
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "WARNING: A MsSQL connection with id: %s already exists. Aborting database open attempt.", hi.id.c_str());
LoggingMutex->Unlock();
return;
}
@@ -787,14 +774,14 @@ class ModuleMsSQL : public Module
connections.clear();
}
- virtual void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
queryDispatcher->LockQueue();
ReadConf();
queryDispatcher->UnlockQueueWakeup();
}
- void OnRequest(Request& request)
+ void OnRequest(Request& request) CXX11_OVERRIDE
{
if(strcmp(SQLREQID, request.id) == 0)
{
@@ -825,7 +812,7 @@ class ModuleMsSQL : public Module
return ++currid;
}
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("MsSQL provider", VF_VENDOR);
}
diff --git a/src/modules/extra/m_mysql.cpp b/src/modules/extra/m_mysql.cpp
index 01b1553b0..1002a98ba 100644
--- a/src/modules/extra/m_mysql.cpp
+++ b/src/modules/extra/m_mysql.cpp
@@ -25,7 +25,7 @@
#include "inspircd.h"
#include <mysql.h>
-#include "sql.h"
+#include "modules/sql.h"
#ifdef _WIN32
# pragma comment(lib, "libmysql.lib")
@@ -33,7 +33,6 @@
/* VERSION 3 API: With nonblocking (threaded) requests */
-/* $ModDesc: SQL Service Provider module for all other m_sql* modules */
/* $CompileFlags: exec("mysql_config --include") */
/* $LinkerFlags: exec("mysql_config --libs_r") rpath("mysql_config --libs_r") */
@@ -105,11 +104,11 @@ class ModuleSQL : public Module
ConnMap connections; // main thread only
ModuleSQL();
- void init();
+ void init() CXX11_OVERRIDE;
~ModuleSQL();
- void OnRehash(User* user);
- void OnUnloadModule(Module* mod);
- Version GetVersion();
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE;
+ void OnUnloadModule(Module* mod) CXX11_OVERRIDE;
+ Version GetVersion() CXX11_OVERRIDE;
};
class DispatcherThread : public SocketThread
@@ -119,8 +118,8 @@ class DispatcherThread : public SocketThread
public:
DispatcherThread(ModuleSQL* CreatorModule) : Parent(CreatorModule) { }
~DispatcherThread() { }
- virtual void Run();
- virtual void OnNotify();
+ void Run();
+ void OnNotify();
};
#if !defined(MYSQL_VERSION_ID) || MYSQL_VERSION_ID<32224
@@ -186,21 +185,17 @@ class MySQLresult : public SQLResult
}
- ~MySQLresult()
- {
- }
-
- virtual int Rows()
+ int Rows()
{
return rows;
}
- virtual void GetCols(std::vector<std::string>& result)
+ void GetCols(std::vector<std::string>& result)
{
result.assign(colnames.begin(), colnames.end());
}
- virtual SQLEntry GetValue(int row, int column)
+ SQLEntry GetValue(int row, int column)
{
if ((row >= 0) && (row < rows) && (column >= 0) && (column < (int)fieldlists[row].size()))
{
@@ -209,7 +204,7 @@ class MySQLresult : public SQLResult
return SQLEntry();
}
- virtual bool GetRow(SQLEntries& result)
+ bool GetRow(SQLEntries& result)
{
if (currentrow < rows)
{
@@ -383,12 +378,7 @@ ModuleSQL::ModuleSQL()
void ModuleSQL::init()
{
Dispatcher = new DispatcherThread(this);
- ServerInstance->Threads->Start(Dispatcher);
-
- Implementation eventlist[] = { I_OnRehash, I_OnUnloadModule };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
-
- OnRehash(NULL);
+ ServerInstance->Threads.Start(Dispatcher);
}
ModuleSQL::~ModuleSQL()
@@ -405,7 +395,7 @@ ModuleSQL::~ModuleSQL()
}
}
-void ModuleSQL::OnRehash(User* user)
+void ModuleSQL::ReadConfig(ConfigStatus& status)
{
ConnMap conns;
ConfigTagList tags = ServerInstance->Config->ConfTags("database");
diff --git a/src/modules/extra/m_pgsql.cpp b/src/modules/extra/m_pgsql.cpp
index ac247548a..b89633ede 100644
--- a/src/modules/extra/m_pgsql.cpp
+++ b/src/modules/extra/m_pgsql.cpp
@@ -24,11 +24,9 @@
#include "inspircd.h"
#include <cstdlib>
-#include <sstream>
#include <libpq-fe.h>
-#include "sql.h"
+#include "modules/sql.h"
-/* $ModDesc: PostgreSQL Service Provider module for all other m_sql* modules, uses v2 of the SQL API */
/* $CompileFlags: -Iexec("pg_config --includedir") eval("my $s = `pg_config --version`;$s =~ /^.*?(\d+)\.(\d+)\.(\d+).*?$/;my $v = hex(sprintf("0x%02x%02x%02x", $1, $2, $3));print "-DPGSQL_HAS_ESCAPECONN" if(($v >= 0x080104) || ($v >= 0x07030F && $v < 0x070400) || ($v >= 0x07040D && $v < 0x080000) || ($v >= 0x080008 && $v < 0x080100));") */
/* $LinkerFlags: -Lexec("pg_config --libdir") -lpq */
@@ -59,10 +57,10 @@ class ReconnectTimer : public Timer
private:
ModulePgSQL* mod;
public:
- ReconnectTimer(ModulePgSQL* m) : Timer(5, ServerInstance->Time(), false), mod(m)
+ ReconnectTimer(ModulePgSQL* m) : Timer(5, false), mod(m)
{
}
- virtual void Tick(time_t TIME);
+ bool Tick(time_t TIME);
};
struct QueueItem
@@ -97,12 +95,12 @@ class PgSQLresult : public SQLResult
PQclear(res);
}
- virtual int Rows()
+ int Rows()
{
return rows;
}
- virtual void GetCols(std::vector<std::string>& result)
+ void GetCols(std::vector<std::string>& result)
{
result.resize(PQnfields(res));
for(unsigned int i=0; i < result.size(); i++)
@@ -111,7 +109,7 @@ class PgSQLresult : public SQLResult
}
}
- virtual SQLEntry GetValue(int row, int column)
+ SQLEntry GetValue(int row, int column)
{
char* v = PQgetvalue(res, row, column);
if (!v || PQgetisnull(res, row, column))
@@ -120,7 +118,7 @@ class PgSQLresult : public SQLResult
return SQLEntry(std::string(v, PQgetlength(res, row, column)));
}
- virtual bool GetRow(SQLEntries& result)
+ bool GetRow(SQLEntries& result)
{
if (currentrow >= PQntuples(res))
return false;
@@ -152,7 +150,7 @@ class SQLConn : public SQLProvider, public EventHandler
{
if (!DoConnect())
{
- ServerInstance->Logs->Log("m_pgsql",DEFAULT, "WARNING: Could not connect to database " + tag->getString("id"));
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "WARNING: Could not connect to database " + tag->getString("id"));
DelayReconnect();
}
}
@@ -180,7 +178,7 @@ class SQLConn : public SQLProvider, public EventHandler
}
}
- virtual void HandleEvent(EventType et, int errornum)
+ void HandleEvent(EventType et, int errornum)
{
switch (et)
{
@@ -242,9 +240,9 @@ class SQLConn : public SQLProvider, public EventHandler
if(this->fd <= -1)
return false;
- if (!ServerInstance->SE->AddFd(this, FD_WANT_NO_WRITE | FD_WANT_NO_READ))
+ if (!SocketEngine::AddFd(this, FD_WANT_NO_WRITE | FD_WANT_NO_READ))
{
- ServerInstance->Logs->Log("m_pgsql",DEBUG, "BUG: Couldn't add pgsql socket to socket engine");
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "BUG: Couldn't add pgsql socket to socket engine");
return false;
}
@@ -257,17 +255,17 @@ class SQLConn : public SQLProvider, public EventHandler
switch(PQconnectPoll(sql))
{
case PGRES_POLLING_WRITING:
- ServerInstance->SE->ChangeEventMask(this, FD_WANT_POLL_WRITE | FD_WANT_NO_READ);
+ SocketEngine::ChangeEventMask(this, FD_WANT_POLL_WRITE | FD_WANT_NO_READ);
status = CWRITE;
return true;
case PGRES_POLLING_READING:
- ServerInstance->SE->ChangeEventMask(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
+ SocketEngine::ChangeEventMask(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
status = CREAD;
return true;
case PGRES_POLLING_FAILED:
return false;
case PGRES_POLLING_OK:
- ServerInstance->SE->ChangeEventMask(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
+ SocketEngine::ChangeEventMask(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
status = WWRITE;
DoConnectedPoll();
default:
@@ -350,17 +348,17 @@ restart:
switch(PQresetPoll(sql))
{
case PGRES_POLLING_WRITING:
- ServerInstance->SE->ChangeEventMask(this, FD_WANT_POLL_WRITE | FD_WANT_NO_READ);
+ SocketEngine::ChangeEventMask(this, FD_WANT_POLL_WRITE | FD_WANT_NO_READ);
status = CWRITE;
return DoPoll();
case PGRES_POLLING_READING:
- ServerInstance->SE->ChangeEventMask(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
+ SocketEngine::ChangeEventMask(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
status = CREAD;
return true;
case PGRES_POLLING_FAILED:
return false;
case PGRES_POLLING_OK:
- ServerInstance->SE->ChangeEventMask(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
+ SocketEngine::ChangeEventMask(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
status = WWRITE;
DoConnectedPoll();
default:
@@ -417,7 +415,7 @@ restart:
int error;
size_t escapedsize = PQescapeStringConn(sql, &buffer[0], parm.data(), parm.length(), &error);
if (error)
- ServerInstance->Logs->Log("m_pgsql", DEBUG, "BUG: Apparently PQescapeStringConn() failed");
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "BUG: Apparently PQescapeStringConn() failed");
#else
size_t escapedsize = PQescapeString(&buffer[0], parm.data(), parm.length());
#endif
@@ -452,7 +450,7 @@ restart:
int error;
size_t escapedsize = PQescapeStringConn(sql, &buffer[0], parm.data(), parm.length(), &error);
if (error)
- ServerInstance->Logs->Log("m_pgsql", DEBUG, "BUG: Apparently PQescapeStringConn() failed");
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "BUG: Apparently PQescapeStringConn() failed");
#else
size_t escapedsize = PQescapeString(&buffer[0], parm.data(), parm.length());
#endif
@@ -488,7 +486,7 @@ restart:
void Close()
{
- ServerInstance->SE->DelFd(this);
+ SocketEngine::DelFd(this);
if(sql)
{
@@ -505,25 +503,17 @@ class ModulePgSQL : public Module
ReconnectTimer* retimer;
ModulePgSQL()
+ : retimer(NULL)
{
}
- void init()
+ ~ModulePgSQL()
{
- ReadConf();
-
- Implementation eventlist[] = { I_OnUnloadModule, I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- virtual ~ModulePgSQL()
- {
- if (retimer)
- ServerInstance->Timers->DelTimer(retimer);
+ delete retimer;
ClearAllConnections();
}
- virtual void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ReadConf();
}
@@ -564,7 +554,7 @@ class ModulePgSQL : public Module
connections.clear();
}
- void OnUnloadModule(Module* mod)
+ void OnUnloadModule(Module* mod) CXX11_OVERRIDE
{
SQLerror err(SQL_BAD_DBID);
for(ConnMap::iterator i = connections.begin(); i != connections.end(); i++)
@@ -592,16 +582,18 @@ class ModulePgSQL : public Module
}
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("PostgreSQL Service Provider module for all other m_sql* modules, uses v2 of the SQL API", VF_VENDOR);
}
};
-void ReconnectTimer::Tick(time_t time)
+bool ReconnectTimer::Tick(time_t time)
{
mod->retimer = NULL;
mod->ReadConf();
+ delete this;
+ return false;
}
void SQLConn::DelayReconnect()
@@ -615,7 +607,7 @@ void SQLConn::DelayReconnect()
if (!mod->retimer)
{
mod->retimer = new ReconnectTimer(mod);
- ServerInstance->Timers->AddTimer(mod->retimer);
+ ServerInstance->Timers.AddTimer(mod->retimer);
}
}
}
diff --git a/src/modules/extra/m_regex_pcre.cpp b/src/modules/extra/m_regex_pcre.cpp
index cba234c8c..9ae6719ba 100644
--- a/src/modules/extra/m_regex_pcre.cpp
+++ b/src/modules/extra/m_regex_pcre.cpp
@@ -20,10 +20,8 @@
#include "inspircd.h"
#include <pcre.h>
-#include "m_regex.h"
+#include "modules/regex.h"
-/* $ModDesc: Regex Provider Module for PCRE */
-/* $ModDep: m_regex.h */
/* $CompileFlags: exec("pcre-config --cflags") */
/* $LinkerFlags: exec("pcre-config --libs") rpath("pcre-config --libs") -lpcre */
@@ -31,21 +29,11 @@
# pragma comment(lib, "libpcre.lib")
#endif
-class PCREException : public ModuleException
-{
-public:
- PCREException(const std::string& rx, const std::string& error, int erroffset)
- : ModuleException("Error in regex " + rx + " at offset " + ConvToStr(erroffset) + ": " + error)
- {
- }
-};
-
class PCRERegex : public Regex
{
-private:
pcre* regex;
-public:
+ public:
PCRERegex(const std::string& rx) : Regex(rx)
{
const char* error;
@@ -53,24 +41,19 @@ public:
regex = pcre_compile(rx.c_str(), 0, &error, &erroffset, NULL);
if (!regex)
{
- ServerInstance->Logs->Log("REGEX", DEBUG, "pcre_compile failed: /%s/ [%d] %s", rx.c_str(), erroffset, error);
- throw PCREException(rx, error, erroffset);
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "pcre_compile failed: /%s/ [%d] %s", rx.c_str(), erroffset, error);
+ throw RegexException(rx, error, erroffset);
}
}
- virtual ~PCRERegex()
+ ~PCRERegex()
{
pcre_free(regex);
}
- virtual bool Matches(const std::string& text)
+ bool Matches(const std::string& text) CXX11_OVERRIDE
{
- if (pcre_exec(regex, NULL, text.c_str(), text.length(), 0, 0, NULL, 0) > -1)
- {
- // Bang. :D
- return true;
- }
- return false;
+ return (pcre_exec(regex, NULL, text.c_str(), text.length(), 0, 0, NULL, 0) >= 0);
}
};
@@ -78,7 +61,7 @@ class PCREFactory : public RegexFactory
{
public:
PCREFactory(Module* m) : RegexFactory(m, "regex/pcre") {}
- Regex* Create(const std::string& expr)
+ Regex* Create(const std::string& expr) CXX11_OVERRIDE
{
return new PCRERegex(expr);
}
@@ -86,13 +69,13 @@ class PCREFactory : public RegexFactory
class ModuleRegexPCRE : public Module
{
-public:
+ public:
PCREFactory ref;
- ModuleRegexPCRE() : ref(this) {
- ServerInstance->Modules->AddService(ref);
+ ModuleRegexPCRE() : ref(this)
+ {
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Regex Provider Module for PCRE", VF_VENDOR);
}
diff --git a/src/modules/extra/m_regex_posix.cpp b/src/modules/extra/m_regex_posix.cpp
index b3afd60c8..b5fddfab8 100644
--- a/src/modules/extra/m_regex_posix.cpp
+++ b/src/modules/extra/m_regex_posix.cpp
@@ -19,28 +19,15 @@
#include "inspircd.h"
-#include "m_regex.h"
+#include "modules/regex.h"
#include <sys/types.h>
#include <regex.h>
-/* $ModDesc: Regex Provider Module for POSIX Regular Expressions */
-/* $ModDep: m_regex.h */
-
-class POSIXRegexException : public ModuleException
-{
-public:
- POSIXRegexException(const std::string& rx, const std::string& error)
- : ModuleException("Error in regex " + rx + ": " + error)
- {
- }
-};
-
class POSIXRegex : public Regex
{
-private:
regex_t regbuf;
-public:
+ public:
POSIXRegex(const std::string& rx, bool extended) : Regex(rx)
{
int flags = (extended ? REG_EXTENDED : 0) | REG_NOSUB;
@@ -58,23 +45,18 @@ public:
error = errbuf;
delete[] errbuf;
regfree(&regbuf);
- throw POSIXRegexException(rx, error);
+ throw RegexException(rx, error);
}
}
- virtual ~POSIXRegex()
+ ~POSIXRegex()
{
regfree(&regbuf);
}
- virtual bool Matches(const std::string& text)
+ bool Matches(const std::string& text) CXX11_OVERRIDE
{
- if (regexec(&regbuf, text.c_str(), 0, NULL, 0) == 0)
- {
- // Bang. :D
- return true;
- }
- return false;
+ return (regexec(&regbuf, text.c_str(), 0, NULL, 0) == 0);
}
};
@@ -83,7 +65,7 @@ class PosixFactory : public RegexFactory
public:
bool extended;
PosixFactory(Module* m) : RegexFactory(m, "regex/posix") {}
- Regex* Create(const std::string& expr)
+ Regex* Create(const std::string& expr) CXX11_OVERRIDE
{
return new POSIXRegex(expr, extended);
}
@@ -92,20 +74,18 @@ class PosixFactory : public RegexFactory
class ModuleRegexPOSIX : public Module
{
PosixFactory ref;
-public:
- ModuleRegexPOSIX() : ref(this) {
- ServerInstance->Modules->AddService(ref);
- Implementation eventlist[] = { I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- OnRehash(NULL);
+
+ public:
+ ModuleRegexPOSIX() : ref(this)
+ {
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Regex Provider Module for POSIX Regular Expressions", VF_VENDOR);
}
- void OnRehash(User* u)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ref.extended = ServerInstance->Config->ConfValue("posix")->getBool("extended");
}
diff --git a/src/modules/extra/m_regex_re2.cpp b/src/modules/extra/m_regex_re2.cpp
new file mode 100644
index 000000000..c4657bf8b
--- /dev/null
+++ b/src/modules/extra/m_regex_re2.cpp
@@ -0,0 +1,81 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2013 Peter Powell <petpow@saberuk.com>
+ * Copyright (C) 2012 ChrisTX <chris@rev-crew.info>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "modules/regex.h"
+
+// Fix warnings about the use of `long long` on C++03 and
+// shadowing on GCC.
+#if defined __clang__
+# pragma clang diagnostic ignored "-Wc++11-long-long"
+#elif defined __GNUC__
+# pragma GCC diagnostic ignored "-Wlong-long"
+# pragma GCC diagnostic ignored "-Wshadow"
+#endif
+
+#include <re2/re2.h>
+
+/* $LinkerFlags: -lre2 */
+
+class RE2Regex : public Regex
+{
+ RE2 regexcl;
+
+ public:
+ RE2Regex(const std::string& rx) : Regex(rx), regexcl(rx, RE2::Quiet)
+ {
+ if (!regexcl.ok())
+ {
+ throw RegexException(rx, regexcl.error());
+ }
+ }
+
+ bool Matches(const std::string& text) CXX11_OVERRIDE
+ {
+ return RE2::FullMatch(text, regexcl);
+ }
+};
+
+class RE2Factory : public RegexFactory
+{
+ public:
+ RE2Factory(Module* m) : RegexFactory(m, "regex/re2") { }
+ Regex* Create(const std::string& expr) CXX11_OVERRIDE
+ {
+ return new RE2Regex(expr);
+ }
+};
+
+class ModuleRegexRE2 : public Module
+{
+ RE2Factory ref;
+
+ public:
+ ModuleRegexRE2() : ref(this)
+ {
+ }
+
+ Version GetVersion() CXX11_OVERRIDE
+ {
+ return Version("Regex Provider Module for RE2", VF_VENDOR);
+ }
+};
+
+MODULE_INIT(ModuleRegexRE2)
diff --git a/src/modules/extra/m_regex_stdlib.cpp b/src/modules/extra/m_regex_stdlib.cpp
index 204728b65..8e7bd0da2 100644
--- a/src/modules/extra/m_regex_stdlib.cpp
+++ b/src/modules/extra/m_regex_stdlib.cpp
@@ -15,32 +15,18 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
+
#include "inspircd.h"
-#include "m_regex.h"
+#include "modules/regex.h"
#include <regex>
-/* $ModDesc: Regex Provider Module for std::regex Regular Expressions */
-/* $ModConfig: <stdregex type="ecmascript">
- * Specify the Regular Expression engine to use here. Valid settings are
- * bre, ere, awk, grep, egrep, ecmascript (default if not specified)*/
/* $CompileFlags: -std=c++11 */
-/* $ModDep: m_regex.h */
-
-class StdRegexException : public ModuleException
-{
-public:
- StdRegexException(const std::string& rx, const std::string& error)
- : ModuleException(std::string("Error in regex ") + rx + ": " + error)
- {
- }
-};
class StdRegex : public Regex
{
-private:
std::regex regexcl;
-public:
+
+ public:
StdRegex(const std::string& rx, std::regex::flag_type fltype) : Regex(rx)
{
try{
@@ -48,11 +34,11 @@ public:
}
catch(std::regex_error rxerr)
{
- throw StdRegexException(rx, rxerr.what());
+ throw RegexException(rx, rxerr.what());
}
}
-
- virtual bool Matches(const std::string& text)
+
+ bool Matches(const std::string& text) CXX11_OVERRIDE
{
return std::regex_search(text, regexcl);
}
@@ -63,7 +49,7 @@ class StdRegexFactory : public RegexFactory
public:
std::regex::flag_type regextype;
StdRegexFactory(Module* m) : RegexFactory(m, "regex/stdregex") {}
- Regex* Create(const std::string& expr)
+ Regex* Create(const std::string& expr) CXX11_OVERRIDE
{
return new StdRegex(expr, regextype);
}
@@ -73,23 +59,20 @@ class ModuleRegexStd : public Module
{
public:
StdRegexFactory ref;
- ModuleRegexStd() : ref(this) {
- ServerInstance->Modules->AddService(ref);
- Implementation eventlist[] = { I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- OnRehash(NULL);
+ ModuleRegexStd() : ref(this)
+ {
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Regex Provider Module for std::regex", VF_VENDOR);
}
-
- void OnRehash(User* u)
+
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ConfigTag* Conf = ServerInstance->Config->ConfValue("stdregex");
std::string regextype = Conf->getString("type", "ecmascript");
-
+
if(regextype == "bre")
ref.regextype = std::regex::basic;
else if(regextype == "ere")
diff --git a/src/modules/extra/m_regex_tre.cpp b/src/modules/extra/m_regex_tre.cpp
index 4b9eab472..8a1d54248 100644
--- a/src/modules/extra/m_regex_tre.cpp
+++ b/src/modules/extra/m_regex_tre.cpp
@@ -19,27 +19,15 @@
#include "inspircd.h"
-#include "m_regex.h"
+#include "modules/regex.h"
#include <sys/types.h>
#include <tre/regex.h>
-/* $ModDesc: Regex Provider Module for TRE Regular Expressions */
/* $CompileFlags: pkgconfincludes("tre","tre/regex.h","") */
/* $LinkerFlags: pkgconflibs("tre","/libtre.so","-ltre") rpath("pkg-config --libs tre") */
-/* $ModDep: m_regex.h */
-
-class TRERegexException : public ModuleException
-{
-public:
- TRERegexException(const std::string& rx, const std::string& error)
- : ModuleException("Error in regex " + rx + ": " + error)
- {
- }
-};
class TRERegex : public Regex
{
-private:
regex_t regbuf;
public:
@@ -60,30 +48,26 @@ public:
error = errbuf;
delete[] errbuf;
regfree(&regbuf);
- throw TRERegexException(rx, error);
+ throw RegexException(rx, error);
}
}
- virtual ~TRERegex()
+ ~TRERegex()
{
regfree(&regbuf);
}
- virtual bool Matches(const std::string& text)
+ bool Matches(const std::string& text) CXX11_OVERRIDE
{
- if (regexec(&regbuf, text.c_str(), 0, NULL, 0) == 0)
- {
- // Bang. :D
- return true;
- }
- return false;
+ return (regexec(&regbuf, text.c_str(), 0, NULL, 0) == 0);
}
};
-class TREFactory : public RegexFactory {
+class TREFactory : public RegexFactory
+{
public:
TREFactory(Module* m) : RegexFactory(m, "regex/tre") {}
- Regex* Create(const std::string& expr)
+ Regex* Create(const std::string& expr) CXX11_OVERRIDE
{
return new TRERegex(expr);
}
@@ -92,18 +76,15 @@ class TREFactory : public RegexFactory {
class ModuleRegexTRE : public Module
{
TREFactory trf;
-public:
- ModuleRegexTRE() : trf(this) {
- ServerInstance->Modules->AddService(trf);
- }
- Version GetVersion()
+ public:
+ ModuleRegexTRE() : trf(this)
{
- return Version("Regex Provider Module for TRE Regular Expressions", VF_VENDOR);
}
- ~ModuleRegexTRE()
+ Version GetVersion() CXX11_OVERRIDE
{
+ return Version("Regex Provider Module for TRE Regular Expressions", VF_VENDOR);
}
};
diff --git a/src/modules/extra/m_sqlite3.cpp b/src/modules/extra/m_sqlite3.cpp
index 7f6a53359..f86e08fb3 100644
--- a/src/modules/extra/m_sqlite3.cpp
+++ b/src/modules/extra/m_sqlite3.cpp
@@ -21,17 +21,23 @@
#include "inspircd.h"
+#include "modules/sql.h"
+
+// Fix warnings about the use of `long long` on C++03.
+#if defined __clang__
+# pragma clang diagnostic ignored "-Wc++11-long-long"
+#elif defined __GNUC__
+# pragma GCC diagnostic ignored "-Wlong-long"
+#endif
+
#include <sqlite3.h>
-#include "sql.h"
#ifdef _WIN32
# pragma comment(lib, "sqlite3.lib")
#endif
-/* $ModDesc: sqlite3 provider */
/* $CompileFlags: pkgconfversion("sqlite3","3.3") pkgconfincludes("sqlite3","/sqlite3.h","") */
/* $LinkerFlags: pkgconflibs("sqlite3","/libsqlite3.so","-lsqlite3") */
-/* $NoPedantic */
class SQLConn;
typedef std::map<std::string, SQLConn*> ConnMap;
@@ -48,16 +54,12 @@ class SQLite3Result : public SQLResult
{
}
- ~SQLite3Result()
- {
- }
-
- virtual int Rows()
+ int Rows()
{
return rows;
}
- virtual bool GetRow(SQLEntries& result)
+ bool GetRow(SQLEntries& result)
{
if (currentrow < rows)
{
@@ -72,7 +74,7 @@ class SQLite3Result : public SQLResult
}
}
- virtual void GetCols(std::vector<std::string>& result)
+ void GetCols(std::vector<std::string>& result)
{
result.assign(columns.begin(), columns.end());
}
@@ -80,7 +82,6 @@ class SQLite3Result : public SQLResult
class SQLConn : public SQLProvider
{
- private:
sqlite3* conn;
reference<ConfigTag> config;
@@ -90,7 +91,7 @@ class SQLConn : public SQLProvider
std::string host = tag->getString("hostname");
if (sqlite3_open_v2(host.c_str(), &conn, SQLITE_OPEN_READWRITE, 0) != SQLITE_OK)
{
- ServerInstance->Logs->Log("m_sqlite3",DEFAULT, "WARNING: Could not open DB with id: " + tag->getString("id"));
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "WARNING: Could not open DB with id: " + tag->getString("id"));
conn = NULL;
}
}
@@ -149,13 +150,13 @@ class SQLConn : public SQLProvider
sqlite3_finalize(stmt);
}
- virtual void submit(SQLQuery* query, const std::string& q)
+ void submit(SQLQuery* query, const std::string& q)
{
Query(query, q);
delete query;
}
- virtual void submit(SQLQuery* query, const std::string& q, const ParamL& p)
+ void submit(SQLQuery* query, const std::string& q, const ParamL& p)
{
std::string res;
unsigned int param = 0;
@@ -176,7 +177,7 @@ class SQLConn : public SQLProvider
submit(query, res);
}
- virtual void submit(SQLQuery* query, const std::string& q, const ParamM& p)
+ void submit(SQLQuery* query, const std::string& q, const ParamM& p)
{
std::string res;
for(std::string::size_type i = 0; i < q.length(); i++)
@@ -206,23 +207,10 @@ class SQLConn : public SQLProvider
class ModuleSQLite3 : public Module
{
- private:
ConnMap conns;
public:
- ModuleSQLite3()
- {
- }
-
- void init()
- {
- ReadConf();
-
- Implementation eventlist[] = { I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- virtual ~ModuleSQLite3()
+ ~ModuleSQLite3()
{
ClearConns();
}
@@ -238,7 +226,7 @@ class ModuleSQLite3 : public Module
conns.clear();
}
- void ReadConf()
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ClearConns();
ConfigTagList tags = ServerInstance->Config->ConfTags("database");
@@ -252,12 +240,7 @@ class ModuleSQLite3 : public Module
}
}
- void OnRehash(User* user)
- {
- ReadConf();
- }
-
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("sqlite3 provider", VF_VENDOR);
}
diff --git a/src/modules/extra/m_ssl_gnutls.cpp b/src/modules/extra/m_ssl_gnutls.cpp
index 6a6a7923a..e6efb9771 100644
--- a/src/modules/extra/m_ssl_gnutls.cpp
+++ b/src/modules/extra/m_ssl_gnutls.cpp
@@ -22,22 +22,36 @@
#include "inspircd.h"
-#ifndef _WIN32
-#include <gcrypt.h>
+#include "modules/ssl.h"
+#include <memory>
+
+// Fix warnings about the use of commas at end of enumerator lists on C++03.
+#if defined __clang__
+# pragma clang diagnostic ignored "-Wc++11-extensions"
+#elif defined __GNUC__
+# pragma GCC diagnostic ignored "-pedantic"
#endif
+
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
-#include "ssl.h"
-#include "m_cap.h"
+
+#if ((GNUTLS_VERSION_MAJOR > 2) || (GNUTLS_VERSION_MAJOR == 2 && GNUTLS_VERSION_MINOR > 9) || (GNUTLS_VERSION_MAJOR == 2 && GNUTLS_VERSION_MINOR == 9 && GNUTLS_VERSION_PATCH >= 8))
+#define GNUTLS_HAS_MAC_GET_ID
+#include <gnutls/crypto.h>
+#endif
+
+#if (GNUTLS_VERSION_MAJOR > 2 || GNUTLS_VERSION_MAJOR == 2 && GNUTLS_VERSION_MINOR > 12)
+# define GNUTLS_HAS_RND
+#else
+# include <gcrypt.h>
+#endif
#ifdef _WIN32
# pragma comment(lib, "libgnutls-28.lib")
#endif
-/* $ModDesc: Provides SSL support for clients */
-/* $CompileFlags: pkgconfincludes("gnutls","/gnutls/gnutls.h","") exec("libgcrypt-config --cflags") */
-/* $LinkerFlags: rpath("pkg-config --libs gnutls") pkgconflibs("gnutls","/libgnutls.so","-lgnutls") exec("libgcrypt-config --libs") */
-/* $NoPedantic */
+/* $CompileFlags: pkgconfincludes("gnutls","/gnutls/gnutls.h","") eval("print `libgcrypt-config --cflags | tr -d \r` if `pkg-config --modversion gnutls 2>/dev/null | tr -d \r` lt '2.12'") */
+/* $LinkerFlags: rpath("pkg-config --libs gnutls") pkgconflibs("gnutls","/libgnutls.so","-lgnutls") eval("print `libgcrypt-config --libs | tr -d \r` if `pkg-config --modversion gnutls 2>/dev/null | tr -d \r` lt '2.12'") */
#ifndef GNUTLS_VERSION_MAJOR
#define GNUTLS_VERSION_MAJOR LIBGNUTLS_VERSION_MAJOR
@@ -55,40 +69,18 @@ typedef gnutls_certificate_credentials_t gnutls_certificate_credentials;
typedef gnutls_dh_params_t gnutls_dh_params;
#endif
-#if (defined(_WIN32) && (GNUTLS_VERSION_MAJOR > 2 || (GNUTLS_VERSION_MAJOR == 2 && GNUTLS_VERSION_MINOR >= 12)))
-# define GNUTLS_HAS_RND
-# include <gnutls/crypto.h>
-#else
-# include <gcrypt.h>
-#endif
-
enum issl_status { ISSL_NONE, ISSL_HANDSHAKING_READ, ISSL_HANDSHAKING_WRITE, ISSL_HANDSHAKEN, ISSL_CLOSING, ISSL_CLOSED };
-static std::vector<gnutls_x509_crt_t> x509_certs;
-static gnutls_x509_privkey_t x509_key;
-#if(GNUTLS_VERSION_MAJOR < 2 || ( GNUTLS_VERSION_MAJOR == 2 && GNUTLS_VERSION_MINOR < 12 ) )
-static int cert_callback (gnutls_session_t session, const gnutls_datum_t * req_ca_rdn, int nreqs,
- const gnutls_pk_algorithm_t * sign_algos, int sign_algos_length, gnutls_retr_st * st) {
-
- st->type = GNUTLS_CRT_X509;
+#if (GNUTLS_VERSION_MAJOR > 2 || (GNUTLS_VERSION_MAJOR == 2 && GNUTLS_VERSION_MINOR >= 12))
+#define GNUTLS_NEW_CERT_CALLBACK_API
+typedef gnutls_retr2_st cert_cb_last_param_type;
#else
-static int cert_callback (gnutls_session_t session, const gnutls_datum_t * req_ca_rdn, int nreqs,
- const gnutls_pk_algorithm_t * sign_algos, int sign_algos_length, gnutls_retr2_st * st) {
- st->cert_type = GNUTLS_CRT_X509;
- st->key_type = GNUTLS_PRIVKEY_X509;
+typedef gnutls_retr_st cert_cb_last_param_type;
#endif
- st->ncerts = x509_certs.size();
- st->cert.x509 = &x509_certs[0];
- st->key.x509 = x509_key;
- st->deinit_all = 0;
-
- return 0;
-}
class RandGen : public HandlerBase2<void, char*, size_t>
{
public:
- RandGen() {}
void Call(char* buffer, size_t len)
{
#ifdef GNUTLS_HAS_RND
@@ -99,557 +91,761 @@ class RandGen : public HandlerBase2<void, char*, size_t>
}
};
-/** Represents an SSL user's extra data
- */
-class issl_session
+namespace GnuTLS
{
-public:
- StreamSocket* socket;
- gnutls_session_t sess;
- issl_status status;
- reference<ssl_cert> cert;
-
- issl_session() : socket(NULL), sess(NULL) {}
-};
-
-class CommandStartTLS : public SplitCommand
-{
- public:
- bool enabled;
- CommandStartTLS (Module* mod) : SplitCommand(mod, "STARTTLS")
+ class Init
{
- enabled = true;
- works_before_reg = true;
- }
+ public:
+ Init() { gnutls_global_init(); }
+ ~Init() { gnutls_global_deinit(); }
+ };
- CmdResult HandleLocal(const std::vector<std::string> &parameters, LocalUser *user)
+ class Exception : public ModuleException
{
- if (!enabled)
- {
- user->WriteNumeric(691, "%s :STARTTLS is not enabled", user->nick.c_str());
- return CMD_FAILURE;
- }
+ public:
+ Exception(const std::string& reason)
+ : ModuleException(reason) { }
+ };
- if (user->registered == REG_ALL)
- {
- user->WriteNumeric(691, "%s :STARTTLS is not permitted after client registration is complete", user->nick.c_str());
- }
- else
+ void ThrowOnError(int errcode, const char* msg)
+ {
+ if (errcode < 0)
{
- if (!user->eh.GetIOHook())
- {
- user->WriteNumeric(670, "%s :STARTTLS successful, go ahead with TLS handshake", user->nick.c_str());
- /* We need to flush the write buffer prior to adding the IOHook,
- * otherwise we'll be sending this line inside the SSL session - which
- * won't start its handshake until the client gets this line. Currently,
- * we assume the write will not block here; this is usually safe, as
- * STARTTLS is sent very early on in the registration phase, where the
- * user hasn't built up much sendq. Handling a blocked write here would
- * be very annoying.
- */
- user->eh.DoWrite();
- user->eh.AddIOHook(creator);
- creator->OnStreamSocketAccept(&user->eh, NULL, NULL);
- }
- else
- user->WriteNumeric(691, "%s :STARTTLS failure", user->nick.c_str());
+ std::string reason = msg;
+ reason.append(" :").append(gnutls_strerror(errcode));
+ throw Exception(reason);
}
-
- return CMD_FAILURE;
}
-};
-class ModuleSSLGnuTLS : public Module
-{
- issl_session* sessions;
-
- gnutls_certificate_credentials_t x509_cred;
- gnutls_dh_params_t dh_params;
- gnutls_digest_algorithm_t hash;
- #ifdef GNUTLS_NEW_PRIO_API
- gnutls_priority_t priority;
- #endif
-
- std::string sslports;
- int dh_bits;
-
- bool cred_alloc;
- bool dh_alloc;
+ /** Used to create a gnutls_datum_t* from a std::string
+ */
+ class Datum
+ {
+ gnutls_datum_t datum;
- RandGen randhandler;
- CommandStartTLS starttls;
+ public:
+ Datum(const std::string& dat)
+ {
+ datum.data = (unsigned char*)dat.data();
+ datum.size = static_cast<unsigned int>(dat.length());
+ }
- GenericCap capHandler;
- ServiceProvider iohook;
+ const gnutls_datum_t* get() const { return &datum; }
+ };
- inline static const char* UnknownIfNULL(const char* str)
+ class Hash
{
- return str ? str : "UNKNOWN";
- }
+ gnutls_digest_algorithm_t hash;
- static ssize_t gnutls_pull_wrapper(gnutls_transport_ptr_t session_wrap, void* buffer, size_t size)
- {
- issl_session* session = reinterpret_cast<issl_session*>(session_wrap);
- if (session->socket->GetEventMask() & FD_READ_WILL_BLOCK)
+ public:
+ // Nothing to deallocate, constructor may throw freely
+ Hash(const std::string& hashname)
{
-#ifdef _WIN32
- gnutls_transport_set_errno(session->sess, EAGAIN);
+ // As older versions of gnutls can't do this, let's disable it where needed.
+#ifdef GNUTLS_HAS_MAC_GET_ID
+ // As gnutls_digest_algorithm_t and gnutls_mac_algorithm_t are mapped 1:1, we can do this
+ // There is no gnutls_dig_get_id() at the moment, but it may come later
+ hash = (gnutls_digest_algorithm_t)gnutls_mac_get_id(hashname.c_str());
+ if (hash == GNUTLS_DIG_UNKNOWN)
+ throw Exception("Unknown hash type " + hashname);
+
+ // Check if the user is giving us something that is a valid MAC but not digest
+ gnutls_hash_hd_t is_digest;
+ if (gnutls_hash_init(&is_digest, hash) < 0)
+ throw Exception("Unknown hash type " + hashname);
+ gnutls_hash_deinit(is_digest, NULL);
#else
- errno = EAGAIN;
+ if (hashname == "md5")
+ hash = GNUTLS_DIG_MD5;
+ else if (hashname == "sha1")
+ hash = GNUTLS_DIG_SHA1;
+ else
+ throw Exception("Unknown hash type " + hashname);
#endif
- return -1;
}
- int rv = ServerInstance->SE->Recv(session->socket, reinterpret_cast<char *>(buffer), size, 0);
+ gnutls_digest_algorithm_t get() const { return hash; }
+ };
-#ifdef _WIN32
- if (rv < 0)
+ class DHParams
+ {
+ gnutls_dh_params_t dh_params;
+
+ DHParams()
{
- /* Windows doesn't use errno, but gnutls does, so check SocketEngine::IgnoreError()
- * and then set errno appropriately.
- * The gnutls library may also have a different errno variable than us, see
- * gnutls_transport_set_errno(3).
- */
- gnutls_transport_set_errno(session->sess, SocketEngine::IgnoreError() ? EAGAIN : errno);
+ ThrowOnError(gnutls_dh_params_init(&dh_params), "gnutls_dh_params_init() failed");
}
-#endif
- if (rv < (int)size)
- ServerInstance->SE->ChangeEventMask(session->socket, FD_READ_WILL_BLOCK);
- return rv;
- }
-
- static ssize_t gnutls_push_wrapper(gnutls_transport_ptr_t session_wrap, const void* buffer, size_t size)
- {
- issl_session* session = reinterpret_cast<issl_session*>(session_wrap);
- if (session->socket->GetEventMask() & FD_WRITE_WILL_BLOCK)
+ public:
+ /** Import */
+ static std::auto_ptr<DHParams> Import(const std::string& dhstr)
{
-#ifdef _WIN32
- gnutls_transport_set_errno(session->sess, EAGAIN);
-#else
- errno = EAGAIN;
-#endif
- return -1;
+ std::auto_ptr<DHParams> dh(new DHParams);
+ int ret = gnutls_dh_params_import_pkcs3(dh->dh_params, Datum(dhstr).get(), GNUTLS_X509_FMT_PEM);
+ ThrowOnError(ret, "Unable to import DH params");
+ return dh;
}
- int rv = ServerInstance->SE->Send(session->socket, reinterpret_cast<const char *>(buffer), size, 0);
-
-#ifdef _WIN32
- if (rv < 0)
+ /** Generate */
+ static std::auto_ptr<DHParams> Generate(unsigned int bits)
{
- /* Windows doesn't use errno, but gnutls does, so check SocketEngine::IgnoreError()
- * and then set errno appropriately.
- * The gnutls library may also have a different errno variable than us, see
- * gnutls_transport_set_errno(3).
- */
- gnutls_transport_set_errno(session->sess, SocketEngine::IgnoreError() ? EAGAIN : errno);
+ std::auto_ptr<DHParams> dh(new DHParams);
+ ThrowOnError(gnutls_dh_params_generate2(dh->dh_params, bits), "Unable to generate DH params");
+ return dh;
}
-#endif
- if (rv < (int)size)
- ServerInstance->SE->ChangeEventMask(session->socket, FD_WRITE_WILL_BLOCK);
- return rv;
- }
+ ~DHParams()
+ {
+ gnutls_dh_params_deinit(dh_params);
+ }
- public:
+ const gnutls_dh_params_t& get() const { return dh_params; }
+ };
- ModuleSSLGnuTLS()
- : starttls(this), capHandler(this, "tls"), iohook(this, "ssl/gnutls", SERVICE_IOHOOK)
+ class X509Key
{
-#ifndef GNUTLS_HAS_RND
- gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
-#endif
+ /** Ensure that the key is deinited in case the constructor of X509Key throws
+ */
+ class RAIIKey
+ {
+ public:
+ gnutls_x509_privkey_t key;
- sessions = new issl_session[ServerInstance->SE->GetMaxFds()];
+ RAIIKey()
+ {
+ ThrowOnError(gnutls_x509_privkey_init(&key), "gnutls_x509_privkey_init() failed");
+ }
- gnutls_global_init(); // This must be called once in the program
- gnutls_x509_privkey_init(&x509_key);
+ ~RAIIKey()
+ {
+ gnutls_x509_privkey_deinit(key);
+ }
+ } key;
- #ifdef GNUTLS_NEW_PRIO_API
- // Init this here so it's always initialized, avoids an extra boolean
- gnutls_priority_init(&priority, "NORMAL", NULL);
- #endif
+ public:
+ /** Import */
+ X509Key(const std::string& keystr)
+ {
+ int ret = gnutls_x509_privkey_import(key.key, Datum(keystr).get(), GNUTLS_X509_FMT_PEM);
+ ThrowOnError(ret, "Unable to import private key");
+ }
- cred_alloc = false;
- dh_alloc = false;
- }
+ gnutls_x509_privkey_t& get() { return key.key; }
+ };
- void init()
+ class X509CertList
{
- // Needs the flag as it ignores a plain /rehash
- OnModuleRehash(NULL,"ssl");
+ std::vector<gnutls_x509_crt_t> certs;
- ServerInstance->GenRandom = &randhandler;
+ public:
+ /** Import */
+ X509CertList(const std::string& certstr)
+ {
+ unsigned int certcount = 3;
+ certs.resize(certcount);
+ Datum datum(certstr);
- // Void return, guess we assume success
- gnutls_certificate_set_dh_params(x509_cred, dh_params);
- Implementation eventlist[] = { I_On005Numeric, I_OnRehash, I_OnModuleRehash, I_OnUserConnect,
- I_OnEvent, I_OnHookIO };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
+ int ret = gnutls_x509_crt_list_import(raw(), &certcount, datum.get(), GNUTLS_X509_FMT_PEM, GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
+ if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
+ {
+ // the buffer wasn't big enough to hold all certs but gnutls changed certcount to the number of available certs,
+ // try again with a bigger buffer
+ certs.resize(certcount);
+ ret = gnutls_x509_crt_list_import(raw(), &certcount, datum.get(), GNUTLS_X509_FMT_PEM, GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
+ }
- ServerInstance->Modules->AddService(iohook);
- ServerInstance->Modules->AddService(starttls);
- }
+ ThrowOnError(ret, "Unable to load certificates");
- void OnRehash(User* user)
- {
- sslports.clear();
+ // Resize the vector to the actual number of certs because we rely on its size being correct
+ // when deallocating the certs
+ certs.resize(certcount);
+ }
- ConfigTag* Conf = ServerInstance->Config->ConfValue("gnutls");
- starttls.enabled = Conf->getBool("starttls", true);
+ ~X509CertList()
+ {
+ for (std::vector<gnutls_x509_crt_t>::iterator i = certs.begin(); i != certs.end(); ++i)
+ gnutls_x509_crt_deinit(*i);
+ }
+
+ gnutls_x509_crt_t* raw() { return &certs[0]; }
+ unsigned int size() const { return certs.size(); }
+ };
- if (Conf->getBool("showports", true))
+ class X509CRL : public refcountbase
+ {
+ class RAIICRL
{
- sslports = Conf->getString("advertisedports");
- if (!sslports.empty())
- return;
+ public:
+ gnutls_x509_crl_t crl;
- for (size_t i = 0; i < ServerInstance->ports.size(); i++)
+ RAIICRL()
{
- ListenSocket* port = ServerInstance->ports[i];
- if (port->bind_tag->getString("ssl") != "gnutls")
- continue;
+ ThrowOnError(gnutls_x509_crl_init(&crl), "gnutls_x509_crl_init() failed");
+ }
- const std::string& portid = port->bind_desc;
- ServerInstance->Logs->Log("m_ssl_gnutls", DEFAULT, "m_ssl_gnutls.so: Enabling SSL for port %s", portid.c_str());
+ ~RAIICRL()
+ {
+ gnutls_x509_crl_deinit(crl);
+ }
+ } crl;
- if (port->bind_tag->getString("type", "clients") == "clients" && port->bind_addr != "127.0.0.1")
- {
- /*
- * Found an SSL port for clients that is not bound to 127.0.0.1 and handled by us, display
- * the IP:port in ISUPPORT.
- *
- * We used to advertise all ports seperated by a ';' char that matched the above criteria,
- * but this resulted in too long ISUPPORT lines if there were lots of ports to be displayed.
- * To solve this by default we now only display the first IP:port found and let the user
- * configure the exact value for the 005 token, if necessary.
- */
- sslports = portid;
- break;
- }
+ public:
+ /** Import */
+ X509CRL(const std::string& crlstr)
+ {
+ int ret = gnutls_x509_crl_import(get(), Datum(crlstr).get(), GNUTLS_X509_FMT_PEM);
+ ThrowOnError(ret, "Unable to load certificate revocation list");
+ }
+
+ gnutls_x509_crl_t& get() { return crl.crl; }
+ };
+
+#ifdef GNUTLS_NEW_PRIO_API
+ class Priority
+ {
+ gnutls_priority_t priority;
+
+ public:
+ Priority(const std::string& priorities)
+ {
+ // Try to set the priorities for ciphers, kex methods etc. to the user supplied string
+ // If the user did not supply anything then the string is already set to "NORMAL"
+ const char* priocstr = priorities.c_str();
+ const char* prioerror;
+
+ int ret = gnutls_priority_init(&priority, priocstr, &prioerror);
+ if (ret < 0)
+ {
+ // gnutls did not understand the user supplied string
+ throw Exception("Unable to initialize priorities to \"" + priorities + "\": " + gnutls_strerror(ret) + " Syntax error at position " + ConvToStr((unsigned int) (prioerror - priocstr)));
}
}
- }
- void OnModuleRehash(User* user, const std::string &param)
+ ~Priority()
+ {
+ gnutls_priority_deinit(priority);
+ }
+
+ void SetupSession(gnutls_session_t sess)
+ {
+ gnutls_priority_set(sess, priority);
+ }
+ };
+#else
+ /** Dummy class, used when gnutls_priority_set() is not available
+ */
+ class Priority
{
- if(param != "ssl")
- return;
+ public:
+ Priority(const std::string& priorities)
+ {
+ if (priorities != "NORMAL")
+ throw Exception("You've set a non-default priority string, but GnuTLS lacks support for it");
+ }
- std::string keyfile;
- std::string certfile;
- std::string cafile;
- std::string crlfile;
- OnRehash(user);
-
- ConfigTag* Conf = ServerInstance->Config->ConfValue("gnutls");
-
- cafile = Conf->getString("cafile", CONFIG_PATH "/ca.pem");
- crlfile = Conf->getString("crlfile", CONFIG_PATH "/crl.pem");
- certfile = Conf->getString("certfile", CONFIG_PATH "/cert.pem");
- keyfile = Conf->getString("keyfile", CONFIG_PATH "/key.pem");
- dh_bits = Conf->getInt("dhbits");
- std::string hashname = Conf->getString("hash", "md5");
-
- // The GnuTLS manual states that the gnutls_set_default_priority()
- // call we used previously when initializing the session is the same
- // as setting the "NORMAL" priority string.
- // Thus if the setting below is not in the config we will behave exactly
- // the same as before, when the priority setting wasn't available.
- std::string priorities = Conf->getString("priority", "NORMAL");
-
- if((dh_bits != 768) && (dh_bits != 1024) && (dh_bits != 2048) && (dh_bits != 3072) && (dh_bits != 4096))
- dh_bits = 1024;
-
- if (hashname == "md5")
- hash = GNUTLS_DIG_MD5;
- else if (hashname == "sha1")
- hash = GNUTLS_DIG_SHA1;
- else
- throw ModuleException("Unknown hash type " + hashname);
+ static void SetupSession(gnutls_session_t sess)
+ {
+ // Always set the default priorities
+ gnutls_set_default_priority(sess);
+ }
+ };
+#endif
+ class CertCredentials
+ {
+ /** DH parameters associated with these credentials
+ */
+ std::auto_ptr<DHParams> dh;
- int ret;
+ protected:
+ gnutls_certificate_credentials_t cred;
- if (dh_alloc)
+ public:
+ CertCredentials()
{
- gnutls_dh_params_deinit(dh_params);
- dh_alloc = false;
- dh_params = NULL;
+ ThrowOnError(gnutls_certificate_allocate_credentials(&cred), "Cannot allocate certificate credentials");
}
- if (cred_alloc)
+ ~CertCredentials()
{
- // Deallocate the old credentials
- gnutls_certificate_free_credentials(x509_cred);
+ gnutls_certificate_free_credentials(cred);
+ }
- for(unsigned int i=0; i < x509_certs.size(); i++)
- gnutls_x509_crt_deinit(x509_certs[i]);
- x509_certs.clear();
+ /** Associates these credentials with the session
+ */
+ void SetupSession(gnutls_session_t sess)
+ {
+ gnutls_credentials_set(sess, GNUTLS_CRD_CERTIFICATE, cred);
}
- ret = gnutls_certificate_allocate_credentials(&x509_cred);
- cred_alloc = (ret >= 0);
- if (!cred_alloc)
- ServerInstance->Logs->Log("m_ssl_gnutls",DEBUG, "m_ssl_gnutls.so: Failed to allocate certificate credentials: %s", gnutls_strerror(ret));
+ /** Set the given DH parameters to be used with these credentials
+ */
+ void SetDH(std::auto_ptr<DHParams>& DH)
+ {
+ dh = DH;
+ gnutls_certificate_set_dh_params(cred, dh->get());
+ }
+ };
- if((ret =gnutls_certificate_set_x509_trust_file(x509_cred, cafile.c_str(), GNUTLS_X509_FMT_PEM)) < 0)
- ServerInstance->Logs->Log("m_ssl_gnutls",DEBUG, "m_ssl_gnutls.so: Failed to set X.509 trust file '%s': %s", cafile.c_str(), gnutls_strerror(ret));
+ class X509Credentials : public CertCredentials
+ {
+ /** Private key
+ */
+ X509Key key;
- if((ret = gnutls_certificate_set_x509_crl_file (x509_cred, crlfile.c_str(), GNUTLS_X509_FMT_PEM)) < 0)
- ServerInstance->Logs->Log("m_ssl_gnutls",DEBUG, "m_ssl_gnutls.so: Failed to set X.509 CRL file '%s': %s", crlfile.c_str(), gnutls_strerror(ret));
+ /** Certificate list, presented to the peer
+ */
+ X509CertList certs;
- FileReader reader;
+ /** Trusted CA, may be NULL
+ */
+ std::auto_ptr<X509CertList> trustedca;
- reader.LoadFile(certfile);
- std::string cert_string = reader.Contents();
- gnutls_datum_t cert_datum = { (unsigned char*)cert_string.data(), static_cast<unsigned int>(cert_string.length()) };
+ /** Certificate revocation list, may be NULL
+ */
+ std::auto_ptr<X509CRL> crl;
- reader.LoadFile(keyfile);
- std::string key_string = reader.Contents();
- gnutls_datum_t key_datum = { (unsigned char*)key_string.data(), static_cast<unsigned int>(key_string.length()) };
+ static int cert_callback(gnutls_session_t session, const gnutls_datum_t* req_ca_rdn, int nreqs, const gnutls_pk_algorithm_t* sign_algos, int sign_algos_length, cert_cb_last_param_type* st);
- // If this fails, no SSL port will work. At all. So, do the smart thing - throw a ModuleException
- unsigned int certcount = 3;
- x509_certs.resize(certcount);
- ret = gnutls_x509_crt_list_import(&x509_certs[0], &certcount, &cert_datum, GNUTLS_X509_FMT_PEM, GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
- if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
+ public:
+ X509Credentials(const std::string& certstr, const std::string& keystr)
+ : key(keystr)
+ , certs(certstr)
{
- // the buffer wasn't big enough to hold all certs but gnutls updated certcount to the number of available certs, try again with a bigger buffer
- x509_certs.resize(certcount);
- ret = gnutls_x509_crt_list_import(&x509_certs[0], &certcount, &cert_datum, GNUTLS_X509_FMT_PEM, GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
+ // Throwing is ok here, the destructor of Credentials is called in that case
+ int ret = gnutls_certificate_set_x509_key(cred, certs.raw(), certs.size(), key.get());
+ ThrowOnError(ret, "Unable to set cert/key pair");
+
+#ifdef GNUTLS_NEW_CERT_CALLBACK_API
+ gnutls_certificate_set_retrieve_function(cred, cert_callback);
+#else
+ gnutls_certificate_client_set_retrieve_function(cred, cert_callback);
+#endif
}
- if (ret <= 0)
+ /** Sets the trusted CA and the certificate revocation list
+ * to use when verifying certificates
+ */
+ void SetCA(std::auto_ptr<X509CertList>& certlist, std::auto_ptr<X509CRL>& CRL)
{
- // clear the vector so we won't call gnutls_x509_crt_deinit() on the (uninited) certs later
- x509_certs.clear();
- throw ModuleException("Unable to load GnuTLS server certificate (" + certfile + "): " + ((ret < 0) ? (std::string(gnutls_strerror(ret))) : "No certs could be read"));
+ // Do nothing if certlist is NULL
+ if (certlist.get())
+ {
+ int ret = gnutls_certificate_set_x509_trust(cred, certlist->raw(), certlist->size());
+ ThrowOnError(ret, "gnutls_certificate_set_x509_trust() failed");
+
+ if (CRL.get())
+ {
+ ret = gnutls_certificate_set_x509_crl(cred, &CRL->get(), 1);
+ ThrowOnError(ret, "gnutls_certificate_set_x509_crl() failed");
+ }
+
+ trustedca = certlist;
+ crl = CRL;
+ }
}
- x509_certs.resize(ret);
+ };
- if((ret = gnutls_x509_privkey_import(x509_key, &key_datum, GNUTLS_X509_FMT_PEM)) < 0)
- throw ModuleException("Unable to load GnuTLS server private key (" + keyfile + "): " + std::string(gnutls_strerror(ret)));
+ class Profile : public refcountbase
+ {
+ /** Name of this profile
+ */
+ const std::string name;
- if((ret = gnutls_certificate_set_x509_key(x509_cred, &x509_certs[0], certcount, x509_key)) < 0)
- throw ModuleException("Unable to set GnuTLS cert/key pair: " + std::string(gnutls_strerror(ret)));
+ /** X509 certificate(s) and key
+ */
+ X509Credentials x509cred;
- #ifdef GNUTLS_NEW_PRIO_API
- // It's safe to call this every time as we cannot have this uninitialized, see constructor and below.
- gnutls_priority_deinit(priority);
+ /** The minimum length in bits for the DH prime to be accepted as a client
+ */
+ unsigned int min_dh_bits;
- // Try to set the priorities for ciphers, kex methods etc. to the user supplied string
- // If the user did not supply anything then the string is already set to "NORMAL"
- const char* priocstr = priorities.c_str();
- const char* prioerror;
+ /** Hashing algorithm to use when generating certificate fingerprints
+ */
+ Hash hash;
- if ((ret = gnutls_priority_init(&priority, priocstr, &prioerror)) < 0)
+ /** Priorities for ciphers, compression methods, etc.
+ */
+ Priority priority;
+
+ Profile(const std::string& profilename, const std::string& certstr, const std::string& keystr,
+ std::auto_ptr<DHParams>& DH, unsigned int mindh, const std::string& hashstr,
+ const std::string& priostr, std::auto_ptr<X509CertList>& CA, std::auto_ptr<X509CRL>& CRL)
+ : name(profilename)
+ , x509cred(certstr, keystr)
+ , min_dh_bits(mindh)
+ , hash(hashstr)
+ , priority(priostr)
{
- // gnutls did not understand the user supplied string, log and fall back to the default priorities
- ServerInstance->Logs->Log("m_ssl_gnutls",DEFAULT, "m_ssl_gnutls.so: Failed to set priorities to \"%s\": %s Syntax error at position %u, falling back to default (NORMAL)", priorities.c_str(), gnutls_strerror(ret), (unsigned int) (prioerror - priocstr));
- gnutls_priority_init(&priority, "NORMAL", NULL);
+ x509cred.SetDH(DH);
+ x509cred.SetCA(CA, CRL);
}
- #else
- if (priorities != "NORMAL")
- ServerInstance->Logs->Log("m_ssl_gnutls",DEFAULT, "m_ssl_gnutls.so: You've set <gnutls:priority> to a value other than the default, but this is only supported with GnuTLS v2.1.7 or newer. Your GnuTLS version is older than that so the option will have no effect.");
- #endif
-
- #if(GNUTLS_VERSION_MAJOR < 2 || ( GNUTLS_VERSION_MAJOR == 2 && GNUTLS_VERSION_MINOR < 12 ) )
- gnutls_certificate_client_set_retrieve_function (x509_cred, cert_callback);
- #else
- gnutls_certificate_set_retrieve_function (x509_cred, cert_callback);
- #endif
- ret = gnutls_dh_params_init(&dh_params);
- dh_alloc = (ret >= 0);
- if (!dh_alloc)
+ static std::string ReadFile(const std::string& filename)
{
- ServerInstance->Logs->Log("m_ssl_gnutls",DEFAULT, "m_ssl_gnutls.so: Failed to initialise DH parameters: %s", gnutls_strerror(ret));
- return;
+ FileReader reader(filename);
+ std::string ret = reader.GetString();
+ if (ret.empty())
+ throw Exception("Cannot read file " + filename);
+ return ret;
}
- std::string dhfile = Conf->getString("dhfile");
- if (!dhfile.empty())
+ public:
+ static reference<Profile> Create(const std::string& profilename, ConfigTag* tag)
{
- // Try to load DH params from file
- reader.LoadFile(dhfile);
- std::string dhstring = reader.Contents();
- gnutls_datum_t dh_datum = { (unsigned char*)dhstring.data(), static_cast<unsigned int>(dhstring.length()) };
+ std::string certstr = ReadFile(tag->getString("certfile", "cert.pem"));
+ std::string keystr = ReadFile(tag->getString("keyfile", "key.pem"));
- if ((ret = gnutls_dh_params_import_pkcs3(dh_params, &dh_datum, GNUTLS_X509_FMT_PEM)) < 0)
+ std::auto_ptr<DHParams> dh;
+ int gendh = tag->getInt("gendh");
+ if (gendh)
+ {
+ gendh = (gendh < 1024 ? 1024 : gendh);
+ dh = DHParams::Generate(gendh);
+ }
+ else
+ dh = DHParams::Import(ReadFile(tag->getString("dhfile", "dhparams.pem")));
+
+ // Use default priority string if this tag does not specify one
+ std::string priostr = tag->getString("priority", "NORMAL");
+ unsigned int mindh = tag->getInt("mindhbits", 1024);
+ std::string hashstr = tag->getString("hash", "md5");
+
+ // Load trusted CA and revocation list, if set
+ std::auto_ptr<X509CertList> ca;
+ std::auto_ptr<X509CRL> crl;
+ std::string filename = tag->getString("cafile");
+ if (!filename.empty())
{
- // File unreadable or GnuTLS was unhappy with the contents, generate the DH primes now
- ServerInstance->Logs->Log("m_ssl_gnutls", DEFAULT, "m_ssl_gnutls.so: Generating DH parameters because I failed to load them from file '%s': %s", dhfile.c_str(), gnutls_strerror(ret));
- GenerateDHParams();
+ ca.reset(new X509CertList(ReadFile(filename)));
+
+ filename = tag->getString("crlfile");
+ if (!filename.empty())
+ crl.reset(new X509CRL(ReadFile(filename)));
}
+
+ return new Profile(profilename, certstr, keystr, dh, mindh, hashstr, priostr, ca, crl);
}
- else
+
+ /** Set up the given session with the settings in this profile
+ */
+ void SetupSession(gnutls_session_t sess)
{
- GenerateDHParams();
+ priority.SetupSession(sess);
+ x509cred.SetupSession(sess);
+ gnutls_dh_set_prime_bits(sess, min_dh_bits);
}
- }
-
- void GenerateDHParams()
- {
- // Generate Diffie Hellman parameters - for use with DHE
- // kx algorithms. These should be discarded and regenerated
- // once a day, once a week or once a month. Depending on the
- // security requirements.
- if (!dh_alloc)
- return;
-
- int ret;
+ const std::string& GetName() const { return name; }
+ X509Credentials& GetX509Credentials() { return x509cred; }
+ gnutls_digest_algorithm_t GetHash() const { return hash.get(); }
+ };
+}
- if((ret = gnutls_dh_params_generate2(dh_params, dh_bits)) < 0)
- ServerInstance->Logs->Log("m_ssl_gnutls",DEFAULT, "m_ssl_gnutls.so: Failed to generate DH parameters (%d bits): %s", dh_bits, gnutls_strerror(ret));
- }
+class GnuTLSIOHook : public SSLIOHook
+{
+ private:
+ gnutls_session_t sess;
+ issl_status status;
+ reference<GnuTLS::Profile> profile;
- ~ModuleSSLGnuTLS()
+ void InitSession(StreamSocket* user, bool me_server)
{
- for(unsigned int i=0; i < x509_certs.size(); i++)
- gnutls_x509_crt_deinit(x509_certs[i]);
+ gnutls_init(&sess, me_server ? GNUTLS_SERVER : GNUTLS_CLIENT);
- gnutls_x509_privkey_deinit(x509_key);
- #ifdef GNUTLS_NEW_PRIO_API
- gnutls_priority_deinit(priority);
- #endif
+ profile->SetupSession(sess);
+ gnutls_transport_set_ptr(sess, reinterpret_cast<gnutls_transport_ptr_t>(user));
+ gnutls_transport_set_push_function(sess, gnutls_push_wrapper);
+ gnutls_transport_set_pull_function(sess, gnutls_pull_wrapper);
- if (dh_alloc)
- gnutls_dh_params_deinit(dh_params);
- if (cred_alloc)
- gnutls_certificate_free_credentials(x509_cred);
+ if (me_server)
+ gnutls_certificate_server_set_request(sess, GNUTLS_CERT_REQUEST); // Request client certificate if any.
+ }
- gnutls_global_deinit();
- delete[] sessions;
- ServerInstance->GenRandom = &ServerInstance->HandleGenRandom;
+ void CloseSession()
+ {
+ if (this->sess)
+ {
+ gnutls_bye(this->sess, GNUTLS_SHUT_WR);
+ gnutls_deinit(this->sess);
+ }
+ sess = NULL;
+ certificate = NULL;
+ status = ISSL_NONE;
}
- void OnCleanup(int target_type, void* item)
+ bool Handshake(StreamSocket* user)
{
- if(target_type == TYPE_USER)
+ int ret = gnutls_handshake(this->sess);
+
+ if (ret < 0)
{
- LocalUser* user = IS_LOCAL(static_cast<User*>(item));
+ if(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)
+ {
+ // Handshake needs resuming later, read() or write() would have blocked.
- if (user && user->eh.GetIOHook() == this)
+ if (gnutls_record_get_direction(this->sess) == 0)
+ {
+ // gnutls_handshake() wants to read() again.
+ this->status = ISSL_HANDSHAKING_READ;
+ SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
+ }
+ else
+ {
+ // gnutls_handshake() wants to write() again.
+ this->status = ISSL_HANDSHAKING_WRITE;
+ SocketEngine::ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE);
+ }
+ }
+ else
{
- // User is using SSL, they're a local user, and they're using one of *our* SSL ports.
- // Potentially there could be multiple SSL modules loaded at once on different ports.
- ServerInstance->Users->QuitUser(user, "SSL module unloading");
+ user->SetError("Handshake Failed - " + std::string(gnutls_strerror(ret)));
+ CloseSession();
+ this->status = ISSL_CLOSING;
}
+
+ return false;
}
- }
+ else
+ {
+ // Change the seesion state
+ this->status = ISSL_HANDSHAKEN;
- Version GetVersion()
- {
- return Version("Provides SSL support for clients", VF_VENDOR);
- }
+ VerifyCertificate();
+ // Finish writing, if any left
+ SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE | FD_ADD_TRIAL_WRITE);
- void On005Numeric(std::string &output)
- {
- if (!sslports.empty())
- output.append(" SSL=" + sslports);
- if (starttls.enabled)
- output.append(" STARTTLS");
+ return true;
+ }
}
- void OnHookIO(StreamSocket* user, ListenSocket* lsb)
+ void VerifyCertificate()
{
- if (!user->GetIOHook() && lsb->bind_tag->getString("ssl") == "gnutls")
+ unsigned int certstatus;
+ const gnutls_datum_t* cert_list;
+ int ret;
+ unsigned int cert_list_size;
+ gnutls_x509_crt_t cert;
+ char str[512];
+ unsigned char digest[512];
+ size_t digest_size = sizeof(digest);
+ size_t name_size = sizeof(str);
+ ssl_cert* certinfo = new ssl_cert;
+ this->certificate = certinfo;
+
+ /* This verification function uses the trusted CAs in the credentials
+ * structure. So you must have installed one or more CA certificates.
+ */
+ ret = gnutls_certificate_verify_peers2(this->sess, &certstatus);
+
+ if (ret < 0)
{
- /* Hook the user with our module */
- user->AddIOHook(this);
+ certinfo->error = std::string(gnutls_strerror(ret));
+ return;
}
- }
- void OnRequest(Request& request)
- {
- if (strcmp("GET_SSL_CERT", request.id) == 0)
+ certinfo->invalid = (certstatus & GNUTLS_CERT_INVALID);
+ certinfo->unknownsigner = (certstatus & GNUTLS_CERT_SIGNER_NOT_FOUND);
+ certinfo->revoked = (certstatus & GNUTLS_CERT_REVOKED);
+ certinfo->trusted = !(certstatus & GNUTLS_CERT_SIGNER_NOT_CA);
+
+ /* Up to here the process is the same for X.509 certificates and
+ * OpenPGP keys. From now on X.509 certificates are assumed. This can
+ * be easily extended to work with openpgp keys as well.
+ */
+ if (gnutls_certificate_type_get(this->sess) != GNUTLS_CRT_X509)
{
- SocketCertificateRequest& req = static_cast<SocketCertificateRequest&>(request);
- int fd = req.sock->GetFd();
- issl_session* session = &sessions[fd];
+ certinfo->error = "No X509 keys sent";
+ return;
+ }
- req.cert = session->cert;
+ ret = gnutls_x509_crt_init(&cert);
+ if (ret < 0)
+ {
+ certinfo->error = gnutls_strerror(ret);
+ return;
+ }
+
+ cert_list_size = 0;
+ cert_list = gnutls_certificate_get_peers(this->sess, &cert_list_size);
+ if (cert_list == NULL)
+ {
+ certinfo->error = "No certificate was found";
+ goto info_done_dealloc;
+ }
+
+ /* This is not a real world example, since we only check the first
+ * certificate in the given chain.
+ */
+
+ ret = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
+ if (ret < 0)
+ {
+ certinfo->error = gnutls_strerror(ret);
+ goto info_done_dealloc;
+ }
+
+ if (gnutls_x509_crt_get_dn(cert, str, &name_size) == 0)
+ {
+ std::string& dn = certinfo->dn;
+ dn = str;
+ // Make sure there are no chars in the string that we consider invalid
+ if (dn.find_first_of("\r\n") != std::string::npos)
+ dn.clear();
+ }
+
+ name_size = sizeof(str);
+ if (gnutls_x509_crt_get_issuer_dn(cert, str, &name_size) == 0)
+ {
+ std::string& issuer = certinfo->issuer;
+ issuer = str;
+ if (issuer.find_first_of("\r\n") != std::string::npos)
+ issuer.clear();
}
+
+ if ((ret = gnutls_x509_crt_get_fingerprint(cert, profile->GetHash(), digest, &digest_size)) < 0)
+ {
+ certinfo->error = gnutls_strerror(ret);
+ }
+ else
+ {
+ certinfo->fingerprint = BinToHex(digest, digest_size);
+ }
+
+ /* Beware here we do not check for errors.
+ */
+ if ((gnutls_x509_crt_get_expiration_time(cert) < ServerInstance->Time()) || (gnutls_x509_crt_get_activation_time(cert) > ServerInstance->Time()))
+ {
+ certinfo->error = "Not activated, or expired certificate";
+ }
+
+info_done_dealloc:
+ gnutls_x509_crt_deinit(cert);
}
- void InitSession(StreamSocket* user, bool me_server)
+ static const char* UnknownIfNULL(const char* str)
{
- issl_session* session = &sessions[user->GetFd()];
+ return str ? str : "UNKNOWN";
+ }
- gnutls_init(&session->sess, me_server ? GNUTLS_SERVER : GNUTLS_CLIENT);
- session->socket = user;
+ static ssize_t gnutls_pull_wrapper(gnutls_transport_ptr_t session_wrap, void* buffer, size_t size)
+ {
+ StreamSocket* sock = reinterpret_cast<StreamSocket*>(session_wrap);
+#ifdef _WIN32
+ GnuTLSIOHook* session = static_cast<GnuTLSIOHook*>(sock->GetIOHook());
+#endif
- #ifdef GNUTLS_NEW_PRIO_API
- gnutls_priority_set(session->sess, priority);
- #else
- gnutls_set_default_priority(session->sess);
- #endif
- gnutls_credentials_set(session->sess, GNUTLS_CRD_CERTIFICATE, x509_cred);
- gnutls_dh_set_prime_bits(session->sess, dh_bits);
- gnutls_transport_set_ptr(session->sess, reinterpret_cast<gnutls_transport_ptr_t>(session));
- gnutls_transport_set_push_function(session->sess, gnutls_push_wrapper);
- gnutls_transport_set_pull_function(session->sess, gnutls_pull_wrapper);
+ if (sock->GetEventMask() & FD_READ_WILL_BLOCK)
+ {
+#ifdef _WIN32
+ gnutls_transport_set_errno(session->sess, EAGAIN);
+#else
+ errno = EAGAIN;
+#endif
+ return -1;
+ }
- if (me_server)
- gnutls_certificate_server_set_request(session->sess, GNUTLS_CERT_REQUEST); // Request client certificate if any.
+ int rv = SocketEngine::Recv(sock, reinterpret_cast<char *>(buffer), size, 0);
+
+#ifdef _WIN32
+ if (rv < 0)
+ {
+ /* Windows doesn't use errno, but gnutls does, so check SocketEngine::IgnoreError()
+ * and then set errno appropriately.
+ * The gnutls library may also have a different errno variable than us, see
+ * gnutls_transport_set_errno(3).
+ */
+ gnutls_transport_set_errno(session->sess, SocketEngine::IgnoreError() ? EAGAIN : errno);
+ }
+#endif
- Handshake(session, user);
+ if (rv < (int)size)
+ SocketEngine::ChangeEventMask(sock, FD_READ_WILL_BLOCK);
+ return rv;
}
- void OnStreamSocketAccept(StreamSocket* user, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server)
+ static ssize_t gnutls_push_wrapper(gnutls_transport_ptr_t session_wrap, const void* buffer, size_t size)
{
- issl_session* session = &sessions[user->GetFd()];
+ StreamSocket* sock = reinterpret_cast<StreamSocket*>(session_wrap);
+#ifdef _WIN32
+ GnuTLSIOHook* session = static_cast<GnuTLSIOHook*>(sock->GetIOHook());
+#endif
- /* For STARTTLS: Don't try and init a session on a socket that already has a session */
- if (session->sess)
- return;
+ if (sock->GetEventMask() & FD_WRITE_WILL_BLOCK)
+ {
+#ifdef _WIN32
+ gnutls_transport_set_errno(session->sess, EAGAIN);
+#else
+ errno = EAGAIN;
+#endif
+ return -1;
+ }
+
+ int rv = SocketEngine::Send(sock, reinterpret_cast<const char *>(buffer), size, 0);
+
+#ifdef _WIN32
+ if (rv < 0)
+ {
+ /* Windows doesn't use errno, but gnutls does, so check SocketEngine::IgnoreError()
+ * and then set errno appropriately.
+ * The gnutls library may also have a different errno variable than us, see
+ * gnutls_transport_set_errno(3).
+ */
+ gnutls_transport_set_errno(session->sess, SocketEngine::IgnoreError() ? EAGAIN : errno);
+ }
+#endif
- InitSession(user, true);
+ if (rv < (int)size)
+ SocketEngine::ChangeEventMask(sock, FD_WRITE_WILL_BLOCK);
+ return rv;
}
- void OnStreamSocketConnect(StreamSocket* user)
+ public:
+ GnuTLSIOHook(IOHookProvider* hookprov, StreamSocket* sock, bool outbound, const reference<GnuTLS::Profile>& sslprofile)
+ : SSLIOHook(hookprov)
+ , sess(NULL)
+ , status(ISSL_NONE)
+ , profile(sslprofile)
{
- InitSession(user, false);
+ InitSession(sock, outbound);
+ sock->AddIOHook(this);
+ Handshake(sock);
}
- void OnStreamSocketClose(StreamSocket* user)
+ void OnStreamSocketClose(StreamSocket* user) CXX11_OVERRIDE
{
- CloseSession(&sessions[user->GetFd()]);
+ CloseSession();
}
- int OnStreamSocketRead(StreamSocket* user, std::string& recvq)
+ int OnStreamSocketRead(StreamSocket* user, std::string& recvq) CXX11_OVERRIDE
{
- issl_session* session = &sessions[user->GetFd()];
-
- if (!session->sess)
+ if (!this->sess)
{
- CloseSession(session);
+ CloseSession();
user->SetError("No SSL session");
return -1;
}
- if (session->status == ISSL_HANDSHAKING_READ || session->status == ISSL_HANDSHAKING_WRITE)
+ if (this->status == ISSL_HANDSHAKING_READ || this->status == ISSL_HANDSHAKING_WRITE)
{
// The handshake isn't finished, try to finish it.
- if(!Handshake(session, user))
+ if (!Handshake(user))
{
- if (session->status != ISSL_CLOSING)
+ if (this->status != ISSL_CLOSING)
return 0;
return -1;
}
}
- // If we resumed the handshake then session->status will be ISSL_HANDSHAKEN.
+ // If we resumed the handshake then this->status will be ISSL_HANDSHAKEN.
- if (session->status == ISSL_HANDSHAKEN)
+ if (this->status == ISSL_HANDSHAKEN)
{
char* buffer = ServerInstance->GetReadBuffer();
size_t bufsiz = ServerInstance->Config->NetBufferSize;
- int ret = gnutls_record_recv(session->sess, buffer, bufsiz);
+ int ret = gnutls_record_recv(this->sess, buffer, bufsiz);
if (ret > 0)
{
recvq.append(buffer, ret);
@@ -662,68 +858,66 @@ class ModuleSSLGnuTLS : public Module
else if (ret == 0)
{
user->SetError("Connection closed");
- CloseSession(session);
+ CloseSession();
return -1;
}
else
{
user->SetError(gnutls_strerror(ret));
- CloseSession(session);
+ CloseSession();
return -1;
}
}
- else if (session->status == ISSL_CLOSING)
+ else if (this->status == ISSL_CLOSING)
return -1;
return 0;
}
- int OnStreamSocketWrite(StreamSocket* user, std::string& sendq)
+ int OnStreamSocketWrite(StreamSocket* user, std::string& sendq) CXX11_OVERRIDE
{
- issl_session* session = &sessions[user->GetFd()];
-
- if (!session->sess)
+ if (!this->sess)
{
- CloseSession(session);
+ CloseSession();
user->SetError("No SSL session");
return -1;
}
- if (session->status == ISSL_HANDSHAKING_WRITE || session->status == ISSL_HANDSHAKING_READ)
+ if (this->status == ISSL_HANDSHAKING_WRITE || this->status == ISSL_HANDSHAKING_READ)
{
// The handshake isn't finished, try to finish it.
- Handshake(session, user);
- if (session->status != ISSL_CLOSING)
+ Handshake(user);
+ if (this->status != ISSL_CLOSING)
return 0;
return -1;
}
int ret = 0;
- if (session->status == ISSL_HANDSHAKEN)
+ if (this->status == ISSL_HANDSHAKEN)
{
- ret = gnutls_record_send(session->sess, sendq.data(), sendq.length());
+ ret = gnutls_record_send(this->sess, sendq.data(), sendq.length());
if (ret == (int)sendq.length())
{
- ServerInstance->SE->ChangeEventMask(user, FD_WANT_NO_WRITE);
+ SocketEngine::ChangeEventMask(user, FD_WANT_NO_WRITE);
return 1;
}
else if (ret > 0)
{
sendq = sendq.substr(ret);
- ServerInstance->SE->ChangeEventMask(user, FD_WANT_SINGLE_WRITE);
+ SocketEngine::ChangeEventMask(user, FD_WANT_SINGLE_WRITE);
return 0;
}
else if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED || ret == 0)
{
- ServerInstance->SE->ChangeEventMask(user, FD_WANT_SINGLE_WRITE);
+ SocketEngine::ChangeEventMask(user, FD_WANT_SINGLE_WRITE);
return 0;
}
else // (ret < 0)
{
user->SetError(gnutls_strerror(ret));
- CloseSession(session);
+ CloseSession();
return -1;
}
}
@@ -731,197 +925,198 @@ class ModuleSSLGnuTLS : public Module
return 0;
}
- bool Handshake(issl_session* session, StreamSocket* user)
+ void TellCiphersAndFingerprint(LocalUser* user)
{
- int ret = gnutls_handshake(session->sess);
-
- if (ret < 0)
+ if (sess)
{
- if(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)
- {
- // Handshake needs resuming later, read() or write() would have blocked.
+ std::string text = "*** You are connected using SSL cipher '";
- if(gnutls_record_get_direction(session->sess) == 0)
- {
- // gnutls_handshake() wants to read() again.
- session->status = ISSL_HANDSHAKING_READ;
- ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
- }
- else
- {
- // gnutls_handshake() wants to write() again.
- session->status = ISSL_HANDSHAKING_WRITE;
- ServerInstance->SE->ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE);
- }
- }
- else
- {
- user->SetError("Handshake Failed - " + std::string(gnutls_strerror(ret)));
- CloseSession(session);
- session->status = ISSL_CLOSING;
- }
+ text += UnknownIfNULL(gnutls_kx_get_name(gnutls_kx_get(sess)));
+ text.append("-").append(UnknownIfNULL(gnutls_cipher_get_name(gnutls_cipher_get(sess)))).append("-");
+ text.append(UnknownIfNULL(gnutls_mac_get_name(gnutls_mac_get(sess)))).append("'");
- return false;
+ if (!certificate->fingerprint.empty())
+ text += " and your SSL certificate fingerprint is " + certificate->fingerprint;
+
+ user->WriteNotice(text);
}
- else
- {
- // Change the seesion state
- session->status = ISSL_HANDSHAKEN;
+ }
- VerifyCertificate(session,user);
+ GnuTLS::Profile* GetProfile() { return profile; }
+};
- // Finish writing, if any left
- ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE | FD_ADD_TRIAL_WRITE);
+int GnuTLS::X509Credentials::cert_callback(gnutls_session_t sess, const gnutls_datum_t* req_ca_rdn, int nreqs, const gnutls_pk_algorithm_t* sign_algos, int sign_algos_length, cert_cb_last_param_type* st)
+{
+#ifndef GNUTLS_NEW_CERT_CALLBACK_API
+ st->type = GNUTLS_CRT_X509;
+#else
+ st->cert_type = GNUTLS_CRT_X509;
+ st->key_type = GNUTLS_PRIVKEY_X509;
+#endif
+ StreamSocket* sock = reinterpret_cast<StreamSocket*>(gnutls_transport_get_ptr(sess));
+ GnuTLS::X509Credentials& cred = static_cast<GnuTLSIOHook*>(sock->GetIOHook())->GetProfile()->GetX509Credentials();
- return true;
- }
- }
+ st->ncerts = cred.certs.size();
+ st->cert.x509 = cred.certs.raw();
+ st->key.x509 = cred.key.get();
+ st->deinit_all = 0;
+
+ return 0;
+}
- void OnUserConnect(LocalUser* user)
+class GnuTLSIOHookProvider : public refcountbase, public IOHookProvider
+{
+ reference<GnuTLS::Profile> profile;
+
+ public:
+ GnuTLSIOHookProvider(Module* mod, reference<GnuTLS::Profile>& prof)
+ : IOHookProvider(mod, "ssl/" + prof->GetName(), IOHookProvider::IOH_SSL)
+ , profile(prof)
{
- if (user->eh.GetIOHook() == this)
- {
- if (sessions[user->eh.GetFd()].sess)
- {
- const gnutls_session_t& sess = sessions[user->eh.GetFd()].sess;
- std::string cipher = UnknownIfNULL(gnutls_kx_get_name(gnutls_kx_get(sess)));
- cipher.append("-").append(UnknownIfNULL(gnutls_cipher_get_name(gnutls_cipher_get(sess)))).append("-");
- cipher.append(UnknownIfNULL(gnutls_mac_get_name(gnutls_mac_get(sess))));
-
- ssl_cert* cert = sessions[user->eh.GetFd()].cert;
- if (cert->fingerprint.empty())
- user->WriteServ("NOTICE %s :*** You are connected using SSL cipher \"%s\"", user->nick.c_str(), cipher.c_str());
- else
- user->WriteServ("NOTICE %s :*** You are connected using SSL cipher \"%s\""
- " and your SSL fingerprint is %s", user->nick.c_str(), cipher.c_str(), cert->fingerprint.c_str());
- }
- }
+ ServerInstance->Modules->AddService(*this);
}
- void CloseSession(issl_session* session)
+ ~GnuTLSIOHookProvider()
{
- if (session->sess)
- {
- gnutls_bye(session->sess, GNUTLS_SHUT_WR);
- gnutls_deinit(session->sess);
- }
- session->socket = NULL;
- session->sess = NULL;
- session->cert = NULL;
- session->status = ISSL_NONE;
+ ServerInstance->Modules->DelService(*this);
}
- void VerifyCertificate(issl_session* session, StreamSocket* user)
+ void OnAccept(StreamSocket* sock, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) CXX11_OVERRIDE
{
- if (!session->sess || !user)
- return;
+ new GnuTLSIOHook(this, sock, true, profile);
+ }
- unsigned int status;
- const gnutls_datum_t* cert_list;
- int ret;
- unsigned int cert_list_size;
- gnutls_x509_crt_t cert;
- char name[MAXBUF];
- unsigned char digest[MAXBUF];
- size_t digest_size = sizeof(digest);
- size_t name_size = sizeof(name);
- ssl_cert* certinfo = new ssl_cert;
- session->cert = certinfo;
+ void OnConnect(StreamSocket* sock) CXX11_OVERRIDE
+ {
+ new GnuTLSIOHook(this, sock, false, profile);
+ }
+};
- /* This verification function uses the trusted CAs in the credentials
- * structure. So you must have installed one or more CA certificates.
- */
- ret = gnutls_certificate_verify_peers2(session->sess, &status);
+class ModuleSSLGnuTLS : public Module
+{
+ typedef std::vector<reference<GnuTLSIOHookProvider> > ProfileList;
- if (ret < 0)
- {
- certinfo->error = std::string(gnutls_strerror(ret));
- return;
- }
+ // First member of the class, gets constructed first and destructed last
+ GnuTLS::Init libinit;
+ RandGen randhandler;
+ ProfileList profiles;
- certinfo->invalid = (status & GNUTLS_CERT_INVALID);
- certinfo->unknownsigner = (status & GNUTLS_CERT_SIGNER_NOT_FOUND);
- certinfo->revoked = (status & GNUTLS_CERT_REVOKED);
- certinfo->trusted = !(status & GNUTLS_CERT_SIGNER_NOT_CA);
+ void ReadProfiles()
+ {
+ // First, store all profiles in a new, temporary container. If no problems occur, swap the two
+ // containers; this way if something goes wrong we can go back and continue using the current profiles,
+ // avoiding unpleasant situations where no new SSL connections are possible.
+ ProfileList newprofiles;
- /* Up to here the process is the same for X.509 certificates and
- * OpenPGP keys. From now on X.509 certificates are assumed. This can
- * be easily extended to work with openpgp keys as well.
- */
- if (gnutls_certificate_type_get(session->sess) != GNUTLS_CRT_X509)
+ ConfigTagList tags = ServerInstance->Config->ConfTags("sslprofile");
+ if (tags.first == tags.second)
{
- certinfo->error = "No X509 keys sent";
- return;
- }
+ // No <sslprofile> tags found, create a profile named "gnutls" from settings in the <gnutls> block
+ const std::string defname = "gnutls";
+ ConfigTag* tag = ServerInstance->Config->ConfValue(defname);
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "No <sslprofile> tags found; using settings from the <gnutls> tag");
- ret = gnutls_x509_crt_init(&cert);
- if (ret < 0)
- {
- certinfo->error = gnutls_strerror(ret);
- return;
+ try
+ {
+ reference<GnuTLS::Profile> profile(GnuTLS::Profile::Create(defname, tag));
+ newprofiles.push_back(new GnuTLSIOHookProvider(this, profile));
+ }
+ catch (CoreException& ex)
+ {
+ throw ModuleException("Error while initializing the default SSL profile - " + ex.GetReason());
+ }
}
- cert_list_size = 0;
- cert_list = gnutls_certificate_get_peers(session->sess, &cert_list_size);
- if (cert_list == NULL)
+ for (ConfigIter i = tags.first; i != tags.second; ++i)
{
- certinfo->error = "No certificate was found";
- goto info_done_dealloc;
- }
+ ConfigTag* tag = i->second;
+ if (tag->getString("provider") != "gnutls")
+ continue;
- /* This is not a real world example, since we only check the first
- * certificate in the given chain.
- */
+ std::string name = tag->getString("name");
+ if (name.empty())
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Ignoring <sslprofile> tag without name at " + tag->getTagLocation());
+ continue;
+ }
- ret = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
- if (ret < 0)
- {
- certinfo->error = gnutls_strerror(ret);
- goto info_done_dealloc;
- }
+ reference<GnuTLS::Profile> profile;
+ try
+ {
+ profile = GnuTLS::Profile::Create(name, tag);
+ }
+ catch (CoreException& ex)
+ {
+ throw ModuleException("Error while initializing SSL profile \"" + name + "\" at " + tag->getTagLocation() + " - " + ex.GetReason());
+ }
- if (gnutls_x509_crt_get_dn(cert, name, &name_size) == 0)
- {
- std::string& dn = certinfo->dn;
- dn = name;
- // Make sure there are no chars in the string that we consider invalid
- if (dn.find_first_of("\r\n") != std::string::npos)
- dn.clear();
+ newprofiles.push_back(new GnuTLSIOHookProvider(this, profile));
}
- name_size = sizeof(name);
- if (gnutls_x509_crt_get_issuer_dn(cert, name, &name_size) == 0)
- {
- std::string& issuer = certinfo->issuer;
- issuer = name;
- if (issuer.find_first_of("\r\n") != std::string::npos)
- issuer.clear();
- }
+ // New profiles are ok, begin using them
+ // Old profiles are deleted when their refcount drops to zero
+ profiles.swap(newprofiles);
+ }
- if ((ret = gnutls_x509_crt_get_fingerprint(cert, hash, digest, &digest_size)) < 0)
+ public:
+ ModuleSSLGnuTLS()
+ {
+#ifndef GNUTLS_HAS_RND
+ gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+#endif
+ }
+
+ void init() CXX11_OVERRIDE
+ {
+ ReadProfiles();
+ ServerInstance->GenRandom = &randhandler;
+ }
+
+ void OnModuleRehash(User* user, const std::string &param) CXX11_OVERRIDE
+ {
+ if(param != "ssl")
+ return;
+
+ try
{
- certinfo->error = gnutls_strerror(ret);
+ ReadProfiles();
}
- else
+ catch (ModuleException& ex)
{
- certinfo->fingerprint = irc::hex(digest, digest_size);
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, ex.GetReason() + " Not applying settings.");
}
+ }
- /* Beware here we do not check for errors.
- */
- if ((gnutls_x509_crt_get_expiration_time(cert) < ServerInstance->Time()) || (gnutls_x509_crt_get_activation_time(cert) > ServerInstance->Time()))
+ ~ModuleSSLGnuTLS()
+ {
+ ServerInstance->GenRandom = &ServerInstance->HandleGenRandom;
+ }
+
+ void OnCleanup(int target_type, void* item) CXX11_OVERRIDE
+ {
+ if(target_type == TYPE_USER)
{
- certinfo->error = "Not activated, or expired certificate";
+ LocalUser* user = IS_LOCAL(static_cast<User*>(item));
+
+ if (user && user->eh.GetIOHook() && user->eh.GetIOHook()->prov->creator == this)
+ {
+ // User is using SSL, they're a local user, and they're using one of *our* SSL ports.
+ // Potentially there could be multiple SSL modules loaded at once on different ports.
+ ServerInstance->Users->QuitUser(user, "SSL module unloading");
+ }
}
+ }
-info_done_dealloc:
- gnutls_x509_crt_deinit(cert);
+ Version GetVersion() CXX11_OVERRIDE
+ {
+ return Version("Provides SSL support for clients", VF_VENDOR);
}
- void OnEvent(Event& ev)
+ void OnUserConnect(LocalUser* user) CXX11_OVERRIDE
{
- if (starttls.enabled)
- capHandler.HandleEvent(ev);
+ IOHook* hook = user->eh.GetIOHook();
+ if (hook && hook->prov->creator == this)
+ static_cast<GnuTLSIOHook*>(hook)->TellCiphersAndFingerprint(user);
}
};
diff --git a/src/modules/extra/m_ssl_openssl.cpp b/src/modules/extra/m_ssl_openssl.cpp
index 33f848798..afead64d8 100644
--- a/src/modules/extra/m_ssl_openssl.cpp
+++ b/src/modules/extra/m_ssl_openssl.cpp
@@ -21,35 +21,26 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
- /* HACK: This prevents OpenSSL on OS X 10.7 and later from spewing deprecation
- * warnings for every single function call. As far as I (SaberUK) know, Apple
- * have no plans to remove OpenSSL so this warning just causes needless spam.
- */
-#ifdef __APPLE__
-# define __AVAILABILITYMACROS__
-# define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
-#endif
-
+
#include "inspircd.h"
+#include "iohook.h"
+#include "modules/ssl.h"
+
+// Ignore OpenSSL deprecation warnings on OS X Lion and newer.
+#if defined __APPLE__
+# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
#include <openssl/ssl.h>
#include <openssl/err.h>
-#include "ssl.h"
#ifdef _WIN32
# pragma comment(lib, "ssleay32.lib")
# pragma comment(lib, "libeay32.lib")
-# undef MAX_DESCRIPTORS
-# define MAX_DESCRIPTORS 10000
#endif
-/* $ModDesc: Provides SSL support for clients */
-
-/* $LinkerFlags: if("USE_FREEBSD_BASE_SSL") -lssl -lcrypto */
-/* $CompileFlags: if(!"USE_FREEBSD_BASE_SSL") pkgconfversion("openssl","0.9.7") pkgconfincludes("openssl","/openssl/ssl.h","") */
-/* $LinkerFlags: if(!"USE_FREEBSD_BASE_SSL") rpath("pkg-config --libs openssl") pkgconflibs("openssl","/libssl.so","-lssl -lcrypto -ldl") */
-
-/* $NoPedantic */
-
+/* $CompileFlags: pkgconfversion("openssl","0.9.7") pkgconfincludes("openssl","/openssl/ssl.h","") */
+/* $LinkerFlags: rpath("pkg-config --libs openssl") pkgconflibs("openssl","/libssl.so","-lssl -lcrypto") */
enum issl_status { ISSL_NONE, ISSL_HANDSHAKING, ISSL_OPEN };
@@ -60,407 +51,424 @@ char* get_error()
return ERR_error_string(ERR_get_error(), NULL);
}
-static int error_callback(const char *str, size_t len, void *u);
+static int OnVerify(int preverify_ok, X509_STORE_CTX* ctx);
-/** Represents an SSL user's extra data
- */
-class issl_session
+namespace OpenSSL
{
-public:
- SSL* sess;
- issl_status status;
- reference<ssl_cert> cert;
-
- bool outbound;
- bool data_to_write;
-
- issl_session()
+ class Exception : public ModuleException
{
- outbound = false;
- data_to_write = false;
- }
-};
-
-static int OnVerify(int preverify_ok, X509_STORE_CTX *ctx)
-{
- /* XXX: This will allow self signed certificates.
- * In the future if we want an option to not allow this,
- * we can just return preverify_ok here, and openssl
- * will boot off self-signed and invalid peer certs.
- */
- int ve = X509_STORE_CTX_get_error(ctx);
-
- SelfSigned = (ve == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT);
-
- return 1;
-}
-
-class ModuleSSLOpenSSL : public Module
-{
- issl_session* sessions;
+ public:
+ Exception(const std::string& reason)
+ : ModuleException(reason) { }
+ };
- SSL_CTX* ctx;
- SSL_CTX* clictx;
-
- std::string sslports;
- bool use_sha;
-
- ServiceProvider iohook;
- public:
-
- ModuleSSLOpenSSL() : iohook(this, "ssl/openssl", SERVICE_IOHOOK)
+ class DHParams
{
- sessions = new issl_session[ServerInstance->SE->GetMaxFds()];
+ DH* dh;
- /* Global SSL library initialization*/
- SSL_library_init();
- SSL_load_error_strings();
-
- /* Build our SSL contexts:
- * NOTE: OpenSSL makes us have two contexts, one for servers and one for clients. ICK.
- */
- ctx = SSL_CTX_new( SSLv23_server_method() );
- clictx = SSL_CTX_new( SSLv23_client_method() );
+ public:
+ DHParams(const std::string& filename)
+ {
+#ifdef _WIN32
+ BIO* dhpfile = BIO_new_file(filename.c_str(), "r");
+#else
+ FILE* dhpfile = fopen(filename.c_str(), "r");
+#endif
+ if (dhpfile == NULL)
+ throw Exception("Couldn't open DH file " + filename + ": " + strerror(errno));
- SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
- SSL_CTX_set_mode(clictx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+#ifdef _WIN32
+ dh = PEM_read_bio_DHparams(dhpfile, NULL, NULL, NULL);
+ BIO_free(dhpfile);
+#else
+ dh = PEM_read_DHparams(dhpfile, NULL, NULL, NULL);
+ fclose(dhpfile);
+#endif
+ if (!dh)
+ throw Exception("Couldn't read DH params from file " + filename);
+ }
- SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, OnVerify);
- SSL_CTX_set_verify(clictx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, OnVerify);
+ ~DHParams()
+ {
+ DH_free(dh);
+ }
- const unsigned char session_id[] = "inspircd";
- SSL_CTX_set_session_id_context(ctx, session_id, sizeof(session_id) - 1);
- }
+ DH* get()
+ {
+ return dh;
+ }
+ };
- void init()
+ class Context
{
- // Needs the flag as it ignores a plain /rehash
- OnModuleRehash(NULL,"ssl");
- Implementation eventlist[] = { I_On005Numeric, I_OnRehash, I_OnModuleRehash, I_OnHookIO, I_OnUserConnect };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- ServerInstance->Modules->AddService(iohook);
- }
+ SSL_CTX* const ctx;
- void OnHookIO(StreamSocket* user, ListenSocket* lsb)
- {
- if (!user->GetIOHook() && lsb->bind_tag->getString("ssl") == "openssl")
+ public:
+ Context(SSL_CTX* context)
+ : ctx(context)
{
- /* Hook the user with our module */
- user->AddIOHook(this);
+ // Sane default options for OpenSSL see https://www.openssl.org/docs/ssl/SSL_CTX_set_options.html
+ // and when choosing a cipher, use the server's preferences instead of the client preferences.
+ SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_CIPHER_SERVER_PREFERENCE);
+ SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, OnVerify);
+
+ const unsigned char session_id[] = "inspircd";
+ SSL_CTX_set_session_id_context(ctx, session_id, sizeof(session_id) - 1);
}
- }
- void OnRehash(User* user)
- {
- sslports.clear();
+ ~Context()
+ {
+ SSL_CTX_free(ctx);
+ }
- ConfigTag* Conf = ServerInstance->Config->ConfValue("openssl");
+ bool SetDH(DHParams& dh)
+ {
+ return (SSL_CTX_set_tmp_dh(ctx, dh.get()) >= 0);
+ }
- if (Conf->getBool("showports", true))
+ bool SetCiphers(const std::string& ciphers)
{
- sslports = Conf->getString("advertisedports");
- if (!sslports.empty())
- return;
+ return SSL_CTX_set_cipher_list(ctx, ciphers.c_str());
+ }
- for (size_t i = 0; i < ServerInstance->ports.size(); i++)
- {
- ListenSocket* port = ServerInstance->ports[i];
- if (port->bind_tag->getString("ssl") != "openssl")
- continue;
+ bool SetCerts(const std::string& filename)
+ {
+ return SSL_CTX_use_certificate_chain_file(ctx, filename.c_str());
+ }
- const std::string& portid = port->bind_desc;
- ServerInstance->Logs->Log("m_ssl_openssl", DEFAULT, "m_ssl_openssl.so: Enabling SSL for port %s", portid.c_str());
+ bool SetPrivateKey(const std::string& filename)
+ {
+ return SSL_CTX_use_PrivateKey_file(ctx, filename.c_str(), SSL_FILETYPE_PEM);
+ }
- if (port->bind_tag->getString("type", "clients") == "clients" && port->bind_addr != "127.0.0.1")
- {
- /*
- * Found an SSL port for clients that is not bound to 127.0.0.1 and handled by us, display
- * the IP:port in ISUPPORT.
- *
- * We used to advertise all ports seperated by a ';' char that matched the above criteria,
- * but this resulted in too long ISUPPORT lines if there were lots of ports to be displayed.
- * To solve this by default we now only display the first IP:port found and let the user
- * configure the exact value for the 005 token, if necessary.
- */
- sslports = portid;
- break;
- }
- }
+ bool SetCA(const std::string& filename)
+ {
+ return SSL_CTX_load_verify_locations(ctx, filename.c_str(), 0);
}
- }
- void OnModuleRehash(User* user, const std::string &param)
+ SSL* CreateSession()
+ {
+ return SSL_new(ctx);
+ }
+ };
+
+ class Profile : public refcountbase
{
- if (param != "ssl")
- return;
+ /** Name of this profile
+ */
+ const std::string name;
- std::string keyfile;
- std::string certfile;
- std::string cafile;
- std::string dhfile;
- OnRehash(user);
+ /** DH parameters in use
+ */
+ DHParams dh;
- ConfigTag* conf = ServerInstance->Config->ConfValue("openssl");
+ /** OpenSSL makes us have two contexts, one for servers and one for clients
+ */
+ Context ctx;
+ Context clictx;
- cafile = conf->getString("cafile", CONFIG_PATH "/ca.pem");
- certfile = conf->getString("certfile", CONFIG_PATH "/cert.pem");
- keyfile = conf->getString("keyfile", CONFIG_PATH "/key.pem");
- dhfile = conf->getString("dhfile", CONFIG_PATH "/dhparams.pem");
- std::string hash = conf->getString("hash", "md5");
- if (hash != "sha1" && hash != "md5")
- throw ModuleException("Unknown hash type " + hash);
- use_sha = (hash == "sha1");
+ /** Digest to use when generating fingerprints
+ */
+ const EVP_MD* digest;
- std::string ciphers = conf->getString("ciphers", "");
+ /** Last error, set by error_callback()
+ */
+ std::string lasterr;
- if (!ciphers.empty())
+ static int error_callback(const char* str, size_t len, void* u)
{
- if ((!SSL_CTX_set_cipher_list(ctx, ciphers.c_str())) || (!SSL_CTX_set_cipher_list(clictx, ciphers.c_str())))
- {
- ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "m_ssl_openssl.so: Can't set cipher list to %s.", ciphers.c_str());
- ERR_print_errors_cb(error_callback, this);
- }
+ Profile* profile = reinterpret_cast<Profile*>(u);
+ profile->lasterr = std::string(str, len - 1);
+ return 0;
}
- /* Load our keys and certificates
- * NOTE: OpenSSL's error logging API sucks, don't blame us for this clusterfuck.
- */
- if ((!SSL_CTX_use_certificate_chain_file(ctx, certfile.c_str())) || (!SSL_CTX_use_certificate_chain_file(clictx, certfile.c_str())))
+ public:
+ Profile(const std::string& profilename, ConfigTag* tag)
+ : name(profilename)
+ , dh(ServerInstance->Config->Paths.PrependConfig(tag->getString("dhfile", "dh.pem")))
+ , ctx(SSL_CTX_new(SSLv23_server_method()))
+ , clictx(SSL_CTX_new(SSLv23_client_method()))
{
- ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "m_ssl_openssl.so: Can't read certificate file %s. %s", certfile.c_str(), strerror(errno));
- ERR_print_errors_cb(error_callback, this);
- }
+ if ((!ctx.SetDH(dh)) || (!clictx.SetDH(dh)))
+ throw Exception("Couldn't set DH parameters");
- if (((!SSL_CTX_use_PrivateKey_file(ctx, keyfile.c_str(), SSL_FILETYPE_PEM))) || (!SSL_CTX_use_PrivateKey_file(clictx, keyfile.c_str(), SSL_FILETYPE_PEM)))
- {
- ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "m_ssl_openssl.so: Can't read key file %s. %s", keyfile.c_str(), strerror(errno));
- ERR_print_errors_cb(error_callback, this);
- }
+ std::string hash = tag->getString("hash", "md5");
+ digest = EVP_get_digestbyname(hash.c_str());
+ if (digest == NULL)
+ throw Exception("Unknown hash type " + hash);
- /* Load the CAs we trust*/
- if (((!SSL_CTX_load_verify_locations(ctx, cafile.c_str(), 0))) || (!SSL_CTX_load_verify_locations(clictx, cafile.c_str(), 0)))
- {
- ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "m_ssl_openssl.so: Can't read CA list from %s. This is only a problem if you want to verify client certificates, otherwise it's safe to ignore this message. Error: %s", cafile.c_str(), strerror(errno));
- ERR_print_errors_cb(error_callback, this);
- }
+ std::string ciphers = tag->getString("ciphers");
+ if (!ciphers.empty())
+ {
+ if ((!ctx.SetCiphers(ciphers)) || (!clictx.SetCiphers(ciphers)))
+ {
+ ERR_print_errors_cb(error_callback, this);
+ throw Exception("Can't set cipher list to \"" + ciphers + "\" " + lasterr);
+ }
+ }
-#ifdef _WIN32
- BIO* dhpfile = BIO_new_file(dhfile.c_str(), "r");
-#else
- FILE* dhpfile = fopen(dhfile.c_str(), "r");
-#endif
- DH* ret;
+ /* Load our keys and certificates
+ * NOTE: OpenSSL's error logging API sucks, don't blame us for this clusterfuck.
+ */
+ std::string filename = ServerInstance->Config->Paths.PrependConfig(tag->getString("certfile", "cert.pem"));
+ if ((!ctx.SetCerts(filename)) || (!clictx.SetCerts(filename)))
+ {
+ ERR_print_errors_cb(error_callback, this);
+ throw Exception("Can't read certificate file: " + lasterr);
+ }
- if (dhpfile == NULL)
- {
- ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "m_ssl_openssl.so Couldn't open DH file %s: %s", dhfile.c_str(), strerror(errno));
- throw ModuleException("Couldn't open DH file " + dhfile + ": " + strerror(errno));
- }
- else
- {
-#ifdef _WIN32
- ret = PEM_read_bio_DHparams(dhpfile, NULL, NULL, NULL);
- BIO_free(dhpfile);
-#else
- ret = PEM_read_DHparams(dhpfile, NULL, NULL, NULL);
-#endif
- if ((SSL_CTX_set_tmp_dh(ctx, ret) < 0) || (SSL_CTX_set_tmp_dh(clictx, ret) < 0))
+ filename = ServerInstance->Config->Paths.PrependConfig(tag->getString("keyfile", "key.pem"));
+ if ((!ctx.SetPrivateKey(filename)) || (!clictx.SetPrivateKey(filename)))
+ {
+ ERR_print_errors_cb(error_callback, this);
+ throw Exception("Can't read key file: " + lasterr);
+ }
+
+ // Load the CAs we trust
+ filename = ServerInstance->Config->Paths.PrependConfig(tag->getString("cafile", "ca.pem"));
+ if ((!ctx.SetCA(filename)) || (!clictx.SetCA(filename)))
{
- ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "m_ssl_openssl.so: Couldn't set DH parameters %s. SSL errors follow:", dhfile.c_str());
ERR_print_errors_cb(error_callback, this);
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Can't read CA list from %s. This is only a problem if you want to verify client certificates, otherwise it's safe to ignore this message. Error: %s", filename.c_str(), lasterr.c_str());
}
- DH_free(ret);
}
-#ifndef _WIN32
- fclose(dhpfile);
-#endif
- }
+ const std::string& GetName() const { return name; }
+ SSL* CreateServerSession() { return ctx.CreateSession(); }
+ SSL* CreateClientSession() { return clictx.CreateSession(); }
+ const EVP_MD* GetDigest() { return digest; }
+ };
+}
- void On005Numeric(std::string &output)
- {
- if (!sslports.empty())
- output.append(" SSL=" + sslports);
- }
+static int OnVerify(int preverify_ok, X509_STORE_CTX *ctx)
+{
+ /* XXX: This will allow self signed certificates.
+ * In the future if we want an option to not allow this,
+ * we can just return preverify_ok here, and openssl
+ * will boot off self-signed and invalid peer certs.
+ */
+ int ve = X509_STORE_CTX_get_error(ctx);
- ~ModuleSSLOpenSSL()
- {
- SSL_CTX_free(ctx);
- SSL_CTX_free(clictx);
- delete[] sessions;
- }
+ SelfSigned = (ve == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT);
- void OnUserConnect(LocalUser* user)
+ return 1;
+}
+
+class OpenSSLIOHook : public SSLIOHook
+{
+ private:
+ SSL* sess;
+ issl_status status;
+ const bool outbound;
+ bool data_to_write;
+ reference<OpenSSL::Profile> profile;
+
+ bool Handshake(StreamSocket* user)
{
- if (user->eh.GetIOHook() == this)
+ int ret;
+
+ if (outbound)
+ ret = SSL_connect(sess);
+ else
+ ret = SSL_accept(sess);
+
+ if (ret < 0)
{
- if (sessions[user->eh.GetFd()].sess)
+ int err = SSL_get_error(sess, ret);
+
+ if (err == SSL_ERROR_WANT_READ)
{
- if (!sessions[user->eh.GetFd()].cert->fingerprint.empty())
- user->WriteServ("NOTICE %s :*** You are connected using SSL cipher \"%s\""
- " and your SSL fingerprint is %s", user->nick.c_str(), SSL_get_cipher(sessions[user->eh.GetFd()].sess), sessions[user->eh.GetFd()].cert->fingerprint.c_str());
- else
- user->WriteServ("NOTICE %s :*** You are connected using SSL cipher \"%s\"", user->nick.c_str(), SSL_get_cipher(sessions[user->eh.GetFd()].sess));
+ SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
+ this->status = ISSL_HANDSHAKING;
+ return true;
+ }
+ else if (err == SSL_ERROR_WANT_WRITE)
+ {
+ SocketEngine::ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE);
+ this->status = ISSL_HANDSHAKING;
+ return true;
+ }
+ else
+ {
+ CloseSession();
}
- }
- }
- void OnCleanup(int target_type, void* item)
- {
- if (target_type == TYPE_USER)
+ return false;
+ }
+ else if (ret > 0)
{
- LocalUser* user = IS_LOCAL((User*)item);
+ // Handshake complete.
+ VerifyCertificate();
- if (user && user->eh.GetIOHook() == this)
- {
- // User is using SSL, they're a local user, and they're using one of *our* SSL ports.
- // Potentially there could be multiple SSL modules loaded at once on different ports.
- ServerInstance->Users->QuitUser(user, "SSL module unloading");
- }
+ status = ISSL_OPEN;
+
+ SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE | FD_ADD_TRIAL_WRITE);
+
+ return true;
+ }
+ else if (ret == 0)
+ {
+ CloseSession();
+ return true;
}
- }
- Version GetVersion()
- {
- return Version("Provides SSL support for clients", VF_VENDOR);
+ return true;
}
- void OnRequest(Request& request)
+ void CloseSession()
{
- if (strcmp("GET_SSL_CERT", request.id) == 0)
+ if (sess)
{
- SocketCertificateRequest& req = static_cast<SocketCertificateRequest&>(request);
- int fd = req.sock->GetFd();
- issl_session* session = &sessions[fd];
-
- req.cert = session->cert;
+ SSL_shutdown(sess);
+ SSL_free(sess);
}
+ sess = NULL;
+ certificate = NULL;
+ status = ISSL_NONE;
+ errno = EIO;
}
- void OnStreamSocketAccept(StreamSocket* user, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server)
+ void VerifyCertificate()
{
- int fd = user->GetFd();
-
- issl_session* session = &sessions[fd];
-
- session->sess = SSL_new(ctx);
- session->status = ISSL_NONE;
- session->outbound = false;
- session->cert = NULL;
+ X509* cert;
+ ssl_cert* certinfo = new ssl_cert;
+ this->certificate = certinfo;
+ unsigned int n;
+ unsigned char md[EVP_MAX_MD_SIZE];
- if (session->sess == NULL)
- return;
+ cert = SSL_get_peer_certificate(sess);
- if (SSL_set_fd(session->sess, fd) == 0)
+ if (!cert)
{
- ServerInstance->Logs->Log("m_ssl_openssl",DEBUG,"BUG: Can't set fd with SSL_set_fd: %d", fd);
+ certinfo->error = "Could not get peer certificate: "+std::string(get_error());
return;
}
- Handshake(user, session);
- }
+ certinfo->invalid = (SSL_get_verify_result(sess) != X509_V_OK);
- void OnStreamSocketConnect(StreamSocket* user)
- {
- int fd = user->GetFd();
- /* Are there any possibilities of an out of range fd? Hope not, but lets be paranoid */
- if ((fd < 0) || (fd > ServerInstance->SE->GetMaxFds() -1))
- return;
+ if (!SelfSigned)
+ {
+ certinfo->unknownsigner = false;
+ certinfo->trusted = true;
+ }
+ else
+ {
+ certinfo->unknownsigner = true;
+ certinfo->trusted = false;
+ }
- issl_session* session = &sessions[fd];
+ char buf[512];
+ X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
+ certinfo->dn = buf;
+ // Make sure there are no chars in the string that we consider invalid
+ if (certinfo->dn.find_first_of("\r\n") != std::string::npos)
+ certinfo->dn.clear();
- session->sess = SSL_new(clictx);
- session->status = ISSL_NONE;
- session->outbound = true;
+ X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof(buf));
+ certinfo->issuer = buf;
+ if (certinfo->issuer.find_first_of("\r\n") != std::string::npos)
+ certinfo->issuer.clear();
- if (session->sess == NULL)
- return;
+ if (!X509_digest(cert, profile->GetDigest(), md, &n))
+ {
+ certinfo->error = "Out of memory generating fingerprint";
+ }
+ else
+ {
+ certinfo->fingerprint = BinToHex(md, n);
+ }
- if (SSL_set_fd(session->sess, fd) == 0)
+ if ((ASN1_UTCTIME_cmp_time_t(X509_get_notAfter(cert), ServerInstance->Time()) == -1) || (ASN1_UTCTIME_cmp_time_t(X509_get_notBefore(cert), ServerInstance->Time()) == 0))
{
- ServerInstance->Logs->Log("m_ssl_openssl",DEBUG,"BUG: Can't set fd with SSL_set_fd: %d", fd);
- return;
+ certinfo->error = "Not activated, or expired certificate";
}
- Handshake(user, session);
+ X509_free(cert);
}
- void OnStreamSocketClose(StreamSocket* user)
+ public:
+ OpenSSLIOHook(IOHookProvider* hookprov, StreamSocket* sock, bool is_outbound, SSL* session, const reference<OpenSSL::Profile>& sslprofile)
+ : SSLIOHook(hookprov)
+ , sess(session)
+ , status(ISSL_NONE)
+ , outbound(is_outbound)
+ , data_to_write(false)
+ , profile(sslprofile)
{
- int fd = user->GetFd();
- /* Are there any possibilities of an out of range fd? Hope not, but lets be paranoid */
- if ((fd < 0) || (fd > ServerInstance->SE->GetMaxFds() - 1))
+ if (sess == NULL)
return;
+ if (SSL_set_fd(sess, sock->GetFd()) == 0)
+ throw ModuleException("Can't set fd with SSL_set_fd: " + ConvToStr(sock->GetFd()));
- CloseSession(&sessions[fd]);
+ sock->AddIOHook(this);
+ Handshake(sock);
}
- int OnStreamSocketRead(StreamSocket* user, std::string& recvq)
+ void OnStreamSocketClose(StreamSocket* user) CXX11_OVERRIDE
{
- int fd = user->GetFd();
- /* Are there any possibilities of an out of range fd? Hope not, but lets be paranoid */
- if ((fd < 0) || (fd > ServerInstance->SE->GetMaxFds() - 1))
- return -1;
-
- issl_session* session = &sessions[fd];
+ CloseSession();
+ }
- if (!session->sess)
+ int OnStreamSocketRead(StreamSocket* user, std::string& recvq) CXX11_OVERRIDE
+ {
+ if (!sess)
{
- CloseSession(session);
+ CloseSession();
return -1;
}
- if (session->status == ISSL_HANDSHAKING)
+ if (status == ISSL_HANDSHAKING)
{
// The handshake isn't finished and it wants to read, try to finish it.
- if (!Handshake(user, session))
+ if (!Handshake(user))
{
// Couldn't resume handshake.
- if (session->status == ISSL_NONE)
+ if (status == ISSL_NONE)
return -1;
return 0;
}
}
- // If we resumed the handshake then session->status will be ISSL_OPEN
+ // If we resumed the handshake then this->status will be ISSL_OPEN
- if (session->status == ISSL_OPEN)
+ if (status == ISSL_OPEN)
{
char* buffer = ServerInstance->GetReadBuffer();
size_t bufsiz = ServerInstance->Config->NetBufferSize;
- int ret = SSL_read(session->sess, buffer, bufsiz);
+ int ret = SSL_read(sess, buffer, bufsiz);
if (ret > 0)
{
recvq.append(buffer, ret);
- if (session->data_to_write)
- ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_SINGLE_WRITE);
+ if (data_to_write)
+ SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_SINGLE_WRITE);
return 1;
}
else if (ret == 0)
{
// Client closed connection.
- CloseSession(session);
+ CloseSession();
user->SetError("Connection closed");
return -1;
}
else if (ret < 0)
{
- int err = SSL_get_error(session->sess, ret);
+ int err = SSL_get_error(sess, ret);
if (err == SSL_ERROR_WANT_READ)
{
- ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_READ);
+ SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ);
return 0;
}
else if (err == SSL_ERROR_WANT_WRITE)
{
- ServerInstance->SE->ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE);
+ SocketEngine::ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE);
return 0;
}
else
{
- CloseSession(session);
+ CloseSession();
return -1;
}
}
@@ -469,68 +477,64 @@ class ModuleSSLOpenSSL : public Module
return 0;
}
- int OnStreamSocketWrite(StreamSocket* user, std::string& buffer)
+ int OnStreamSocketWrite(StreamSocket* user, std::string& buffer) CXX11_OVERRIDE
{
- int fd = user->GetFd();
-
- issl_session* session = &sessions[fd];
-
- if (!session->sess)
+ if (!sess)
{
- CloseSession(session);
+ CloseSession();
return -1;
}
- session->data_to_write = true;
+ data_to_write = true;
- if (session->status == ISSL_HANDSHAKING)
+ if (status == ISSL_HANDSHAKING)
{
- if (!Handshake(user, session))
+ if (!Handshake(user))
{
// Couldn't resume handshake.
- if (session->status == ISSL_NONE)
+ if (status == ISSL_NONE)
return -1;
return 0;
}
}
- if (session->status == ISSL_OPEN)
+ if (status == ISSL_OPEN)
{
- int ret = SSL_write(session->sess, buffer.data(), buffer.size());
+ int ret = SSL_write(sess, buffer.data(), buffer.size());
if (ret == (int)buffer.length())
{
- session->data_to_write = false;
- ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
+ data_to_write = false;
+ SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
return 1;
}
else if (ret > 0)
{
buffer = buffer.substr(ret);
- ServerInstance->SE->ChangeEventMask(user, FD_WANT_SINGLE_WRITE);
+ SocketEngine::ChangeEventMask(user, FD_WANT_SINGLE_WRITE);
return 0;
}
else if (ret == 0)
{
- CloseSession(session);
+ CloseSession();
return -1;
}
else if (ret < 0)
{
- int err = SSL_get_error(session->sess, ret);
+ int err = SSL_get_error(sess, ret);
if (err == SSL_ERROR_WANT_WRITE)
{
- ServerInstance->SE->ChangeEventMask(user, FD_WANT_SINGLE_WRITE);
+ SocketEngine::ChangeEventMask(user, FD_WANT_SINGLE_WRITE);
return 0;
}
else if (err == SSL_ERROR_WANT_READ)
{
- ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_READ);
+ SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ);
return 0;
}
else
{
- CloseSession(session);
+ CloseSession();
return -1;
}
}
@@ -538,148 +542,159 @@ class ModuleSSLOpenSSL : public Module
return 0;
}
- bool Handshake(StreamSocket* user, issl_session* session)
+ void TellCiphersAndFingerprint(LocalUser* user)
{
- int ret;
+ if (sess)
+ {
+ std::string text = "*** You are connected using SSL cipher '" + std::string(SSL_get_cipher(sess)) + "'";
+ const std::string& fingerprint = certificate->fingerprint;
+ if (!fingerprint.empty())
+ text += " and your SSL certificate fingerprint is " + fingerprint;
- if (session->outbound)
- ret = SSL_connect(session->sess);
- else
- ret = SSL_accept(session->sess);
+ user->WriteNotice(text);
+ }
+ }
+};
- if (ret < 0)
+class OpenSSLIOHookProvider : public refcountbase, public IOHookProvider
+{
+ reference<OpenSSL::Profile> profile;
+
+ public:
+ OpenSSLIOHookProvider(Module* mod, reference<OpenSSL::Profile>& prof)
+ : IOHookProvider(mod, "ssl/" + prof->GetName(), IOHookProvider::IOH_SSL)
+ , profile(prof)
+ {
+ ServerInstance->Modules->AddService(*this);
+ }
+
+ ~OpenSSLIOHookProvider()
+ {
+ ServerInstance->Modules->DelService(*this);
+ }
+
+ void OnAccept(StreamSocket* sock, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) CXX11_OVERRIDE
+ {
+ new OpenSSLIOHook(this, sock, false, profile->CreateServerSession(), profile);
+ }
+
+ void OnConnect(StreamSocket* sock) CXX11_OVERRIDE
+ {
+ new OpenSSLIOHook(this, sock, true, profile->CreateClientSession(), profile);
+ }
+};
+
+class ModuleSSLOpenSSL : public Module
+{
+ typedef std::vector<reference<OpenSSLIOHookProvider> > ProfileList;
+
+ ProfileList profiles;
+
+ void ReadProfiles()
+ {
+ ProfileList newprofiles;
+ ConfigTagList tags = ServerInstance->Config->ConfTags("sslprofile");
+ if (tags.first == tags.second)
{
- int err = SSL_get_error(session->sess, ret);
+ // Create a default profile named "openssl"
+ const std::string defname = "openssl";
+ ConfigTag* tag = ServerInstance->Config->ConfValue(defname);
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "No <sslprofile> tags found, using settings from the <openssl> tag");
- if (err == SSL_ERROR_WANT_READ)
- {
- ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
- session->status = ISSL_HANDSHAKING;
- return true;
- }
- else if (err == SSL_ERROR_WANT_WRITE)
+ try
{
- ServerInstance->SE->ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE);
- session->status = ISSL_HANDSHAKING;
- return true;
+ reference<OpenSSL::Profile> profile(new OpenSSL::Profile(defname, tag));
+ newprofiles.push_back(new OpenSSLIOHookProvider(this, profile));
}
- else
+ catch (OpenSSL::Exception& ex)
{
- CloseSession(session);
+ throw ModuleException("Error while initializing the default SSL profile - " + ex.GetReason());
}
-
- return false;
}
- else if (ret > 0)
+
+ for (ConfigIter i = tags.first; i != tags.second; ++i)
{
- // Handshake complete.
- VerifyCertificate(session, user);
+ ConfigTag* tag = i->second;
+ if (tag->getString("provider") != "openssl")
+ continue;
- session->status = ISSL_OPEN;
+ std::string name = tag->getString("name");
+ if (name.empty())
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Ignoring <sslprofile> tag without name at " + tag->getTagLocation());
+ continue;
+ }
- ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE | FD_ADD_TRIAL_WRITE);
+ reference<OpenSSL::Profile> profile;
+ try
+ {
+ profile = new OpenSSL::Profile(name, tag);
+ }
+ catch (CoreException& ex)
+ {
+ throw ModuleException("Error while initializing SSL profile \"" + name + "\" at " + tag->getTagLocation() + " - " + ex.GetReason());
+ }
- return true;
- }
- else if (ret == 0)
- {
- CloseSession(session);
- return true;
+ newprofiles.push_back(new OpenSSLIOHookProvider(this, profile));
}
- return true;
+ profiles.swap(newprofiles);
}
- void CloseSession(issl_session* session)
+ public:
+ ModuleSSLOpenSSL()
{
- if (session->sess)
- {
- SSL_shutdown(session->sess);
- SSL_free(session->sess);
- }
+ // Initialize OpenSSL
+ SSL_library_init();
+ SSL_load_error_strings();
+ }
- session->sess = NULL;
- session->status = ISSL_NONE;
- errno = EIO;
+ void init() CXX11_OVERRIDE
+ {
+ ReadProfiles();
}
- void VerifyCertificate(issl_session* session, StreamSocket* user)
+ void OnModuleRehash(User* user, const std::string &param) CXX11_OVERRIDE
{
- if (!session->sess || !user)
+ if (param != "ssl")
return;
- X509* cert;
- ssl_cert* certinfo = new ssl_cert;
- session->cert = certinfo;
- unsigned int n;
- unsigned char md[EVP_MAX_MD_SIZE];
- const EVP_MD *digest = use_sha ? EVP_sha1() : EVP_md5();
-
- cert = SSL_get_peer_certificate((SSL*)session->sess);
-
- if (!cert)
+ try
{
- certinfo->error = "Could not get peer certificate: "+std::string(get_error());
- return;
+ ReadProfiles();
}
-
- certinfo->invalid = (SSL_get_verify_result(session->sess) != X509_V_OK);
-
- if (!SelfSigned)
+ catch (ModuleException& ex)
{
- certinfo->unknownsigner = false;
- certinfo->trusted = true;
- }
- else
- {
- certinfo->unknownsigner = true;
- certinfo->trusted = false;
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, ex.GetReason() + " Not applying settings.");
}
+ }
- char buf[512];
- X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
- certinfo->dn = buf;
- // Make sure there are no chars in the string that we consider invalid
- if (certinfo->dn.find_first_of("\r\n") != std::string::npos)
- certinfo->dn.clear();
-
- X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof(buf));
- certinfo->issuer = buf;
- if (certinfo->issuer.find_first_of("\r\n") != std::string::npos)
- certinfo->issuer.clear();
+ void OnUserConnect(LocalUser* user) CXX11_OVERRIDE
+ {
+ IOHook* hook = user->eh.GetIOHook();
+ if (hook && hook->prov->creator == this)
+ static_cast<OpenSSLIOHook*>(hook)->TellCiphersAndFingerprint(user);
+ }
- if (!X509_digest(cert, digest, md, &n))
- {
- certinfo->error = "Out of memory generating fingerprint";
- }
- else
+ void OnCleanup(int target_type, void* item) CXX11_OVERRIDE
+ {
+ if (target_type == TYPE_USER)
{
- certinfo->fingerprint = irc::hex(md, n);
- }
+ LocalUser* user = IS_LOCAL((User*)item);
- if ((ASN1_UTCTIME_cmp_time_t(X509_get_notAfter(cert), ServerInstance->Time()) == -1) || (ASN1_UTCTIME_cmp_time_t(X509_get_notBefore(cert), ServerInstance->Time()) == 0))
- {
- certinfo->error = "Not activated, or expired certificate";
+ if (user && user->eh.GetIOHook() && user->eh.GetIOHook()->prov->creator == this)
+ {
+ // User is using SSL, they're a local user, and they're using one of *our* SSL ports.
+ // Potentially there could be multiple SSL modules loaded at once on different ports.
+ ServerInstance->Users->QuitUser(user, "SSL module unloading");
+ }
}
+ }
- X509_free(cert);
+ Version GetVersion() CXX11_OVERRIDE
+ {
+ return Version("Provides SSL support for clients", VF_VENDOR);
}
};
-static int error_callback(const char *str, size_t len, void *u)
-{
- ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "SSL error: " + std::string(str, len - 1));
-
- //
- // XXX: Remove this line, it causes valgrind warnings...
- //
- // MD_update(&m, buf, j);
- //
- //
- // ... ONLY JOKING! :-)
- //
-
- return 0;
-}
-
MODULE_INIT(ModuleSSLOpenSSL)
diff --git a/src/modules/hash.h b/src/modules/hash.h
deleted file mode 100644
index f7bf85e20..000000000
--- a/src/modules/hash.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#ifndef HASH_H
-#define HASH_H
-
-#include "modules.h"
-
-class HashProvider : public DataProvider
-{
- public:
- const unsigned int out_size;
- const unsigned int block_size;
- HashProvider(Module* mod, const std::string& Name, int osiz, int bsiz)
- : DataProvider(mod, Name), out_size(osiz), block_size(bsiz) {}
- virtual std::string sum(const std::string& data) = 0;
- inline std::string hexsum(const std::string& data)
- {
- return BinToHex(sum(data));
- }
-
- inline std::string b64sum(const std::string& data)
- {
- return BinToBase64(sum(data), NULL, 0);
- }
-
- /** Allows the IVs for the hash to be specified. As the choice of initial IV is
- * important for the security of a hash, this should not be used except to
- * maintain backwards compatability. This also allows you to change the hex
- * sequence from its default of "0123456789abcdef", which does not improve the
- * strength of the output, but helps confuse those attempting to implement it.
- *
- * Example:
- * \code
- * unsigned int iv[] = { 0xFFFFFFFF, 0x00000000, 0xAAAAAAAA, 0xCCCCCCCC };
- * std::string result = Hash.sumIV(iv, "fedcba9876543210", "data");
- * \endcode
- */
- virtual std::string sumIV(unsigned int* IV, const char* HexMap, const std::string &sdata) = 0;
-
- /** HMAC algorithm, RFC 2104 */
- std::string hmac(const std::string& key, const std::string& msg)
- {
- std::string hmac1, hmac2;
- std::string kbuf = key.length() > block_size ? sum(key) : key;
- kbuf.resize(block_size);
-
- for (size_t n = 0; n < block_size; n++)
- {
- hmac1.push_back(static_cast<char>(kbuf[n] ^ 0x5C));
- hmac2.push_back(static_cast<char>(kbuf[n] ^ 0x36));
- }
- hmac2.append(msg);
- hmac1.append(sum(hmac2));
- return sum(hmac1);
- }
-};
-
-#endif
-
diff --git a/src/modules/httpd.h b/src/modules/httpd.h
deleted file mode 100644
index 56fd22da0..000000000
--- a/src/modules/httpd.h
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com>
- * Copyright (C) 2007 John Brooks <john.brooks@dereferenced.net>
- * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
- * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "base.h"
-
-#ifndef HTTPD_H
-#define HTTPD_H
-
-#include <string>
-#include <sstream>
-#include <map>
-
-/** A modifyable list of HTTP header fields
- */
-class HTTPHeaders
-{
- protected:
- std::map<std::string,std::string> headers;
- public:
-
- /** Set the value of a header
- * Sets the value of the named header. If the header is already present, it will be replaced
- */
- void SetHeader(const std::string &name, const std::string &data)
- {
- headers[name] = data;
- }
-
- /** Set the value of a header, only if it doesn't exist already
- * Sets the value of the named header. If the header is already present, it will NOT be updated
- */
- void CreateHeader(const std::string &name, const std::string &data)
- {
- if (!IsSet(name))
- SetHeader(name, data);
- }
-
- /** Remove the named header
- */
- void RemoveHeader(const std::string &name)
- {
- headers.erase(name);
- }
-
- /** Remove all headers
- */
- void Clear()
- {
- headers.clear();
- }
-
- /** Get the value of a header
- * @return The value of the header, or an empty string
- */
- std::string GetHeader(const std::string &name)
- {
- std::map<std::string,std::string>::iterator it = headers.find(name);
- if (it == headers.end())
- return std::string();
-
- return it->second;
- }
-
- /** Check if the given header is specified
- * @return true if the header is specified
- */
- bool IsSet(const std::string &name)
- {
- std::map<std::string,std::string>::iterator it = headers.find(name);
- return (it != headers.end());
- }
-
- /** Get all headers, formatted by the HTTP protocol
- * @return Returns all headers, formatted according to the HTTP protocol. There is no request terminator at the end
- */
- std::string GetFormattedHeaders()
- {
- std::string re;
-
- for (std::map<std::string,std::string>::iterator i = headers.begin(); i != headers.end(); i++)
- re += i->first + ": " + i->second + "\r\n";
-
- return re;
- }
-};
-
-class HttpServerSocket;
-
-/** This class represents a HTTP request.
- */
-class HTTPRequest : public Event
-{
- protected:
- std::string type;
- std::string document;
- std::string ipaddr;
- std::string postdata;
-
- public:
-
- HTTPHeaders *headers;
- int errorcode;
-
- /** A socket pointer, which you must return in your HTTPDocument class
- * if you reply to this request.
- */
- HttpServerSocket* sock;
-
- /** Initialize HTTPRequest.
- * This constructor is called by m_httpd.so to initialize the class.
- * @param request_type The request type, e.g. GET, POST, HEAD
- * @param uri The URI, e.g. /page
- * @param hdr The headers sent with the request
- * @param opaque An opaque pointer used internally by m_httpd, which you must pass back to the module in your reply.
- * @param ip The IP address making the web request.
- * @param pdata The post data (content after headers) received with the request, up to Content-Length in size
- */
- HTTPRequest(Module* me, const std::string &eventid, const std::string &request_type, const std::string &uri,
- HTTPHeaders* hdr, HttpServerSocket* socket, const std::string &ip, const std::string &pdata)
- : Event(me, eventid), type(request_type), document(uri), ipaddr(ip), postdata(pdata), headers(hdr), sock(socket)
- {
- }
-
- /** Get the post data (request content).
- * All post data will be returned, including carriage returns and linefeeds.
- * @return The postdata
- */
- std::string& GetPostData()
- {
- return postdata;
- }
-
- /** Get the request type.
- * Any request type can be intercepted, even ones which are invalid in the HTTP/1.1 spec.
- * @return The request type, e.g. GET, POST, HEAD
- */
- std::string& GetType()
- {
- return type;
- }
-
- /** Get URI.
- * The URI string (URL minus hostname and scheme) will be provided by this function.
- * @return The URI being requested
- */
- std::string& GetURI()
- {
- return document;
- }
-
- /** Get IP address of requester.
- * The requesting system's ip address will be returned.
- * @return The IP address as a string
- */
- std::string& GetIP()
- {
- return ipaddr;
- }
-};
-
-/** You must return a HTTPDocument to the httpd module by using the Request class.
- * When you initialize this class you may initialize it with all components required to
- * form a valid HTTP response, including document data, headers, and a response code.
- */
-class HTTPDocumentResponse : public Request
-{
- public:
- std::stringstream* document;
- int responsecode;
- HTTPHeaders headers;
- HTTPRequest& src;
-
- /** Initialize a HTTPRequest ready for sending to m_httpd.so.
- * @param opaque The socket pointer you obtained from the HTTPRequest at an earlier time
- * @param doc A stringstream containing the document body
- * @param response A valid HTTP/1.0 or HTTP/1.1 response code. The response text will be determined for you
- * based upon the response code.
- * @param extra Any extra headers to include with the defaults, seperated by carriage return and linefeed.
- */
- HTTPDocumentResponse(Module* me, HTTPRequest& req, std::stringstream* doc, int response)
- : Request(me, req.source, "HTTP-DOC"), document(doc), responsecode(response), src(req)
- {
- }
-};
-
-#endif
-
diff --git a/src/modules/m_abbreviation.cpp b/src/modules/m_abbreviation.cpp
index a744f55f6..77d86cb31 100644
--- a/src/modules/m_abbreviation.cpp
+++ b/src/modules/m_abbreviation.cpp
@@ -19,49 +19,37 @@
#include "inspircd.h"
-/* $ModDesc: Provides the ability to abbreviate commands a-la BBC BASIC keywords. */
-
class ModuleAbbreviation : public Module
{
public:
- void init()
- {
- ServerInstance->Modules->Attach(I_OnPreCommand, this);
- }
-
void Prioritize()
{
ServerInstance->Modules->SetPriority(this, I_OnPreCommand, PRIORITY_FIRST);
}
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides the ability to abbreviate commands a-la BBC BASIC keywords.",VF_VENDOR);
}
- virtual ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line)
+ ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line) CXX11_OVERRIDE
{
/* Command is already validated, has a length of 0, or last character is not a . */
if (validated || command.empty() || *command.rbegin() != '.')
return MOD_RES_PASSTHRU;
- /* Whack the . off the end */
- command.erase(command.end() - 1);
-
/* Look for any command that starts with the same characters, if it does, replace the command string with it */
- size_t clen = command.length();
+ size_t clen = command.length() - 1;
std::string foundcommand, matchlist;
bool foundmatch = false;
- for (Commandtable::iterator n = ServerInstance->Parser->cmdlist.begin(); n != ServerInstance->Parser->cmdlist.end(); ++n)
+ const CommandParser::CommandMap& commands = ServerInstance->Parser.GetCommands();
+ for (CommandParser::CommandMap::const_iterator n = commands.begin(); n != commands.end(); ++n)
{
- if (n->first.length() < clen)
- continue;
-
- if (command == n->first.substr(0, clen))
+ if (!command.compare(0, clen, n->first, 0, clen))
{
if (matchlist.length() > 450)
{
- user->WriteNumeric(420, "%s :Ambiguous abbreviation and too many possible matches.", user->nick.c_str());
+ user->WriteNumeric(420, ":Ambiguous abbreviation and too many possible matches.");
return MOD_RES_DENY;
}
@@ -79,16 +67,11 @@ class ModuleAbbreviation : public Module
/* Ambiguous command, list the matches */
if (!matchlist.empty())
{
- user->WriteNumeric(420, "%s :Ambiguous abbreviation, posssible matches: %s%s", user->nick.c_str(), foundcommand.c_str(), matchlist.c_str());
+ user->WriteNumeric(420, ":Ambiguous abbreviation, posssible matches: %s%s", foundcommand.c_str(), matchlist.c_str());
return MOD_RES_DENY;
}
- if (foundcommand.empty())
- {
- /* No match, we have to put the . back again so that the invalid command numeric looks correct. */
- command += '.';
- }
- else
+ if (!foundcommand.empty())
{
command = foundcommand;
}
diff --git a/src/modules/m_alias.cpp b/src/modules/m_alias.cpp
index 32fc80b64..2d4bdded3 100644
--- a/src/modules/m_alias.cpp
+++ b/src/modules/m_alias.cpp
@@ -22,15 +22,13 @@
#include "inspircd.h"
-/* $ModDesc: Provides aliases of commands. */
-
/** An alias definition
*/
class Alias
{
public:
/** The text of the alias command */
- irc::string AliasedCommand;
+ std::string AliasedCommand;
/** Text to replace with */
std::string ReplaceFormat;
@@ -59,20 +57,22 @@ class Alias
class ModuleAlias : public Module
{
- private:
-
char fprefix;
/* We cant use a map, there may be multiple aliases with the same name.
* We can, however, use a fancy invention: the multimap. Maps a key to one or more values.
* -- w00t
- */
- std::multimap<irc::string, Alias> Aliases;
+ */
+ typedef std::multimap<std::string, Alias, irc::insensitive_swo> AliasMap;
+
+ AliasMap Aliases;
/* whether or not +B users are allowed to use fantasy commands */
bool AllowBots;
+ UserModeReference botmode;
- virtual void ReadAliases()
+ public:
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ConfigTag* fantasy = ServerInstance->Config->ConfValue("fantasy");
AllowBots = fantasy->getBool("allowbots", false);
@@ -85,8 +85,8 @@ class ModuleAlias : public Module
{
ConfigTag* tag = i->second;
Alias a;
- std::string aliastext = tag->getString("text");
- a.AliasedCommand = aliastext.c_str();
+ a.AliasedCommand = tag->getString("text");
+ std::transform(a.AliasedCommand.begin(), a.AliasedCommand.end(), a.AliasedCommand.begin(), ::toupper);
tag->readString("replace", a.ReplaceFormat, true);
a.RequiredNick = tag->getString("requires");
a.ULineOnly = tag->getBool("uline");
@@ -99,20 +99,12 @@ class ModuleAlias : public Module
}
}
- public:
-
- void init()
+ ModuleAlias()
+ : botmode(this, "bot")
{
- ReadAliases();
- Implementation eventlist[] = { I_OnPreCommand, I_OnRehash, I_OnUserMessage };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
}
- virtual ~ModuleAlias()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides aliases of commands.", VF_VENDOR);
}
@@ -142,10 +134,8 @@ class ModuleAlias : public Module
return word;
}
- virtual ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line)
+ ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line) CXX11_OVERRIDE
{
- std::multimap<irc::string, Alias>::iterator i, upperbound;
-
/* If theyre not registered yet, we dont want
* to know.
*/
@@ -153,19 +143,16 @@ class ModuleAlias : public Module
return MOD_RES_PASSTHRU;
/* We dont have any commands looking like this? Stop processing. */
- i = Aliases.find(command.c_str());
- if (i == Aliases.end())
+ std::pair<AliasMap::iterator, AliasMap::iterator> iters = Aliases.equal_range(command);
+ if (iters.first == iters.second)
return MOD_RES_PASSTHRU;
- /* Avoid iterating on to different aliases if no patterns match. */
- upperbound = Aliases.upper_bound(command.c_str());
- irc::string c = command.c_str();
/* The parameters for the command in their original form, with the command stripped off */
std::string compare = original_line.substr(command.length());
while (*(compare.c_str()) == ' ')
compare.erase(compare.begin());
- while (i != upperbound)
+ for (AliasMap::iterator i = iters.first; i != iters.second; ++i)
{
if (i->second.UserCommand)
{
@@ -174,29 +161,27 @@ class ModuleAlias : public Module
return MOD_RES_DENY;
}
}
-
- i++;
}
// If we made it here, no aliases actually matched.
return MOD_RES_PASSTHRU;
}
- virtual void OnUserMessage(User *user, void *dest, int target_type, const std::string &text, char status, const CUList &exempt_list)
+ void OnUserMessage(User *user, void *dest, int target_type, const std::string &text, char status, const CUList &exempt_list, MessageType msgtype) CXX11_OVERRIDE
{
- if (target_type != TYPE_CHANNEL)
+ if ((target_type != TYPE_CHANNEL) || (msgtype != MSG_PRIVMSG))
{
return;
}
// fcommands are only for local users. Spanningtree will send them back out as their original cmd.
- if (!user || !IS_LOCAL(user))
+ if (!IS_LOCAL(user))
{
return;
}
/* Stop here if the user is +B and allowbot is set to no. */
- if (!AllowBots && user->IsModeSet('B'))
+ if (!AllowBots && user->IsModeSet(botmode))
{
return;
}
@@ -207,37 +192,31 @@ class ModuleAlias : public Module
// text is like "!moo cows bite me", we want "!moo" first
irc::spacesepstream ss(text);
ss.GetToken(scommand);
- irc::string fcommand = scommand.c_str();
- if (fcommand.empty())
+ if (scommand.empty())
{
return; // wtfbbq
}
// we don't want to touch non-fantasy stuff
- if (*fcommand.c_str() != fprefix)
+ if (*scommand.c_str() != fprefix)
{
return;
}
// nor do we give a shit about the prefix
- fcommand.erase(fcommand.begin());
+ scommand.erase(scommand.begin());
- std::multimap<irc::string, Alias>::iterator i = Aliases.find(fcommand);
-
- if (i == Aliases.end())
+ std::pair<AliasMap::iterator, AliasMap::iterator> iters = Aliases.equal_range(scommand);
+ if (iters.first == iters.second)
return;
- /* Avoid iterating on to other aliases if no patterns match */
- std::multimap<irc::string, Alias>::iterator upperbound = Aliases.upper_bound(fcommand);
-
-
/* The parameters for the command in their original form, with the command stripped off */
- std::string compare = text.substr(fcommand.length() + 1);
+ std::string compare = text.substr(scommand.length() + 1);
while (*(compare.c_str()) == ' ')
compare.erase(compare.begin());
- while (i != upperbound)
+ for (AliasMap::iterator i = iters.first; i != iters.second; ++i)
{
if (i->second.ChannelCommand)
{
@@ -245,16 +224,12 @@ class ModuleAlias : public Module
if (DoAlias(user, c, &(i->second), compare, text.substr(1)))
return;
}
-
- i++;
}
}
int DoAlias(User *user, Channel *c, Alias *a, const std::string& compare, const std::string& safe)
{
- User *u = NULL;
-
/* Does it match the pattern? */
if (!a->format.empty())
{
@@ -270,24 +245,22 @@ class ModuleAlias : public Module
}
}
- if ((a->OperOnly) && (!IS_OPER(user)))
+ if ((a->OperOnly) && (!user->IsOper()))
return 0;
if (!a->RequiredNick.empty())
{
- u = ServerInstance->FindNick(a->RequiredNick);
+ User* u = ServerInstance->FindNick(a->RequiredNick);
if (!u)
{
- user->WriteNumeric(401, ""+user->nick+" "+a->RequiredNick+" :is currently unavailable. Please try again later.");
+ user->WriteNumeric(ERR_NOSUCHNICK, a->RequiredNick + " :is currently unavailable. Please try again later.");
return 1;
}
- }
- if ((u != NULL) && (!a->RequiredNick.empty()) && (a->ULineOnly))
- {
- if (!ServerInstance->ULine(u->server))
+
+ if ((a->ULineOnly) && (!u->server->IsULine()))
{
- ServerInstance->SNO->WriteToSnoMask('a', "NOTICE -- Service "+a->RequiredNick+" required by alias "+std::string(a->AliasedCommand.c_str())+" is not on a u-lined server, possibly underhanded antics detected!");
- user->WriteNumeric(401, ""+user->nick+" "+a->RequiredNick+" :is an imposter! Please inform an IRC operator as soon as possible.");
+ ServerInstance->SNO->WriteToSnoMask('a', "NOTICE -- Service "+a->RequiredNick+" required by alias "+a->AliasedCommand+" is not on a u-lined server, possibly underhanded antics detected!");
+ user->WriteNumeric(ERR_NOSUCHNICK, a->RequiredNick + " :is an imposter! Please inform an IRC operator as soon as possible.");
return 1;
}
}
@@ -316,7 +289,7 @@ class ModuleAlias : public Module
void DoCommand(const std::string& newline, User* user, Channel *chan, const std::string &original_line)
{
std::string result;
- result.reserve(MAXBUF);
+ result.reserve(newline.length());
for (unsigned int i = 0; i < newline.length(); i++)
{
char c = newline[i];
@@ -329,28 +302,28 @@ class ModuleAlias : public Module
result.append(GetVar(var, original_line));
i += len - 1;
}
- else if (newline.substr(i, 5) == "$nick")
+ else if (!newline.compare(i, 5, "$nick", 5))
{
result.append(user->nick);
i += 4;
}
- else if (newline.substr(i, 5) == "$host")
+ else if (!newline.compare(i, 5, "$host", 5))
{
result.append(user->host);
i += 4;
}
- else if (newline.substr(i, 5) == "$chan")
+ else if (!newline.compare(i, 5, "$chan", 5))
{
if (chan)
result.append(chan->name);
i += 4;
}
- else if (newline.substr(i, 6) == "$ident")
+ else if (!newline.compare(i, 6, "$ident", 6))
{
result.append(user->ident);
i += 5;
}
- else if (newline.substr(i, 6) == "$vhost")
+ else if (!newline.compare(i, 6, "$vhost", 6))
{
result.append(user->dhost);
i += 5;
@@ -367,19 +340,14 @@ class ModuleAlias : public Module
std::string command, token;
ss.GetToken(command);
- while (ss.GetToken(token) && (pars.size() <= MAXPARAMETERS))
+ while (ss.GetToken(token))
{
pars.push_back(token);
}
- ServerInstance->Parser->CallHandler(command, pars, user);
+ ServerInstance->Parser.CallHandler(command, pars, user);
}
- virtual void OnRehash(User* user)
- {
- ReadAliases();
- }
-
- virtual void Prioritize()
+ void Prioritize()
{
// Prioritise after spanningtree so that channel aliases show the alias before the effects.
Module* linkmod = ServerInstance->Modules->Find("m_spanningtree.so");
diff --git a/src/modules/m_allowinvite.cpp b/src/modules/m_allowinvite.cpp
index 08a5f542a..05e76113a 100644
--- a/src/modules/m_allowinvite.cpp
+++ b/src/modules/m_allowinvite.cpp
@@ -19,8 +19,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides support for channel mode +A, allowing /invite freely on a channel and extban A to deny specific users it */
-
class AllowInvite : public SimpleChannelModeHandler
{
public:
@@ -36,19 +34,12 @@ class ModuleAllowInvite : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(ni);
- Implementation eventlist[] = { I_OnUserPreInvite, I_On005Numeric };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- virtual void On005Numeric(std::string &output)
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
- ServerInstance->AddExtBanChar('A');
+ tokens["EXTBAN"].push_back('A');
}
- virtual ModResult OnUserPreInvite(User* user,User* dest,Channel* channel, time_t timeout)
+ ModResult OnUserPreInvite(User* user,User* dest,Channel* channel, time_t timeout) CXX11_OVERRIDE
{
if (IS_LOCAL(user))
{
@@ -56,10 +47,10 @@ class ModuleAllowInvite : public Module
if (res == MOD_RES_DENY)
{
// Matching extban, explicitly deny /invite
- user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You are banned from using INVITE", user->nick.c_str(), channel->name.c_str());
+ user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s :You are banned from using INVITE", channel->name.c_str());
return res;
}
- if (channel->IsModeSet('A') || res == MOD_RES_ALLOW)
+ if (channel->IsModeSet(ni) || res == MOD_RES_ALLOW)
{
// Explicitly allow /invite
return MOD_RES_ALLOW;
@@ -69,11 +60,7 @@ class ModuleAllowInvite : public Module
return MOD_RES_PASSTHRU;
}
- virtual ~ModuleAllowInvite()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for channel mode +A, allowing /invite freely on a channel and extban A to deny specific users it",VF_VENDOR);
}
diff --git a/src/modules/m_alltime.cpp b/src/modules/m_alltime.cpp
index 38ae4b254..075064c62 100644
--- a/src/modules/m_alltime.cpp
+++ b/src/modules/m_alltime.cpp
@@ -21,22 +21,17 @@
#include "inspircd.h"
-/* $ModDesc: Display timestamps from all servers connected to the network */
-
class CommandAlltime : public Command
{
public:
CommandAlltime(Module* Creator) : Command(Creator, "ALLTIME", 0)
{
flags_needed = 'o';
- translation.push_back(TR_END);
}
CmdResult Handle(const std::vector<std::string> &parameters, User *user)
{
- char fmtdate[64];
- time_t now = ServerInstance->Time();
- strftime(fmtdate, sizeof(fmtdate), "%Y-%m-%d %H:%M:%S", gmtime(&now));
+ const std::string fmtdate = InspIRCd::TimeString(ServerInstance->Time(), "%Y-%m-%d %H:%M:%S", true);
std::string msg = ":" + ServerInstance->Config->ServerName + " NOTICE " + user->nick + " :System time is " + fmtdate + " (" + ConvToStr(ServerInstance->Time()) + ") on " + ServerInstance->Config->ServerName;
@@ -52,7 +47,6 @@ class CommandAlltime : public Command
}
};
-
class Modulealltime : public Module
{
CommandAlltime mycommand;
@@ -62,16 +56,7 @@ class Modulealltime : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(mycommand);
- }
-
- virtual ~Modulealltime()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Display timestamps from all servers connected to the network", VF_OPTCOMMON | VF_VENDOR);
}
diff --git a/src/modules/m_auditorium.cpp b/src/modules/m_auditorium.cpp
index 2a8edb9d4..7ad7ba1a3 100644
--- a/src/modules/m_auditorium.cpp
+++ b/src/modules/m_auditorium.cpp
@@ -22,55 +22,28 @@
#include "inspircd.h"
-/* $ModDesc: Allows for auditorium channels (+u) where nobody can see others joining and parting or the nick list */
-
-class AuditoriumMode : public ModeHandler
+class AuditoriumMode : public SimpleChannelModeHandler
{
public:
- AuditoriumMode(Module* Creator) : ModeHandler(Creator, "auditorium", 'u', PARAM_NONE, MODETYPE_CHANNEL)
+ AuditoriumMode(Module* Creator) : SimpleChannelModeHandler(Creator, "auditorium", 'u')
{
levelrequired = OP_VALUE;
}
-
- ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
- {
- if (channel->IsModeSet(this) == adding)
- return MODEACTION_DENY;
- channel->SetMode(this, adding);
- return MODEACTION_ALLOW;
- }
};
class ModuleAuditorium : public Module
{
- private:
AuditoriumMode aum;
bool OpsVisible;
bool OpsCanSee;
bool OperCanSee;
+
public:
ModuleAuditorium() : aum(this)
{
}
- void init()
- {
- ServerInstance->Modules->AddService(aum);
-
- OnRehash(NULL);
-
- Implementation eventlist[] = {
- I_OnUserJoin, I_OnUserPart, I_OnUserKick,
- I_OnBuildNeighborList, I_OnNamesListItem, I_OnSendWhoLine,
- I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- ~ModuleAuditorium()
- {
- }
-
- void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ConfigTag* tag = ServerInstance->Config->ConfValue("auditorium");
OpsVisible = tag->getBool("opvisible");
@@ -78,7 +51,7 @@ class ModuleAuditorium : public Module
OperCanSee = tag->getBool("opercansee", true);
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Allows for auditorium channels (+u) where nobody can see others joining and parting or the nick list", VF_VENDOR);
}
@@ -112,19 +85,16 @@ class ModuleAuditorium : public Module
return false;
}
- void OnNamesListItem(User* issuer, Membership* memb, std::string &prefixes, std::string &nick)
+ ModResult OnNamesListItem(User* issuer, Membership* memb, std::string& prefixes, std::string& nick) CXX11_OVERRIDE
{
- // Some module already hid this from being displayed, don't bother
- if (nick.empty())
- return;
-
if (IsVisible(memb))
- return;
+ return MOD_RES_PASSTHRU;
if (CanSee(issuer, memb))
- return;
+ return MOD_RES_PASSTHRU;
- nick.clear();
+ // Don't display this user in the NAMES list
+ return MOD_RES_DENY;
}
/** Build CUList for showing this join/part/kick */
@@ -133,43 +103,45 @@ class ModuleAuditorium : public Module
if (IsVisible(memb))
return;
- const UserMembList* users = memb->chan->GetUsers();
- for(UserMembCIter i = users->begin(); i != users->end(); i++)
+ const Channel::MemberMap& users = memb->chan->GetUsers();
+ for (Channel::MemberMap::const_iterator i = users.begin(); i != users.end(); ++i)
{
if (IS_LOCAL(i->first) && !CanSee(i->first, memb))
excepts.insert(i->first);
}
}
- void OnUserJoin(Membership* memb, bool sync, bool created, CUList& excepts)
+ void OnUserJoin(Membership* memb, bool sync, bool created, CUList& excepts) CXX11_OVERRIDE
{
BuildExcept(memb, excepts);
}
- void OnUserPart(Membership* memb, std::string &partmessage, CUList& excepts)
+ void OnUserPart(Membership* memb, std::string &partmessage, CUList& excepts) CXX11_OVERRIDE
{
BuildExcept(memb, excepts);
}
- void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& excepts)
+ void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& excepts) CXX11_OVERRIDE
{
BuildExcept(memb, excepts);
}
- void OnBuildNeighborList(User* source, UserChanList &include, std::map<User*,bool> &exception)
+ void OnBuildNeighborList(User* source, IncludeChanList& include, std::map<User*, bool>& exception) CXX11_OVERRIDE
{
- UCListIter i = include.begin();
- while (i != include.end())
+ for (IncludeChanList::iterator i = include.begin(); i != include.end(); )
{
- Channel* c = *i++;
- Membership* memb = c->GetUser(source);
- if (!memb || IsVisible(memb))
+ Membership* memb = *i;
+ if (IsVisible(memb))
+ {
+ ++i;
continue;
+ }
+
// this channel should not be considered when listing my neighbors
- include.erase(c);
+ i = include.erase(i);
// however, that might hide me from ops that can see me...
- const UserMembList* users = c->GetUsers();
- for(UserMembCIter j = users->begin(); j != users->end(); j++)
+ const Channel::MemberMap& users = memb->chan->GetUsers();
+ for(Channel::MemberMap::const_iterator j = users.begin(); j != users.end(); ++j)
{
if (IS_LOCAL(j->first) && CanSee(j->first, memb))
exception[j->first] = true;
@@ -177,13 +149,11 @@ class ModuleAuditorium : public Module
}
}
- void OnSendWhoLine(User* source, const std::vector<std::string>& params, User* user, std::string& line)
+ void OnSendWhoLine(User* source, const std::vector<std::string>& params, User* user, Membership* memb, std::string& line) CXX11_OVERRIDE
{
- Channel* channel = ServerInstance->FindChan(params[0]);
- if (!channel)
+ if (!memb)
return;
- Membership* memb = channel->GetUser(user);
- if ((!memb) || (IsVisible(memb)))
+ if (IsVisible(memb))
return;
if (CanSee(source, memb))
return;
diff --git a/src/modules/m_autoop.cpp b/src/modules/m_autoop.cpp
index 0c0e8f579..828bef14c 100644
--- a/src/modules/m_autoop.cpp
+++ b/src/modules/m_autoop.cpp
@@ -19,9 +19,7 @@
#include "inspircd.h"
-#include "u_listmode.h"
-
-/* $ModDesc: Provides support for the +w channel mode, autoop list */
+#include "listmode.h"
/** Handles +w channel mode
*/
@@ -34,17 +32,13 @@ class AutoOpList : public ListModeBase
tidy = false;
}
- ModeHandler* FindMode(const std::string& mid)
+ PrefixMode* FindMode(const std::string& mid)
{
if (mid.length() == 1)
- return ServerInstance->Modes->FindMode(mid[0], MODETYPE_CHANNEL);
- for(char c='A'; c <= 'z'; c++)
- {
- ModeHandler* mh = ServerInstance->Modes->FindMode(c, MODETYPE_CHANNEL);
- if (mh && mh->name == mid)
- return mh;
- }
- return NULL;
+ return ServerInstance->Modes->FindPrefixMode(mid[0]);
+
+ ModeHandler* mh = ServerInstance->Modes->FindMode(mid, MODETYPE_CHANNEL);
+ return mh ? mh->IsPrefixMode() : NULL;
}
ModResult AccessCheck(User* source, Channel* channel, std::string &parameter, bool adding)
@@ -54,12 +48,12 @@ class AutoOpList : public ListModeBase
return adding ? MOD_RES_DENY : MOD_RES_PASSTHRU;
unsigned int mylevel = channel->GetPrefixValue(source);
std::string mid = parameter.substr(0, pos);
- ModeHandler* mh = FindMode(mid);
+ PrefixMode* mh = FindMode(mid);
- if (adding && (!mh || !mh->GetPrefixRank()))
+ if (adding && !mh)
{
- source->WriteNumeric(415, "%s %s :Cannot find prefix mode '%s' for autoop",
- source->nick.c_str(), mid.c_str(), mid.c_str());
+ source->WriteNumeric(415, "%s :Cannot find prefix mode '%s' for autoop",
+ mid.c_str(), mid.c_str());
return MOD_RES_DENY;
}
else if (!mh)
@@ -70,8 +64,8 @@ class AutoOpList : public ListModeBase
return MOD_RES_DENY;
if (mh->GetLevelRequired() > mylevel)
{
- source->WriteNumeric(482, "%s %s :You must be able to set mode '%s' to include it in an autoop",
- source->nick.c_str(), channel->name.c_str(), mid.c_str());
+ source->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s :You must be able to set mode '%s' to include it in an autoop",
+ channel->name.c_str(), mid.c_str());
return MOD_RES_DENY;
}
return MOD_RES_PASSTHRU;
@@ -82,40 +76,31 @@ class ModuleAutoOp : public Module
{
AutoOpList mh;
-public:
+ public:
ModuleAutoOp() : mh(this)
{
}
- void init()
- {
- ServerInstance->Modules->AddService(mh);
- mh.DoImplements(this);
-
- Implementation list[] = { I_OnPostJoin, };
- ServerInstance->Modules->Attach(list, this, sizeof(list)/sizeof(Implementation));
- }
-
- void OnPostJoin(Membership *memb)
+ void OnPostJoin(Membership *memb) CXX11_OVERRIDE
{
if (!IS_LOCAL(memb->user))
return;
- modelist* list = mh.extItem.get(memb->chan);
+ ListModeBase::ModeList* list = mh.GetList(memb->chan);
if (list)
{
std::string modeline("+");
std::vector<std::string> modechange;
modechange.push_back(memb->chan->name);
- for (modelist::iterator it = list->begin(); it != list->end(); it++)
+ for (ListModeBase::ModeList::iterator it = list->begin(); it != list->end(); it++)
{
std::string::size_type colon = it->mask.find(':');
if (colon == std::string::npos)
continue;
if (memb->chan->CheckBan(memb->user, it->mask.substr(colon+1)))
{
- ModeHandler* given = mh.FindMode(it->mask.substr(0, colon));
- if (given && given->GetPrefixRank())
+ PrefixMode* given = mh.FindMode(it->mask.substr(0, colon));
+ if (given)
modeline.push_back(given->GetModeChar());
}
}
@@ -123,21 +108,16 @@ public:
for(std::string::size_type i = modeline.length(); i > 1; --i) // we use "i > 1" instead of "i" so we skip the +
modechange.push_back(memb->user->nick);
if(modechange.size() >= 3)
- ServerInstance->SendGlobalMode(modechange, ServerInstance->FakeClient);
+ ServerInstance->Modes->Process(modechange, ServerInstance->FakeClient);
}
}
- void OnSyncChannel(Channel* chan, Module* proto, void* opaque)
- {
- mh.DoSyncChannel(chan, proto, opaque);
- }
-
- void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
mh.DoRehash();
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for the +w channel mode", VF_VENDOR);
}
diff --git a/src/modules/m_banexception.cpp b/src/modules/m_banexception.cpp
index 1811f743d..b29b39747 100644
--- a/src/modules/m_banexception.cpp
+++ b/src/modules/m_banexception.cpp
@@ -22,10 +22,7 @@
#include "inspircd.h"
-#include "u_listmode.h"
-
-/* $ModDesc: Provides support for the +e channel mode */
-/* $ModDep: ../../include/u_listmode.h */
+#include "listmode.h"
/* Written by Om<om@inspircd.org>, April 2005. */
/* Rewritten to use the listmode utility by Om, December 2005 */
@@ -49,85 +46,63 @@ class ModuleBanException : public Module
{
BanException be;
-public:
+ public:
ModuleBanException() : be(this)
{
}
- void init()
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
- ServerInstance->Modules->AddService(be);
-
- be.DoImplements(this);
- Implementation list[] = { I_OnRehash, I_On005Numeric, I_OnExtBanCheck, I_OnCheckChannelBan };
- ServerInstance->Modules->Attach(list, this, sizeof(list)/sizeof(Implementation));
+ tokens["EXCEPTS"] = "e";
}
- void On005Numeric(std::string &output)
+ ModResult OnExtBanCheck(User *user, Channel *chan, char type) CXX11_OVERRIDE
{
- output.append(" EXCEPTS=e");
- }
+ ListModeBase::ModeList* list = be.GetList(chan);
+ if (!list)
+ return MOD_RES_PASSTHRU;
- ModResult OnExtBanCheck(User *user, Channel *chan, char type)
- {
- if (chan != NULL)
+ for (ListModeBase::ModeList::iterator it = list->begin(); it != list->end(); it++)
{
- modelist *list = be.extItem.get(chan);
-
- if (!list)
- return MOD_RES_PASSTHRU;
+ if (it->mask[0] != type || it->mask[1] != ':')
+ continue;
- for (modelist::iterator it = list->begin(); it != list->end(); it++)
+ if (chan->CheckBan(user, it->mask.substr(2)))
{
- if (it->mask[0] != type || it->mask[1] != ':')
- continue;
-
- if (chan->CheckBan(user, it->mask.substr(2)))
- {
- // They match an entry on the list, so let them pass this.
- return MOD_RES_ALLOW;
- }
+ // They match an entry on the list, so let them pass this.
+ return MOD_RES_ALLOW;
}
}
return MOD_RES_PASSTHRU;
}
- ModResult OnCheckChannelBan(User* user, Channel* chan)
+ ModResult OnCheckChannelBan(User* user, Channel* chan) CXX11_OVERRIDE
{
- if (chan)
+ ListModeBase::ModeList* list = be.GetList(chan);
+ if (!list)
{
- modelist *list = be.extItem.get(chan);
-
- if (!list)
- {
- // No list, proceed normally
- return MOD_RES_PASSTHRU;
- }
+ // No list, proceed normally
+ return MOD_RES_PASSTHRU;
+ }
- for (modelist::iterator it = list->begin(); it != list->end(); it++)
+ for (ListModeBase::ModeList::iterator it = list->begin(); it != list->end(); it++)
+ {
+ if (chan->CheckBan(user, it->mask))
{
- if (chan->CheckBan(user, it->mask))
- {
- // They match an entry on the list, so let them in.
- return MOD_RES_ALLOW;
- }
+ // They match an entry on the list, so let them in.
+ return MOD_RES_ALLOW;
}
}
return MOD_RES_PASSTHRU;
}
- void OnSyncChannel(Channel* chan, Module* proto, void* opaque)
- {
- be.DoSyncChannel(chan, proto, opaque);
- }
-
- void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
be.DoRehash();
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for the +e channel mode", VF_VENDOR);
}
diff --git a/src/modules/m_banredirect.cpp b/src/modules/m_banredirect.cpp
index 2e2592541..1a123e580 100644
--- a/src/modules/m_banredirect.cpp
+++ b/src/modules/m_banredirect.cpp
@@ -23,9 +23,7 @@
#include "inspircd.h"
-#include "u_listmode.h"
-
-/* $ModDesc: Allows an extended ban (+b) syntax redirecting banned users to another channel */
+#include "listmode.h"
/* Originally written by Om, January 2009
*/
@@ -43,18 +41,20 @@ class BanRedirectEntry
};
typedef std::vector<BanRedirectEntry> BanRedirectList;
-typedef std::deque<std::string> StringDeque;
class BanRedirect : public ModeWatcher
{
+ ChanModeReference ban;
public:
SimpleExtItem<BanRedirectList> extItem;
- BanRedirect(Module* parent) : ModeWatcher(parent, 'b', MODETYPE_CHANNEL),
- extItem("banredirect", parent)
+ BanRedirect(Module* parent)
+ : ModeWatcher(parent, "ban", MODETYPE_CHANNEL)
+ , ban(parent, "ban")
+ , extItem("banredirect", parent)
{
}
- bool BeforeMode(User* source, User* dest, Channel* channel, std::string &param, bool adding, ModeType type)
+ bool BeforeMode(User* source, User* dest, Channel* channel, std::string &param, bool adding)
{
/* nick!ident@host -> nick!ident@host
* nick!ident@host#chan -> nick!ident@host#chan
@@ -63,21 +63,23 @@ class BanRedirect : public ModeWatcher
* nick#chan -> nick!*@*#chan
*/
- if(channel && (type == MODETYPE_CHANNEL) && param.length())
+ if ((channel) && !param.empty())
{
BanRedirectList* redirects;
std::string mask[4];
enum { NICK, IDENT, HOST, CHAN } current = NICK;
std::string::iterator start_pos = param.begin();
- long maxbans = channel->GetMaxBans();
if (param.length() >= 2 && param[1] == ':')
return true;
- if(adding && (channel->bans.size() > static_cast<unsigned>(maxbans)))
+ ListModeBase* banlm = static_cast<ListModeBase*>(*ban);
+ unsigned int maxbans = banlm->GetLimit(channel);
+ ListModeBase::ModeList* list = banlm->GetList(channel);
+ if ((list) && (adding) && (maxbans <= list->size()))
{
- source->WriteNumeric(478, "%s %s :Channel ban list for %s is full (maximum entries for this channel is %ld)", source->nick.c_str(), channel->name.c_str(), channel->name.c_str(), maxbans);
+ source->WriteNumeric(ERR_BANLISTFULL, "%s :Channel ban list for %s is full (maximum entries for this channel is %u)", channel->name.c_str(), channel->name.c_str(), maxbans);
return false;
}
@@ -86,23 +88,25 @@ class BanRedirect : public ModeWatcher
switch(*curr)
{
case '!':
+ if (current != NICK)
+ break;
mask[current].assign(start_pos, curr);
current = IDENT;
start_pos = curr+1;
break;
case '@':
+ if (current != IDENT)
+ break;
mask[current].assign(start_pos, curr);
current = HOST;
start_pos = curr+1;
break;
case '#':
- /* bug #921: don't barf when redirecting to ## channels */
- if (current != CHAN)
- {
- mask[current].assign(start_pos, curr);
- current = CHAN;
- start_pos = curr;
- }
+ if (current == CHAN)
+ break;
+ mask[current].assign(start_pos, curr);
+ current = CHAN;
+ start_pos = curr;
break;
}
}
@@ -133,27 +137,27 @@ class BanRedirect : public ModeWatcher
{
if (adding && IS_LOCAL(source))
{
- if (!ServerInstance->IsChannel(mask[CHAN].c_str(), ServerInstance->Config->Limits.ChanMax))
+ if (!ServerInstance->IsChannel(mask[CHAN]))
{
- source->WriteNumeric(403, "%s %s :Invalid channel name in redirection (%s)", source->nick.c_str(), channel->name.c_str(), mask[CHAN].c_str());
+ source->WriteNumeric(ERR_NOSUCHCHANNEL, "%s :Invalid channel name in redirection (%s)", channel->name.c_str(), mask[CHAN].c_str());
return false;
}
Channel *c = ServerInstance->FindChan(mask[CHAN]);
if (!c)
{
- source->WriteNumeric(690, "%s :Target channel %s must exist to be set as a redirect.",source->nick.c_str(),mask[CHAN].c_str());
+ source->WriteNumeric(690, ":Target channel %s must exist to be set as a redirect.", mask[CHAN].c_str());
return false;
}
else if (adding && c->GetPrefixValue(source) < OP_VALUE)
{
- source->WriteNumeric(690, "%s :You must be opped on %s to set it as a redirect.",source->nick.c_str(), mask[CHAN].c_str());
+ source->WriteNumeric(690, ":You must be opped on %s to set it as a redirect.", mask[CHAN].c_str());
return false;
}
if (assign(channel->name) == mask[CHAN])
{
- source->WriteNumeric(690, "%s %s :You cannot set a ban redirection to the channel the ban is on", source->nick.c_str(), channel->name.c_str());
+ source->WriteNumeric(690, "%s :You cannot set a ban redirection to the channel the ban is on", channel->name.c_str());
return false;
}
}
@@ -213,26 +217,19 @@ class ModuleBanRedirect : public Module
{
BanRedirect re;
bool nofollow;
+ ChanModeReference limitmode;
+ ChanModeReference redirectmode;
public:
ModuleBanRedirect()
- : re(this)
- {
- nofollow = false;
- }
-
-
- void init()
+ : re(this)
+ , nofollow(false)
+ , limitmode(this, "limit")
+ , redirectmode(this, "redirect")
{
- if(!ServerInstance->Modes->AddModeWatcher(&re))
- throw ModuleException("Could not add mode watcher");
-
- ServerInstance->Modules->AddService(re.extItem);
- Implementation list[] = { I_OnUserPreJoin };
- ServerInstance->Modules->Attach(list, this, sizeof(list)/sizeof(Implementation));
}
- virtual void OnCleanup(int target_type, void* item)
+ void OnCleanup(int target_type, void* item) CXX11_OVERRIDE
{
if(target_type == TYPE_CHANNEL)
{
@@ -242,9 +239,6 @@ class ModuleBanRedirect : public Module
if(redirects)
{
irc::modestacker modestack(false);
- StringDeque stackresult;
- std::vector<std::string> mode_junk;
- mode_junk.push_back(chan->name);
for(BanRedirectList::iterator i = redirects->begin(); i != redirects->end(); i++)
{
@@ -257,17 +251,18 @@ class ModuleBanRedirect : public Module
modestack.Push('b', i->banmask);
}
- while(modestack.GetStackedLine(stackresult))
+ std::vector<std::string> stackresult;
+ stackresult.push_back(chan->name);
+ while (modestack.GetStackedLine(stackresult))
{
- mode_junk.insert(mode_junk.end(), stackresult.begin(), stackresult.end());
- ServerInstance->SendMode(mode_junk, ServerInstance->FakeClient);
- mode_junk.erase(mode_junk.begin() + 1, mode_junk.end());
+ ServerInstance->Modes->Process(stackresult, ServerInstance->FakeClient, ModeParser::MODE_LOCALONLY);
+ stackresult.erase(stackresult.begin() + 1, stackresult.end());
}
}
}
}
- virtual ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven)
+ ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE
{
if (chan)
{
@@ -311,19 +306,19 @@ class ModuleBanRedirect : public Module
std::string destlimit;
if (destchan)
- destlimit = destchan->GetModeParameter('l');
+ destlimit = destchan->GetModeParameter(limitmode);
- if(destchan && ServerInstance->Modules->Find("m_redirect.so") && destchan->IsModeSet('L') && !destlimit.empty() && (destchan->GetUserCounter() >= atoi(destlimit.c_str())))
+ if(destchan && destchan->IsModeSet(redirectmode) && !destlimit.empty() && (destchan->GetUserCounter() >= atoi(destlimit.c_str())))
{
- user->WriteNumeric(474, "%s %s :Cannot join channel (You are banned)", user->nick.c_str(), chan->name.c_str());
+ user->WriteNumeric(ERR_BANNEDFROMCHAN, "%s :Cannot join channel (You are banned)", chan->name.c_str());
return MOD_RES_DENY;
}
else
{
- user->WriteNumeric(474, "%s %s :Cannot join channel (You are banned)", user->nick.c_str(), chan->name.c_str());
- user->WriteNumeric(470, "%s %s %s :You are banned from this channel, so you are automatically transferred to the redirected channel.", user->nick.c_str(), chan->name.c_str(), redir->targetchan.c_str());
+ user->WriteNumeric(ERR_BANNEDFROMCHAN, "%s :Cannot join channel (You are banned)", chan->name.c_str());
+ user->WriteNumeric(470, "%s %s :You are banned from this channel, so you are automatically transferred to the redirected channel.", chan->name.c_str(), redir->targetchan.c_str());
nofollow = true;
- Channel::JoinUser(user, redir->targetchan.c_str(), false, "", false, ServerInstance->Time());
+ Channel::JoinUser(user, redir->targetchan);
nofollow = false;
return MOD_RES_DENY;
}
@@ -334,14 +329,7 @@ class ModuleBanRedirect : public Module
return MOD_RES_PASSTHRU;
}
- virtual ~ModuleBanRedirect()
- {
- /* XXX is this the best place to do this? */
- if (!ServerInstance->Modes->DelModeWatcher(&re))
- ServerInstance->Logs->Log("m_banredirect.so", DEBUG, "Failed to delete modewatcher!");
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Allows an extended ban (+b) syntax redirecting banned users to another channel", VF_COMMON|VF_VENDOR);
}
diff --git a/src/modules/m_blockamsg.cpp b/src/modules/m_blockamsg.cpp
index be861447f..833828233 100644
--- a/src/modules/m_blockamsg.cpp
+++ b/src/modules/m_blockamsg.cpp
@@ -23,8 +23,6 @@
#include "inspircd.h"
-/* $ModDesc: Attempt to block /amsg, at least some of the irritating mIRC scripts. */
-
enum BlockAction { IBLOCK_KILL, IBLOCK_KILLOPERS, IBLOCK_NOTICE, IBLOCK_NOTICEOPERS, IBLOCK_SILENT };
/* IBLOCK_NOTICE - Send a notice to the user informing them of what happened.
* IBLOCK_NOTICEOPERS - Send a notice to the user informing them and send an oper notice.
@@ -37,7 +35,7 @@ enum BlockAction { IBLOCK_KILL, IBLOCK_KILLOPERS, IBLOCK_NOTICE, IBLOCK_NOTICEOP
*/
class BlockedMessage
{
-public:
+ public:
std::string message;
irc::string target;
time_t sent;
@@ -59,24 +57,12 @@ class ModuleBlockAmsg : public Module
{
}
- void init()
- {
- this->OnRehash(NULL);
- ServerInstance->Modules->AddService(blockamsg);
- Implementation eventlist[] = { I_OnRehash, I_OnPreCommand };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- virtual ~ModuleBlockAmsg()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Attempt to block /amsg, at least some of the irritating mIRC scripts.",VF_VENDOR);
}
- virtual void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ConfigTag* tag = ServerInstance->Config->ConfValue("blockamsg");
ForgetDelay = tag->getInt("delay", -1);
@@ -94,7 +80,7 @@ class ModuleBlockAmsg : public Module
action = IBLOCK_KILLOPERS;
}
- virtual ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line)
+ ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line) CXX11_OVERRIDE
{
// Don't do anything with unregistered users
if (user->registered != REG_ALL)
@@ -169,5 +155,4 @@ class ModuleBlockAmsg : public Module
}
};
-
MODULE_INIT(ModuleBlockAmsg)
diff --git a/src/modules/m_blockcaps.cpp b/src/modules/m_blockcaps.cpp
index 200693699..0a64a75b5 100644
--- a/src/modules/m_blockcaps.cpp
+++ b/src/modules/m_blockcaps.cpp
@@ -22,8 +22,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides support to block all-CAPS channel messages and notices */
-
/** Handles the +B channel mode
*/
@@ -36,34 +34,21 @@ class BlockCaps : public SimpleChannelModeHandler
class ModuleBlockCAPS : public Module
{
BlockCaps bc;
- int percent;
+ unsigned int percent;
unsigned int minlen;
char capsmap[256];
-public:
+public:
ModuleBlockCAPS() : bc(this)
{
}
- void init()
- {
- OnRehash(NULL);
- ServerInstance->Modules->AddService(bc);
- Implementation eventlist[] = { I_OnUserPreMessage, I_OnUserPreNotice, I_OnRehash, I_On005Numeric };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- virtual void On005Numeric(std::string &output)
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
- ServerInstance->AddExtBanChar('B');
+ tokens["EXTBAN"].push_back('B');
}
- virtual void OnRehash(User* user)
- {
- ReadConf();
- }
-
- virtual ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+ ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE
{
if (target_type == TYPE_CHANNEL)
{
@@ -76,28 +61,20 @@ public:
if (res == MOD_RES_ALLOW)
return MOD_RES_PASSTHRU;
- if (!c->GetExtBanStatus(user, 'B').check(!c->IsModeSet('B')))
+ if (!c->GetExtBanStatus(user, 'B').check(!c->IsModeSet(bc)))
{
- int caps = 0;
- const char* actstr = "\1ACTION ";
- int act = 0;
-
- for (std::string::iterator i = text.begin(); i != text.end(); i++)
- {
- /* Smart fix for suggestion from Jobe, ignore CTCP ACTION (part of /ME) */
- if (*actstr && *i == *actstr++ && act != -1)
- {
- act++;
- continue;
- }
- else
- act = -1;
+ std::string::size_type caps = 0;
+ unsigned int offset = 0;
+ // Ignore the beginning of the text if it's a CTCP ACTION (/me)
+ if (!text.compare(0, 8, "\1ACTION ", 8))
+ offset = 8;
+ for (std::string::const_iterator i = text.begin() + offset; i != text.end(); ++i)
caps += capsmap[(unsigned char)*i];
- }
- if ( ((caps*100)/(int)text.length()) >= percent )
+
+ if (((caps * 100) / text.length()) >= percent)
{
- user->WriteNumeric(ERR_CANNOTSENDTOCHAN, "%s %s :Your message cannot contain more than %d%% capital letters if it's longer than %d characters", user->nick.c_str(), c->name.c_str(), percent, minlen);
+ user->WriteNumeric(ERR_CANNOTSENDTOCHAN, "%s :Your message cannot contain more than %d%% capital letters if it's longer than %d characters", c->name.c_str(), percent, minlen);
return MOD_RES_DENY;
}
}
@@ -105,37 +82,18 @@ public:
return MOD_RES_PASSTHRU;
}
- virtual ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
- {
- return OnUserPreMessage(user,dest,target_type,text,status,exempt_list);
- }
-
- void ReadConf()
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ConfigTag* tag = ServerInstance->Config->ConfValue("blockcaps");
- percent = tag->getInt("percent", 100);
- minlen = tag->getInt("minlen", 1);
+ percent = tag->getInt("percent", 100, 1, 100);
+ minlen = tag->getInt("minlen", 1, 1, ServerInstance->Config->Limits.MaxLine);
std::string hmap = tag->getString("capsmap", "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
memset(capsmap, 0, sizeof(capsmap));
for (std::string::iterator n = hmap.begin(); n != hmap.end(); n++)
capsmap[(unsigned char)*n] = 1;
- if (percent < 1 || percent > 100)
- {
- ServerInstance->Logs->Log("CONFIG",DEFAULT, "<blockcaps:percent> out of range, setting to default of 100.");
- percent = 100;
- }
- if (minlen < 1 || minlen > MAXBUF-1)
- {
- ServerInstance->Logs->Log("CONFIG",DEFAULT, "<blockcaps:minlen> out of range, setting to default of 1.");
- minlen = 1;
- }
- }
-
- virtual ~ModuleBlockCAPS()
- {
}
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support to block all-CAPS channel messages and notices", VF_VENDOR);
}
diff --git a/src/modules/m_blockcolor.cpp b/src/modules/m_blockcolor.cpp
index 3cc01b4c0..a08ad7c6f 100644
--- a/src/modules/m_blockcolor.cpp
+++ b/src/modules/m_blockcolor.cpp
@@ -23,8 +23,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides channel mode +c to block color */
-
/** Handles the +c channel mode
*/
class BlockColor : public SimpleChannelModeHandler
@@ -42,19 +40,12 @@ class ModuleBlockColor : public Module
{
}
- void init()
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
- ServerInstance->Modules->AddService(bc);
- Implementation eventlist[] = { I_OnUserPreMessage, I_OnUserPreNotice, I_On005Numeric };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
+ tokens["EXTBAN"].push_back('c');
}
- virtual void On005Numeric(std::string &output)
- {
- ServerInstance->AddExtBanChar('c');
- }
-
- virtual ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+ ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE
{
if ((target_type == TYPE_CHANNEL) && (IS_LOCAL(user)))
{
@@ -64,7 +55,7 @@ class ModuleBlockColor : public Module
if (res == MOD_RES_ALLOW)
return MOD_RES_PASSTHRU;
- if (!c->GetExtBanStatus(user, 'c').check(!c->IsModeSet('c')))
+ if (!c->GetExtBanStatus(user, 'c').check(!c->IsModeSet(bc)))
{
for (std::string::iterator i = text.begin(); i != text.end(); i++)
{
@@ -76,7 +67,7 @@ class ModuleBlockColor : public Module
case 21:
case 22:
case 31:
- user->WriteNumeric(404, "%s %s :Can't send colors to channel (+c set)",user->nick.c_str(), c->name.c_str());
+ user->WriteNumeric(ERR_CANNOTSENDTOCHAN, "%s :Can't send colors to channel (+c set)", c->name.c_str());
return MOD_RES_DENY;
break;
}
@@ -86,16 +77,7 @@ class ModuleBlockColor : public Module
return MOD_RES_PASSTHRU;
}
- virtual ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
- {
- return OnUserPreMessage(user,dest,target_type,text,status,exempt_list);
- }
-
- virtual ~ModuleBlockColor()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides channel mode +c to block color",VF_VENDOR);
}
diff --git a/src/modules/m_botmode.cpp b/src/modules/m_botmode.cpp
index b29c58240..67f692b86 100644
--- a/src/modules/m_botmode.cpp
+++ b/src/modules/m_botmode.cpp
@@ -21,8 +21,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides user mode +B to mark the user as a bot */
-
/** Handles user mode +B
*/
class BotMode : public SimpleUserModeHandler
@@ -40,31 +38,18 @@ class ModuleBotMode : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(bm);
- Implementation eventlist[] = { I_OnWhois };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- virtual ~ModuleBotMode()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides user mode +B to mark the user as a bot",VF_VENDOR);
}
- virtual void OnWhois(User* src, User* dst)
+ void OnWhois(User* src, User* dst) CXX11_OVERRIDE
{
- if (dst->IsModeSet('B'))
+ if (dst->IsModeSet(bm))
{
- ServerInstance->SendWhoisLine(src, dst, 335, src->nick+" "+dst->nick+" :is a bot on "+ServerInstance->Config->Network);
+ ServerInstance->SendWhoisLine(src, dst, 335, dst->nick+" :is a bot on "+ServerInstance->Config->Network);
}
}
-
};
-
MODULE_INIT(ModuleBotMode)
diff --git a/src/modules/m_callerid.cpp b/src/modules/m_callerid.cpp
index 4147f0b16..f15760dca 100644
--- a/src/modules/m_callerid.cpp
+++ b/src/modules/m_callerid.cpp
@@ -22,7 +22,17 @@
#include "inspircd.h"
-/* $ModDesc: Implementation of callerid, usermode +g, /accept */
+enum
+{
+ RPL_ACCEPTLIST = 281,
+ RPL_ENDOFACCEPT = 282,
+ ERR_ACCEPTFULL = 456,
+ ERR_ACCEPTEXIST = 457,
+ ERR_ACCEPTNOT = 458,
+ ERR_TARGUMODEG = 716,
+ RPL_TARGNOTIFY = 717,
+ RPL_UMODEGMSG = 718
+};
class callerid_data
{
@@ -62,12 +72,20 @@ struct CallerIDExtInfo : public ExtensionItem
std::string serialize(SerializeFormat format, const Extensible* container, void* item) const
{
- callerid_data* dat = static_cast<callerid_data*>(item);
- return dat->ToString(format);
+ std::string ret;
+ if (format != FORMAT_NETWORK)
+ {
+ callerid_data* dat = static_cast<callerid_data*>(item);
+ ret = dat->ToString(format);
+ }
+ return ret;
}
void unserialize(SerializeFormat format, Extensible* container, const std::string& value)
{
+ if (format == FORMAT_NETWORK)
+ return;
+
callerid_data* dat = new callerid_data;
irc::commasepstream s(value);
std::string tok;
@@ -76,9 +94,6 @@ struct CallerIDExtInfo : public ExtensionItem
while (s.GetToken(tok))
{
- if (tok.empty())
- continue;
-
User *u = ServerInstance->FindNick(tok);
if ((u) && (u->registered == REG_ALL) && (!u->quitting) && (!IS_SERVER(u)))
{
@@ -117,7 +132,7 @@ struct CallerIDExtInfo : public ExtensionItem
if (!targ)
{
- ServerInstance->Logs->Log("m_callerid", DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (1)");
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (1)");
continue; // shouldn't happen, but oh well.
}
@@ -125,7 +140,7 @@ struct CallerIDExtInfo : public ExtensionItem
if (it2 != targ->wholistsme.end())
targ->wholistsme.erase(it2);
else
- ServerInstance->Logs->Log("m_callerid", DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (2)");
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (2)");
}
delete dat;
}
@@ -139,6 +154,28 @@ public:
class CommandAccept : public Command
{
+ /** Pair: first is the target, second is true to add, false to remove
+ */
+ typedef std::pair<User*, bool> ACCEPTAction;
+
+ static ACCEPTAction GetTargetAndAction(std::string& tok, User* cmdfrom = NULL)
+ {
+ bool remove = (tok[0] == '-');
+ if ((remove) || (tok[0] == '+'))
+ tok.erase(tok.begin());
+
+ User* target;
+ if (!cmdfrom || !IS_LOCAL(cmdfrom))
+ target = ServerInstance->FindNick(tok);
+ else
+ target = ServerInstance->FindNickOnly(tok);
+
+ if ((!target) || (target->registered != REG_ALL) || (target->quitting) || (IS_SERVER(target)))
+ target = NULL;
+
+ return std::make_pair(target, !remove);
+ }
+
public:
CallerIDExtInfo extInfo;
unsigned int maxaccepts;
@@ -147,42 +184,21 @@ public:
{
allow_empty_last_param = false;
syntax = "*|(+|-)<nick>[,(+|-)<nick> ...]";
- TRANSLATE2(TR_CUSTOM, TR_END);
+ TRANSLATE1(TR_CUSTOM);
}
- virtual void EncodeParameter(std::string& parameter, int index)
+ void EncodeParameter(std::string& parameter, int index)
{
- if (index != 0)
+ // Send lists as-is (part of 2.0 compat)
+ if (parameter.find(',') != std::string::npos)
return;
- std::string out;
- irc::commasepstream nicks(parameter);
- std::string tok;
- while (nicks.GetToken(tok))
- {
- if (tok == "*")
- {
- continue; // Drop list requests, since remote servers ignore them anyway.
- }
- if (!out.empty())
- out.append(",");
- bool dash = false;
- if (tok[0] == '-')
- {
- dash = true;
- tok.erase(0, 1); // Remove the dash.
- }
- else if (tok[0] == '+')
- tok.erase(0, 1);
- User* u = ServerInstance->FindNick(tok);
- if ((!u) || (u->registered != REG_ALL) || (u->quitting) || (IS_SERVER(u)))
- continue;
+ // Convert a [+|-]<nick> into a [-]<uuid>
+ ACCEPTAction action = GetTargetAndAction(parameter);
+ if (!action.first)
+ return;
- if (dash)
- out.append("-");
- out.append(u->uuid);
- }
- parameter = out;
+ parameter = (action.second ? "" : "-") + action.first->uuid;
}
/** Will take any number of nicks (up to MaxTargets), which can be seperated by commas.
@@ -192,54 +208,58 @@ public:
*/
CmdResult Handle(const std::vector<std::string> &parameters, User* user)
{
- if (ServerInstance->Parser->LoopCall(user, this, parameters, 0))
+ if (CommandParser::LoopCall(user, this, parameters, 0))
return CMD_SUCCESS;
+
/* Even if callerid mode is not set, we let them manage their ACCEPT list so that if they go +g they can
* have a list already setup. */
- const std::string& tok = parameters[0];
-
- if (tok == "*")
+ if (parameters[0] == "*")
{
- if (IS_LOCAL(user))
- ListAccept(user);
+ ListAccept(user);
return CMD_SUCCESS;
}
- else if (tok[0] == '-')
- {
- User* whotoremove;
- if (IS_LOCAL(user))
- whotoremove = ServerInstance->FindNickOnly(tok.substr(1));
- else
- whotoremove = ServerInstance->FindNick(tok.substr(1));
- if (whotoremove)
- return (RemoveAccept(user, whotoremove) ? CMD_SUCCESS : CMD_FAILURE);
- else
- return CMD_FAILURE;
- }
- else
+ std::string tok = parameters[0];
+ ACCEPTAction action = GetTargetAndAction(tok, user);
+ if (!action.first)
{
- const std::string target = (tok[0] == '+' ? tok.substr(1) : tok);
- User* whotoadd;
- if (IS_LOCAL(user))
- whotoadd = ServerInstance->FindNickOnly(target);
- else
- whotoadd = ServerInstance->FindNick(target);
-
- if ((whotoadd) && (whotoadd->registered == REG_ALL) && (!whotoadd->quitting) && (!IS_SERVER(whotoadd)))
- return (AddAccept(user, whotoadd) ? CMD_SUCCESS : CMD_FAILURE);
- else
- {
- user->WriteNumeric(401, "%s %s :No such nick/channel", user->nick.c_str(), tok.c_str());
- return CMD_FAILURE;
- }
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", tok.c_str());
+ return CMD_FAILURE;
}
+
+ if ((!IS_LOCAL(user)) && (!IS_LOCAL(action.first)))
+ // Neither source nor target is local, forward the command to the server of target
+ return CMD_SUCCESS;
+
+ // The second item in the pair is true if the first char is a '+' (or nothing), false if it's a '-'
+ if (action.second)
+ return (AddAccept(user, action.first) ? CMD_SUCCESS : CMD_FAILURE);
+ else
+ return (RemoveAccept(user, action.first) ? CMD_SUCCESS : CMD_FAILURE);
}
RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
{
- return ROUTE_BROADCAST;
+ // There is a list in parameters[0] in two cases:
+ // Either when the source is remote, this happens because 2.0 servers send comma seperated uuid lists,
+ // we don't split those but broadcast them, as before.
+ //
+ // Or if the source is local then LoopCall() runs OnPostCommand() after each entry in the list,
+ // meaning the linking module has sent an ACCEPT already for each entry in the list to the
+ // appropiate server and the ACCEPT with the list of nicks (this) doesn't need to be sent anywhere.
+ if ((!IS_LOCAL(user)) && (parameters[0].find(',') != std::string::npos))
+ return ROUTE_BROADCAST;
+
+ // Find the target
+ std::string targetstring = parameters[0];
+ ACCEPTAction action = GetTargetAndAction(targetstring, user);
+ if (!action.first)
+ // Target is a "*" or source is local and the target is a list of nicks
+ return ROUTE_LOCALONLY;
+
+ // Route to the server of the target
+ return ROUTE_UNICAST(action.first->server);
}
void ListAccept(User* user)
@@ -248,9 +268,9 @@ public:
if (dat)
{
for (std::set<User*>::iterator i = dat->accepting.begin(); i != dat->accepting.end(); ++i)
- user->WriteNumeric(281, "%s %s", user->nick.c_str(), (*i)->nick.c_str());
+ user->WriteNumeric(RPL_ACCEPTLIST, (*i)->nick);
}
- user->WriteNumeric(282, "%s :End of ACCEPT list", user->nick.c_str());
+ user->WriteNumeric(RPL_ENDOFACCEPT, ":End of ACCEPT list");
}
bool AddAccept(User* user, User* whotoadd)
@@ -259,12 +279,12 @@ public:
callerid_data* dat = extInfo.get(user, true);
if (dat->accepting.size() >= maxaccepts)
{
- user->WriteNumeric(456, "%s :Accept list is full (limit is %d)", user->nick.c_str(), maxaccepts);
+ user->WriteNumeric(ERR_ACCEPTFULL, ":Accept list is full (limit is %d)", maxaccepts);
return false;
}
if (!dat->accepting.insert(whotoadd).second)
{
- user->WriteNumeric(457, "%s %s :is already on your accept list", user->nick.c_str(), whotoadd->nick.c_str());
+ user->WriteNumeric(ERR_ACCEPTEXIST, "%s :is already on your accept list", whotoadd->nick.c_str());
return false;
}
@@ -272,7 +292,7 @@ public:
callerid_data *targ = extInfo.get(whotoadd, true);
targ->wholistsme.push_back(dat);
- user->WriteServ("NOTICE %s :%s is now on your accept list", user->nick.c_str(), whotoadd->nick.c_str());
+ user->WriteNotice(whotoadd->nick + " is now on your accept list");
return true;
}
@@ -282,13 +302,13 @@ public:
callerid_data* dat = extInfo.get(user, false);
if (!dat)
{
- user->WriteNumeric(458, "%s %s :is not on your accept list", user->nick.c_str(), whotoremove->nick.c_str());
+ user->WriteNumeric(ERR_ACCEPTNOT, "%s :is not on your accept list", whotoremove->nick.c_str());
return false;
}
std::set<User*>::iterator i = dat->accepting.find(whotoremove);
if (i == dat->accepting.end())
{
- user->WriteNumeric(458, "%s %s :is not on your accept list", user->nick.c_str(), whotoremove->nick.c_str());
+ user->WriteNumeric(ERR_ACCEPTNOT, "%s :is not on your accept list", whotoremove->nick.c_str());
return false;
}
@@ -299,7 +319,7 @@ public:
if (!dat2)
{
// How the fuck is this possible.
- ServerInstance->Logs->Log("m_callerid", DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (3)");
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (3)");
return false;
}
@@ -308,17 +328,16 @@ public:
// Found me!
dat2->wholistsme.erase(it);
else
- ServerInstance->Logs->Log("m_callerid", DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (4)");
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (4)");
- user->WriteServ("NOTICE %s :%s is no longer on your accept list", user->nick.c_str(), whotoremove->nick.c_str());
+ user->WriteNotice(whotoremove->nick + " is no longer on your accept list");
return true;
}
};
class ModuleCallerID : public Module
{
-private:
CommandAccept cmd;
User_g myumode;
@@ -348,7 +367,7 @@ private:
if (it2 != dat->accepting.end())
dat->accepting.erase(it2);
else
- ServerInstance->Logs->Log("m_callerid", DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (5)");
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (5)");
}
userdata->wholistsme.clear();
@@ -359,38 +378,26 @@ public:
{
}
- void init()
- {
- OnRehash(NULL);
-
- ServerInstance->Modules->AddService(myumode);
- ServerInstance->Modules->AddService(cmd);
- ServerInstance->Modules->AddService(cmd.extInfo);
-
- Implementation eventlist[] = { I_OnRehash, I_OnUserPostNick, I_OnUserQuit, I_On005Numeric, I_OnUserPreNotice, I_OnUserPreMessage };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- virtual ~ModuleCallerID()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Implementation of callerid, usermode +g, /accept", VF_COMMON | VF_VENDOR);
}
- virtual void On005Numeric(std::string& output)
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
- output += " CALLERID=g";
+ tokens["CALLERID"] = "g";
}
- ModResult PreText(User* user, User* dest, std::string& text)
+ ModResult OnUserPreMessage(User* user, void* voiddest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE
{
- if (!dest->IsModeSet('g') || (user == dest))
+ if (!IS_LOCAL(user) || target_type != TYPE_USER)
+ return MOD_RES_PASSTHRU;
+
+ User* dest = static_cast<User*>(voiddest);
+ if (!dest->IsModeSet(myumode) || (user == dest))
return MOD_RES_PASSTHRU;
- if (operoverride && IS_OPER(user))
+ if (operoverride && user->IsOper())
return MOD_RES_PASSTHRU;
callerid_data* dat = cmd.extInfo.get(dest, true);
@@ -400,12 +407,12 @@ public:
{
time_t now = ServerInstance->Time();
/* +g and *not* accepted */
- user->WriteNumeric(716, "%s %s :is in +g mode (server-side ignore).", user->nick.c_str(), dest->nick.c_str());
+ user->WriteNumeric(ERR_TARGUMODEG, "%s :is in +g mode (server-side ignore).", dest->nick.c_str());
if (now > (dat->lastnotify + (time_t)notify_cooldown))
{
- user->WriteNumeric(717, "%s %s :has been informed that you messaged them.", user->nick.c_str(), dest->nick.c_str());
- dest->SendText(":%s 718 %s %s %s@%s :is messaging you, and you have umode +g. Use /ACCEPT +%s to allow.",
- ServerInstance->Config->ServerName.c_str(), dest->nick.c_str(), user->nick.c_str(), user->ident.c_str(), user->dhost.c_str(), user->nick.c_str());
+ user->WriteNumeric(RPL_TARGNOTIFY, "%s :has been informed that you messaged them.", dest->nick.c_str());
+ dest->SendText(":%s %03d %s %s %s@%s :is messaging you, and you have umode +g. Use /ACCEPT +%s to allow.",
+ ServerInstance->Config->ServerName.c_str(), RPL_UMODEGMSG, dest->nick.c_str(), user->nick.c_str(), user->ident.c_str(), user->dhost.c_str(), user->nick.c_str());
dat->lastnotify = now;
}
return MOD_RES_DENY;
@@ -413,34 +420,18 @@ public:
return MOD_RES_PASSTHRU;
}
- virtual ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList &exempt_list)
- {
- if (IS_LOCAL(user) && target_type == TYPE_USER)
- return PreText(user, (User*)dest, text);
-
- return MOD_RES_PASSTHRU;
- }
-
- virtual ModResult OnUserPreNotice(User* user, void* dest, int target_type, std::string& text, char status, CUList &exempt_list)
- {
- if (IS_LOCAL(user) && target_type == TYPE_USER)
- return PreText(user, (User*)dest, text);
-
- return MOD_RES_PASSTHRU;
- }
-
- void OnUserPostNick(User* user, const std::string& oldnick)
+ void OnUserPostNick(User* user, const std::string& oldnick) CXX11_OVERRIDE
{
if (!tracknick)
RemoveFromAllAccepts(user);
}
- void OnUserQuit(User* user, const std::string& message, const std::string& oper_message)
+ void OnUserQuit(User* user, const std::string& message, const std::string& oper_message) CXX11_OVERRIDE
{
RemoveFromAllAccepts(user);
}
- virtual void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ConfigTag* tag = ServerInstance->Config->ConfValue("callerid");
cmd.maxaccepts = tag->getInt("maxaccepts", 16);
@@ -451,5 +442,3 @@ public:
};
MODULE_INIT(ModuleCallerID)
-
-
diff --git a/src/modules/m_cap.cpp b/src/modules/m_cap.cpp
index e9f4dae90..bc79e59ec 100644
--- a/src/modules/m_cap.cpp
+++ b/src/modules/m_cap.cpp
@@ -19,9 +19,7 @@
#include "inspircd.h"
-#include "m_cap.h"
-
-/* $ModDesc: Provides the CAP negotiation mechanism seen in ratbox-derived ircds */
+#include "modules/cap.h"
/*
CAP LS
@@ -51,7 +49,8 @@ class CommandCAP : public Command
CmdResult Handle (const std::vector<std::string> &parameters, User *user)
{
- irc::string subcommand = parameters[0].c_str();
+ std::string subcommand(parameters[0].length(), ' ');
+ std::transform(parameters[0].begin(), parameters[0].end(), subcommand.begin(), ::toupper);
if (subcommand == "REQ")
{
@@ -66,6 +65,7 @@ class CommandCAP : public Command
while (cap_stream.GetToken(cap_))
{
+ std::transform(cap_.begin(), cap_.end(), cap_.begin(), ::tolower);
Data.wanted.push_back(cap_);
}
@@ -74,14 +74,14 @@ class CommandCAP : public Command
if (Data.ack.size() > 0)
{
- std::string AckResult = irc::stringjoiner(" ", Data.ack, 0, Data.ack.size() - 1).GetJoined();
- user->WriteServ("CAP %s ACK :%s", user->nick.c_str(), AckResult.c_str());
+ std::string AckResult = irc::stringjoiner(Data.ack);
+ user->WriteCommand("CAP", "ACK :" + AckResult);
}
if (Data.wanted.size() > 0)
{
- std::string NakResult = irc::stringjoiner(" ", Data.wanted, 0, Data.wanted.size() - 1).GetJoined();
- user->WriteServ("CAP %s NAK :%s", user->nick.c_str(), NakResult.c_str());
+ std::string NakResult = irc::stringjoiner(Data.wanted);
+ user->WriteCommand("CAP", "NAK :" + NakResult);
}
}
else if (subcommand == "END")
@@ -95,11 +95,8 @@ class CommandCAP : public Command
reghold.set(user, 1);
Data.Send();
- std::string Result;
- if (Data.wanted.size() > 0)
- Result = irc::stringjoiner(" ", Data.wanted, 0, Data.wanted.size() - 1).GetJoined();
-
- user->WriteServ("CAP %s %s :%s", user->nick.c_str(), subcommand.c_str(), Result.c_str());
+ std::string Result = irc::stringjoiner(Data.wanted);
+ user->WriteCommand("CAP", subcommand + " :" + Result);
}
else if (subcommand == "CLEAR")
{
@@ -108,14 +105,12 @@ class CommandCAP : public Command
reghold.set(user, 1);
Data.Send();
- std::string Result;
- if (!Data.ack.empty())
- Result = irc::stringjoiner(" ", Data.ack, 0, Data.ack.size() - 1).GetJoined();
- user->WriteServ("CAP %s ACK :%s", user->nick.c_str(), Result.c_str());
+ std::string Result = irc::stringjoiner(Data.ack);
+ user->WriteCommand("CAP", "ACK :" + Result);
}
else
{
- user->WriteNumeric(ERR_INVALIDCAPSUBCOMMAND, "%s %s :Invalid CAP subcommand", user->nick.c_str(), subcommand.c_str());
+ user->WriteNumeric(ERR_INVALIDCAPSUBCOMMAND, "%s :Invalid CAP subcommand", subcommand.c_str());
return CMD_FAILURE;
}
@@ -132,16 +127,7 @@ class ModuleCAP : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cmd);
- ServerInstance->Modules->AddService(cmd.reghold);
-
- Implementation eventlist[] = { I_OnCheckReady };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- ModResult OnCheckReady(LocalUser* user)
+ ModResult OnCheckReady(LocalUser* user) CXX11_OVERRIDE
{
/* Users in CAP state get held until CAP END */
if (cmd.reghold.get(user))
@@ -150,15 +136,10 @@ class ModuleCAP : public Module
return MOD_RES_PASSTHRU;
}
- ~ModuleCAP()
- {
- }
-
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Client CAP extension support", VF_VENDOR);
}
};
MODULE_INIT(ModuleCAP)
-
diff --git a/src/modules/m_cap.h b/src/modules/m_cap.h
deleted file mode 100644
index 409671f48..000000000
--- a/src/modules/m_cap.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#ifndef M_CAP_H
-#define M_CAP_H
-
-class CapEvent : public Event
-{
- public:
- enum CapEventType
- {
- CAPEVENT_REQ,
- CAPEVENT_LS,
- CAPEVENT_LIST,
- CAPEVENT_CLEAR
- };
-
- CapEventType type;
- std::vector<std::string> wanted;
- std::vector<std::string> ack;
- User* user;
- CapEvent(Module* sender, User* u, CapEventType capevtype) : Event(sender, "cap_request"), type(capevtype), user(u) {}
-};
-
-class GenericCap
-{
- public:
- LocalIntExt ext;
- const std::string cap;
- GenericCap(Module* parent, const std::string &Cap) : ext("cap_" + Cap, parent), cap(Cap)
- {
- ServerInstance->Modules->AddService(ext);
- }
-
- void HandleEvent(Event& ev)
- {
- if (ev.id != "cap_request")
- return;
-
- CapEvent *data = static_cast<CapEvent*>(&ev);
- if (data->type == CapEvent::CAPEVENT_REQ)
- {
- for (std::vector<std::string>::iterator it = data->wanted.begin(); it != data->wanted.end(); ++it)
- {
- if (it->empty())
- continue;
- bool enablecap = ((*it)[0] != '-');
- if (((enablecap) && (*it == cap)) || (*it == "-" + cap))
- {
- // we can handle this, so ACK it, and remove it from the wanted list
- data->ack.push_back(*it);
- data->wanted.erase(it);
- ext.set(data->user, enablecap ? 1 : 0);
- break;
- }
- }
- }
- else if (data->type == CapEvent::CAPEVENT_LS)
- {
- data->wanted.push_back(cap);
- }
- else if (data->type == CapEvent::CAPEVENT_LIST)
- {
- if (ext.get(data->user))
- data->wanted.push_back(cap);
- }
- else if (data->type == CapEvent::CAPEVENT_CLEAR)
- {
- data->ack.push_back("-" + cap);
- ext.set(data->user, 0);
- }
- }
-};
-
-#endif
diff --git a/src/modules/m_cban.cpp b/src/modules/m_cban.cpp
index fb78e41b2..4fb0653a9 100644
--- a/src/modules/m_cban.cpp
+++ b/src/modules/m_cban.cpp
@@ -23,25 +23,22 @@
#include "inspircd.h"
#include "xline.h"
-/* $ModDesc: Gives /cban, aka C:lines. Think Q:lines, for channels. */
-
/** Holds a CBAN item
*/
class CBan : public XLine
{
-public:
+private:
+ std::string displaytext;
irc::string matchtext;
+public:
CBan(time_t s_time, long d, const std::string& src, const std::string& re, const std::string& ch)
: XLine(s_time, d, src, re, "CBAN")
{
+ this->displaytext = ch;
this->matchtext = ch.c_str();
}
- ~CBan()
- {
- }
-
// XXX I shouldn't have to define this
bool Matches(User *u)
{
@@ -55,15 +52,9 @@ public:
return false;
}
- void DisplayExpiry()
+ const std::string& Displayable()
{
- ServerInstance->SNO->WriteToSnoMask('x',"Removing expired CBan %s (set by %s %ld seconds ago)",
- this->matchtext.c_str(), this->source.c_str(), (long int)(ServerInstance->Time() - this->set_time));
- }
-
- const char* Displayable()
- {
- return matchtext.c_str();
+ return displaytext;
}
};
@@ -95,7 +86,6 @@ class CommandCBan : public Command
CommandCBan(Module* Creator) : Command(Creator, "CBAN", 1, 3)
{
flags_needed = 'o'; this->syntax = "<channel> [<duration> :<reason>]";
- TRANSLATE4(TR_TEXT,TR_TEXT,TR_TEXT,TR_END);
}
CmdResult Handle(const std::vector<std::string> &parameters, User *user)
@@ -111,14 +101,14 @@ class CommandCBan : public Command
}
else
{
- user->WriteServ("NOTICE %s :*** CBan %s not found in list, try /stats C.",user->nick.c_str(),parameters[0].c_str());
+ user->WriteNotice("*** CBan " + parameters[0] + " not found in list, try /stats C.");
return CMD_FAILURE;
}
}
else
{
// Adding - XXX todo make this respect <insane> tag perhaps..
- long duration = ServerInstance->Duration(parameters[1]);
+ unsigned long duration = InspIRCd::Duration(parameters[1]);
const char *reason = (parameters.size() > 2) ? parameters[2].c_str() : "No reason supplied";
CBan* r = new CBan(ServerInstance->Time(), duration, user->nick.c_str(), reason, parameters[0].c_str());
@@ -131,14 +121,14 @@ class CommandCBan : public Command
else
{
time_t c_requires_crap = duration + ServerInstance->Time();
- std::string timestr = ServerInstance->TimeString(c_requires_crap);
+ std::string timestr = InspIRCd::TimeString(c_requires_crap);
ServerInstance->SNO->WriteGlobalSno('x', "%s added timed CBan for %s, expires on %s: %s", user->nick.c_str(), parameters[0].c_str(), timestr.c_str(), reason);
}
}
else
{
delete r;
- user->WriteServ("NOTICE %s :*** CBan for %s already exists", user->nick.c_str(), parameters[0].c_str());
+ user->WriteNotice("*** CBan for " + parameters[0] + " already exists");
return CMD_FAILURE;
}
}
@@ -164,22 +154,18 @@ class ModuleCBan : public Module
{
}
- void init()
+ void init() CXX11_OVERRIDE
{
ServerInstance->XLines->RegisterFactory(&f);
-
- ServerInstance->Modules->AddService(mycommand);
- Implementation eventlist[] = { I_OnUserPreJoin, I_OnStats };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
}
- virtual ~ModuleCBan()
+ ~ModuleCBan()
{
ServerInstance->XLines->DelAll("CBAN");
ServerInstance->XLines->UnregisterFactory(&f);
}
- virtual ModResult OnStats(char symbol, User* user, string_list &out)
+ ModResult OnStats(char symbol, User* user, string_list &out) CXX11_OVERRIDE
{
if (symbol != 'C')
return MOD_RES_PASSTHRU;
@@ -188,27 +174,26 @@ class ModuleCBan : public Module
return MOD_RES_DENY;
}
- virtual ModResult OnUserPreJoin(User *user, Channel *chan, const char *cname, std::string &privs, const std::string &keygiven)
+ ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE
{
XLine *rl = ServerInstance->XLines->MatchesLine("CBAN", cname);
if (rl)
{
// Channel is banned.
- user->WriteServ( "384 %s %s :Cannot join channel, CBANed (%s)", user->nick.c_str(), cname, rl->reason.c_str());
+ user->WriteNumeric(384, "%s :Cannot join channel, CBANed (%s)", cname.c_str(), rl->reason.c_str());
ServerInstance->SNO->WriteGlobalSno('a', "%s tried to join %s which is CBANed (%s)",
- user->nick.c_str(), cname, rl->reason.c_str());
+ user->nick.c_str(), cname.c_str(), rl->reason.c_str());
return MOD_RES_DENY;
}
return MOD_RES_PASSTHRU;
}
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Gives /cban, aka C:lines. Think Q:lines, for channels.", VF_COMMON | VF_VENDOR);
}
};
MODULE_INIT(ModuleCBan)
-
diff --git a/src/modules/m_censor.cpp b/src/modules/m_censor.cpp
index 50c8e22a7..209d61d4a 100644
--- a/src/modules/m_censor.cpp
+++ b/src/modules/m_censor.cpp
@@ -20,13 +20,7 @@
*/
-/* $ModDesc: Provides user and channel +G mode */
-
-#define _CRT_SECURE_NO_DEPRECATE
-#define _SCL_SECURE_NO_DEPRECATE
-
#include "inspircd.h"
-#include <iostream>
typedef std::map<irc::string,irc::string> censor_t;
@@ -55,24 +49,8 @@ class ModuleCensor : public Module
public:
ModuleCensor() : cu(this), cc(this) { }
- void init()
- {
- /* Read the configuration file on startup.
- */
- OnRehash(NULL);
- ServerInstance->Modules->AddService(cu);
- ServerInstance->Modules->AddService(cc);
- Implementation eventlist[] = { I_OnRehash, I_OnUserPreMessage, I_OnUserPreNotice };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
-
- virtual ~ModuleCensor()
- {
- }
-
// format of a config entry is <badword text="shit" replace="poo">
- virtual ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+ ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE
{
if (!IS_LOCAL(user))
return MOD_RES_PASSTHRU;
@@ -80,11 +58,11 @@ class ModuleCensor : public Module
bool active = false;
if (target_type == TYPE_USER)
- active = ((User*)dest)->IsModeSet('G');
+ active = ((User*)dest)->IsModeSet(cu);
else if (target_type == TYPE_CHANNEL)
{
- active = ((Channel*)dest)->IsModeSet('G');
Channel* c = (Channel*)dest;
+ active = c->IsModeSet(cc);
ModResult res = ServerInstance->OnCheckExemption(user,c,"censor");
if (res == MOD_RES_ALLOW)
@@ -101,7 +79,7 @@ class ModuleCensor : public Module
{
if (index->second.empty())
{
- user->WriteNumeric(ERR_WORDFILTERED, "%s %s %s :Your message contained a censored word, and was blocked", user->nick.c_str(), ((Channel*)dest)->name.c_str(), index->first.c_str());
+ user->WriteNumeric(ERR_WORDFILTERED, "%s %s :Your message contained a censored word, and was blocked", ((Channel*)dest)->name.c_str(), index->first.c_str());
return MOD_RES_DENY;
}
@@ -112,12 +90,7 @@ class ModuleCensor : public Module
return MOD_RES_PASSTHRU;
}
- virtual ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
- {
- return OnUserPreMessage(user,dest,target_type,text,status,exempt_list);
- }
-
- virtual void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
/*
* reload our config file on rehash - we must destroy and re-allocate the classes
@@ -136,7 +109,7 @@ class ModuleCensor : public Module
}
}
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides user and channel +G mode",VF_VENDOR);
}
diff --git a/src/modules/m_cgiirc.cpp b/src/modules/m_cgiirc.cpp
index cce2e7855..791045780 100644
--- a/src/modules/m_cgiirc.cpp
+++ b/src/modules/m_cgiirc.cpp
@@ -25,11 +25,17 @@
#include "inspircd.h"
#include "xline.h"
-
-/* $ModDesc: Change user's hosts connecting from known CGI:IRC hosts */
+#include "modules/dns.h"
enum CGItype { PASS, IDENT, PASSFIRST, IDENTFIRST, WEBIRC };
+// We need this method up here so that it can be accessed from anywhere
+static void ChangeIP(User* user, const std::string& newip)
+{
+ ServerInstance->Users->RemoveCloneCounts(user);
+ user->SetClientIP(newip.c_str());
+ ServerInstance->Users->AddClone(user);
+}
/** Holds a CGI site's details
*/
@@ -64,14 +70,11 @@ class CommandWebirc : public Command
bool notify;
StringExtItem realhost;
StringExtItem realip;
- LocalStringExt webirc_hostname;
- LocalStringExt webirc_ip;
CGIHostlist Hosts;
CommandWebirc(Module* Creator)
: Command(Creator, "WEBIRC", 4),
- realhost("cgiirc_realhost", Creator), realip("cgiirc_realip", Creator),
- webirc_hostname("cgiirc_webirc_hostname", Creator), webirc_ip("cgiirc_webirc_ip", Creator)
+ realhost("cgiirc_realhost", Creator), realip("cgiirc_realip", Creator)
{
works_before_reg = true;
this->syntax = "password client hostname ip";
@@ -90,25 +93,25 @@ class CommandWebirc : public Command
realhost.set(user, user->host);
realip.set(user, user->GetIPString());
- bool host_ok = (parameters[2].length() < 64);
+ // Check if we're happy with the provided hostname. If it's problematic then make sure we won't set a host later, just the IP
+ bool host_ok = (parameters[2].length() <= ServerInstance->Config->Limits.MaxHost);
const std::string& newhost = (host_ok ? parameters[2] : parameters[3]);
if (notify)
- ServerInstance->SNO->WriteGlobalSno('a', "Connecting user %s detected as using CGI:IRC (%s), changing real host to %s from %s", user->nick.c_str(), user->host.c_str(), newhost.c_str(), user->host.c_str());
+ ServerInstance->SNO->WriteGlobalSno('w', "Connecting user %s detected as using CGI:IRC (%s), changing real host to %s from %s", user->nick.c_str(), user->host.c_str(), newhost.c_str(), user->host.c_str());
- // Check if we're happy with the provided hostname. If it's problematic then make sure we won't set a host later, just the IP
- if (host_ok)
- webirc_hostname.set(user, parameters[2]);
- else
- webirc_hostname.unset(user);
+ // Where the magic happens - change their IP
+ ChangeIP(user, parameters[3]);
+ // And follow this up by changing their host
+ user->host = user->dhost = newhost;
+ user->InvalidateCache();
- webirc_ip.set(user, parameters[3]);
return CMD_SUCCESS;
}
}
}
- ServerInstance->SNO->WriteGlobalSno('a', "Connecting user %s tried to use WEBIRC, but didn't match any configured webirc blocks.", user->GetFullRealHost().c_str());
+ ServerInstance->SNO->WriteGlobalSno('w', "Connecting user %s tried to use WEBIRC, but didn't match any configured webirc blocks.", user->GetFullRealHost().c_str());
return CMD_FAILURE;
}
};
@@ -116,39 +119,44 @@ class CommandWebirc : public Command
/** Resolver for CGI:IRC hostnames encoded in ident/GECOS
*/
-class CGIResolver : public Resolver
+class CGIResolver : public DNS::Request
{
std::string typ;
std::string theiruid;
LocalIntExt& waiting;
bool notify;
public:
- CGIResolver(Module* me, bool NotifyOpers, const std::string &source, LocalUser* u,
- const std::string &type, bool &cached, LocalIntExt& ext)
- : Resolver(source, DNS_QUERY_PTR4, cached, me), typ(type), theiruid(u->uuid),
+ CGIResolver(DNS::Manager *mgr, Module* me, bool NotifyOpers, const std::string &source, LocalUser* u,
+ const std::string &ttype, LocalIntExt& ext)
+ : DNS::Request(mgr, me, source, DNS::QUERY_PTR), typ(ttype), theiruid(u->uuid),
waiting(ext), notify(NotifyOpers)
{
}
- virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached)
+ void OnLookupComplete(const DNS::Query *r) CXX11_OVERRIDE
{
/* Check the user still exists */
User* them = ServerInstance->FindUUID(theiruid);
if ((them) && (!them->quitting))
{
- if (notify)
- ServerInstance->SNO->WriteGlobalSno('a', "Connecting user %s detected as using CGI:IRC (%s), changing real host to %s from %s", them->nick.c_str(), them->host.c_str(), result.c_str(), typ.c_str());
+ LocalUser* lu = IS_LOCAL(them);
+ if (!lu)
+ return;
- if (result.length() > 64)
+ const DNS::ResourceRecord &ans_record = r->answers[0];
+ if (ans_record.rdata.empty() || ans_record.rdata.length() > ServerInstance->Config->Limits.MaxHost)
return;
- them->host = result;
- them->dhost = result;
+
+ if (notify)
+ ServerInstance->SNO->WriteGlobalSno('w', "Connecting user %s detected as using CGI:IRC (%s), changing real host to %s from %s", them->nick.c_str(), them->host.c_str(), ans_record.rdata.c_str(), typ.c_str());
+
+ them->host = them->dhost = ans_record.rdata;
them->InvalidateCache();
- them->CheckLines(true);
+ lu->CheckLines(true);
}
}
- virtual void OnError(ResolverError e, const std::string &errormessage)
+ void OnError(const DNS::Query *r) CXX11_OVERRIDE
{
if (!notify)
return;
@@ -156,11 +164,11 @@ class CGIResolver : public Resolver
User* them = ServerInstance->FindUUID(theiruid);
if ((them) && (!them->quitting))
{
- ServerInstance->SNO->WriteToSnoMask('a', "Connecting user %s detected as using CGI:IRC (%s), but their host can't be resolved from their %s!", them->nick.c_str(), them->host.c_str(), typ.c_str());
+ ServerInstance->SNO->WriteToSnoMask('w', "Connecting user %s detected as using CGI:IRC (%s), but their host can't be resolved from their %s!", them->nick.c_str(), them->host.c_str(), typ.c_str());
}
}
- virtual ~CGIResolver()
+ ~CGIResolver()
{
User* them = ServerInstance->FindUUID(theiruid);
if (!them)
@@ -175,6 +183,7 @@ class ModuleCgiIRC : public Module
{
CommandWebirc cmd;
LocalIntExt waiting;
+ dynamic_reference<DNS::Manager> DNS;
static void RecheckClass(LocalUser* user)
{
@@ -183,14 +192,6 @@ class ModuleCgiIRC : public Module
user->CheckClass();
}
- static void ChangeIP(LocalUser* user, const std::string& newip)
- {
- ServerInstance->Users->RemoveCloneCounts(user);
- user->SetClientIP(newip.c_str());
- ServerInstance->Users->AddLocalClone(user);
- ServerInstance->Users->AddGlobalClone(user);
- }
-
void HandleIdentOrPass(LocalUser* user, const std::string& newip, bool was_pass)
{
cmd.realhost.set(user, user->host);
@@ -199,40 +200,42 @@ class ModuleCgiIRC : public Module
user->host = user->dhost = user->GetIPString();
user->InvalidateCache();
RecheckClass(user);
+
// Don't create the resolver if the core couldn't put the user in a connect class or when dns is disabled
- if (user->quitting || ServerInstance->Config->NoUserDns)
+ if (user->quitting || !DNS || !user->MyClass->resolvehostnames)
return;
+ CGIResolver* r = new CGIResolver(*this->DNS, this, cmd.notify, newip, user, (was_pass ? "PASS" : "IDENT"), waiting);
try
{
- bool cached;
- CGIResolver* r = new CGIResolver(this, cmd.notify, newip, user, (was_pass ? "PASS" : "IDENT"), cached, waiting);
waiting.set(user, waiting.get(user) + 1);
- ServerInstance->AddResolver(r, cached);
+ this->DNS->Process(r);
}
- catch (...)
+ catch (DNS::Exception &ex)
{
+ int count = waiting.get(user);
+ if (count)
+ waiting.set(user, count - 1);
+ delete r;
if (cmd.notify)
- ServerInstance->SNO->WriteToSnoMask('a', "Connecting user %s detected as using CGI:IRC (%s), but I could not resolve their hostname!", user->nick.c_str(), user->host.c_str());
+ ServerInstance->SNO->WriteToSnoMask('w', "Connecting user %s detected as using CGI:IRC (%s), but I could not resolve their hostname; %s", user->nick.c_str(), user->host.c_str(), ex.GetReason().c_str());
}
}
public:
- ModuleCgiIRC() : cmd(this), waiting("cgiirc-delay", this)
+ ModuleCgiIRC()
+ : cmd(this)
+ , waiting("cgiirc-delay", this)
+ , DNS(this, "DNS")
{
}
- void init()
+ void init() CXX11_OVERRIDE
{
- OnRehash(NULL);
- ServiceProvider* providerlist[] = { &cmd, &cmd.realhost, &cmd.realip, &cmd.webirc_hostname, &cmd.webirc_ip, &waiting };
- ServerInstance->Modules->AddServices(providerlist, sizeof(providerlist)/sizeof(ServiceProvider*));
-
- Implementation eventlist[] = { I_OnRehash, I_OnUserRegister, I_OnCheckReady };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
+ ServerInstance->SNO->EnableSnomask('w', "CGIIRC");
}
- void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
cmd.Hosts.clear();
@@ -251,7 +254,7 @@ public:
{
if (type == "webirc" && password.empty())
{
- ServerInstance->Logs->Log("CONFIG",DEFAULT, "m_cgiirc: Missing password in config: %s", hostmask.c_str());
+ ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "m_cgiirc: Missing password in config: %s", hostmask.c_str());
}
else
{
@@ -267,7 +270,7 @@ public:
else
{
cgitype = PASS;
- ServerInstance->Logs->Log("CONFIG",DEFAULT, "m_cgiirc.so: Invalid <cgihost:type> value in config: %s, setting it to \"pass\"", type.c_str());
+ ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "Invalid <cgihost:type> value in config: %s, setting it to \"pass\"", type.c_str());
}
cmd.Hosts.push_back(CGIhost(hostmask, cgitype, password));
@@ -275,27 +278,20 @@ public:
}
else
{
- ServerInstance->Logs->Log("CONFIG",DEFAULT, "m_cgiirc.so: Invalid <cgihost:mask> value in config: %s", hostmask.c_str());
+ ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "Invalid <cgihost:mask> value in config: %s", hostmask.c_str());
continue;
}
}
}
- ModResult OnCheckReady(LocalUser *user)
+ ModResult OnCheckReady(LocalUser *user) CXX11_OVERRIDE
{
if (waiting.get(user))
return MOD_RES_DENY;
- std::string *webirc_ip = cmd.webirc_ip.get(user);
- if (!webirc_ip)
+ if (!cmd.realip.get(user))
return MOD_RES_PASSTHRU;
- ChangeIP(user, *webirc_ip);
-
- std::string* webirc_hostname = cmd.webirc_hostname.get(user);
- user->host = user->dhost = (webirc_hostname ? *webirc_hostname : user->GetIPString());
- user->InvalidateCache();
-
RecheckClass(user);
if (user->quitting)
return MOD_RES_DENY;
@@ -304,13 +300,10 @@ public:
if (user->quitting)
return MOD_RES_DENY;
- cmd.webirc_hostname.unset(user);
- cmd.webirc_ip.unset(user);
-
return MOD_RES_PASSTHRU;
}
- ModResult OnUserRegister(LocalUser* user)
+ ModResult OnUserRegister(LocalUser* user) CXX11_OVERRIDE
{
for(CGIHostlist::iterator iter = cmd.Hosts.begin(); iter != cmd.Hosts.end(); iter++)
{
@@ -388,7 +381,7 @@ public:
bool IsValidHost(const std::string &host)
{
- if(!host.size() || host.size() > 64)
+ if(!host.size() || host.size() > ServerInstance->Config->Limits.MaxHost)
return false;
for(unsigned int i = 0; i < host.size(); i++)
@@ -407,11 +400,10 @@ public:
return true;
}
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Change user's hosts connecting from known CGI:IRC hosts",VF_VENDOR);
}
-
};
MODULE_INIT(ModuleCgiIRC)
diff --git a/src/modules/m_chancreate.cpp b/src/modules/m_chancreate.cpp
index 997a92648..6cf4af235 100644
--- a/src/modules/m_chancreate.cpp
+++ b/src/modules/m_chancreate.cpp
@@ -21,26 +21,20 @@
#include "inspircd.h"
-/* $ModDesc: Provides snomasks 'j' and 'J', to which notices about newly created channels are sent */
-
class ModuleChanCreate : public Module
{
- private:
public:
- void init()
+ void init() CXX11_OVERRIDE
{
ServerInstance->SNO->EnableSnomask('j', "CHANCREATE");
- Implementation eventlist[] = { I_OnUserJoin };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides snomasks 'j' and 'J', to which notices about newly created channels are sent",VF_VENDOR);
}
-
- void OnUserJoin(Membership* memb, bool sync, bool created, CUList& except)
+ void OnUserJoin(Membership* memb, bool sync, bool created, CUList& except) CXX11_OVERRIDE
{
if ((created) && (IS_LOCAL(memb->user)))
{
diff --git a/src/modules/m_chanfilter.cpp b/src/modules/m_chanfilter.cpp
index 651e659b5..53428a5a8 100644
--- a/src/modules/m_chanfilter.cpp
+++ b/src/modules/m_chanfilter.cpp
@@ -23,13 +23,8 @@
*/
-/* $ModDesc: Provides channel-specific censor lists (like mode +G but varies from channel to channel) */
-
-#define _CRT_SECURE_NO_DEPRECATE
-#define _SCL_SECURE_NO_DEPRECATE
-
#include "inspircd.h"
-#include "u_listmode.h"
+#include "listmode.h"
/** Handles channel mode +g
*/
@@ -38,31 +33,30 @@ class ChanFilter : public ListModeBase
public:
ChanFilter(Module* Creator) : ListModeBase(Creator, "filter", 'g', "End of channel spamfilter list", 941, 940, false, "chanfilter") { }
- virtual bool ValidateParam(User* user, Channel* chan, std::string &word)
+ bool ValidateParam(User* user, Channel* chan, std::string &word)
{
- if ((word.length() > 35) || (word.empty()))
+ if (word.length() > 35)
{
- user->WriteNumeric(935, "%s %s %s :word is too %s for censor list",user->nick.c_str(), chan->name.c_str(), word.c_str(), (word.empty() ? "short" : "long"));
+ user->WriteNumeric(935, "%s %s :word is too long for censor list", chan->name.c_str(), word.c_str());
return false;
}
return true;
}
- virtual bool TellListTooLong(User* user, Channel* chan, std::string &word)
+ void TellListTooLong(User* user, Channel* chan, std::string &word)
{
- user->WriteNumeric(939, "%s %s %s :Channel spamfilter list is full", user->nick.c_str(), chan->name.c_str(), word.c_str());
- return true;
+ user->WriteNumeric(939, "%s %s :Channel spamfilter list is full", chan->name.c_str(), word.c_str());
}
- virtual void TellAlreadyOnList(User* user, Channel* chan, std::string &word)
+ void TellAlreadyOnList(User* user, Channel* chan, std::string &word)
{
- user->WriteNumeric(937, "%s %s :The word %s is already on the spamfilter list",user->nick.c_str(), chan->name.c_str(), word.c_str());
+ user->WriteNumeric(937, "%s :The word %s is already on the spamfilter list", chan->name.c_str(), word.c_str());
}
- virtual void TellNotSet(User* user, Channel* chan, std::string &word)
+ void TellNotSet(User* user, Channel* chan, std::string &word)
{
- user->WriteNumeric(938, "%s %s :No such spamfilter word is set",user->nick.c_str(), chan->name.c_str());
+ user->WriteNumeric(938, "%s :No such spamfilter word is set", chan->name.c_str());
}
};
@@ -78,42 +72,35 @@ class ModuleChanFilter : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cf);
-
- cf.DoImplements(this);
- Implementation eventlist[] = { I_OnRehash, I_OnUserPreMessage, I_OnUserPreNotice, I_OnSyncChannel };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
-
- OnRehash(NULL);
- }
-
- virtual void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
hidemask = ServerInstance->Config->ConfValue("chanfilter")->getBool("hidemask");
cf.DoRehash();
}
- virtual ModResult ProcessMessages(User* user,Channel* chan,std::string &text)
+ ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE
{
+ if (target_type != TYPE_CHANNEL)
+ return MOD_RES_PASSTHRU;
+
+ Channel* chan = static_cast<Channel*>(dest);
ModResult res = ServerInstance->OnCheckExemption(user,chan,"filter");
if (!IS_LOCAL(user) || res == MOD_RES_ALLOW)
return MOD_RES_PASSTHRU;
- modelist* list = cf.extItem.get(chan);
+ ListModeBase::ModeList* list = cf.GetList(chan);
if (list)
{
- for (modelist::iterator i = list->begin(); i != list->end(); i++)
+ for (ListModeBase::ModeList::iterator i = list->begin(); i != list->end(); i++)
{
if (InspIRCd::Match(text, i->mask))
{
if (hidemask)
- user->WriteNumeric(404, "%s %s :Cannot send to channel (your message contained a censored word)",user->nick.c_str(), chan->name.c_str());
+ user->WriteNumeric(ERR_CANNOTSENDTOCHAN, "%s :Cannot send to channel (your message contained a censored word)", chan->name.c_str());
else
- user->WriteNumeric(404, "%s %s %s :Cannot send to channel (your message contained a censored word)",user->nick.c_str(), chan->name.c_str(), i->mask.c_str());
+ user->WriteNumeric(ERR_CANNOTSENDTOCHAN, "%s %s :Cannot send to channel (your message contained a censored word)", chan->name.c_str(), i->mask.c_str());
return MOD_RES_DENY;
}
}
@@ -122,33 +109,10 @@ class ModuleChanFilter : public Module
return MOD_RES_PASSTHRU;
}
- virtual ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
- {
- if (target_type == TYPE_CHANNEL)
- {
- return ProcessMessages(user,(Channel*)dest,text);
- }
- return MOD_RES_PASSTHRU;
- }
-
- virtual ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
- {
- return OnUserPreMessage(user,dest,target_type,text,status,exempt_list);
- }
-
- virtual void OnSyncChannel(Channel* chan, Module* proto, void* opaque)
- {
- cf.DoSyncChannel(chan, proto, opaque);
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides channel-specific censor lists (like mode +G but varies from channel to channel)", VF_VENDOR);
}
-
- virtual ~ModuleChanFilter()
- {
- }
};
MODULE_INIT(ModuleChanFilter)
diff --git a/src/modules/m_chanhistory.cpp b/src/modules/m_chanhistory.cpp
index e48e67fe5..f6e7ea40e 100644
--- a/src/modules/m_chanhistory.cpp
+++ b/src/modules/m_chanhistory.cpp
@@ -19,8 +19,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides channel history for a given number of lines */
-
struct HistoryItem
{
time_t ts;
@@ -32,10 +30,13 @@ struct HistoryList
{
std::deque<HistoryItem> lines;
unsigned int maxlen, maxtime;
- HistoryList(unsigned int len, unsigned int time) : maxlen(len), maxtime(time) {}
+ std::string param;
+
+ HistoryList(unsigned int len, unsigned int time, const std::string& oparam)
+ : maxlen(len), maxtime(time), param(oparam) { }
};
-class HistoryMode : public ModeHandler
+class HistoryMode : public ParamMode<HistoryMode, SimpleExtItem<HistoryList> >
{
bool IsValidDuration(const std::string& duration)
{
@@ -52,110 +53,98 @@ class HistoryMode : public ModeHandler
}
public:
- SimpleExtItem<HistoryList> ext;
unsigned int maxlines;
- HistoryMode(Module* Creator) : ModeHandler(Creator, "history", 'H', PARAM_SETONLY, MODETYPE_CHANNEL),
- ext("history", Creator) { }
+ HistoryMode(Module* Creator)
+ : ParamMode<HistoryMode, SimpleExtItem<HistoryList> >(Creator, "history", 'H')
+ {
+ }
- ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
+ ModeAction OnSet(User* source, Channel* channel, std::string& parameter)
{
- if (adding)
+ std::string::size_type colon = parameter.find(':');
+ if (colon == std::string::npos)
+ return MODEACTION_DENY;
+
+ std::string duration = parameter.substr(colon+1);
+ if ((IS_LOCAL(source)) && ((duration.length() > 10) || (!IsValidDuration(duration))))
+ return MODEACTION_DENY;
+
+ unsigned int len = ConvToInt(parameter.substr(0, colon));
+ int time = InspIRCd::Duration(duration);
+ if (len == 0 || time < 0)
+ return MODEACTION_DENY;
+ if (len > maxlines && IS_LOCAL(source))
+ return MODEACTION_DENY;
+ if (len > maxlines)
+ len = maxlines;
+
+ HistoryList* history = ext.get(channel);
+ if (history)
{
- std::string::size_type colon = parameter.find(':');
- if (colon == std::string::npos)
- return MODEACTION_DENY;
-
- std::string duration = parameter.substr(colon+1);
- if ((IS_LOCAL(source)) && ((duration.length() > 10) || (!IsValidDuration(duration))))
- return MODEACTION_DENY;
-
- unsigned int len = ConvToInt(parameter.substr(0, colon));
- int time = ServerInstance->Duration(duration);
- if (len == 0 || time < 0)
- return MODEACTION_DENY;
- if (len > maxlines && IS_LOCAL(source))
- return MODEACTION_DENY;
- if (len > maxlines)
- len = maxlines;
- if (parameter == channel->GetModeParameter(this))
- return MODEACTION_DENY;
-
- HistoryList* history = ext.get(channel);
- if (history)
- {
- // Shrink the list if the new line number limit is lower than the old one
- if (len < history->lines.size())
- history->lines.erase(history->lines.begin(), history->lines.begin() + (history->lines.size() - len));
+ // Shrink the list if the new line number limit is lower than the old one
+ if (len < history->lines.size())
+ history->lines.erase(history->lines.begin(), history->lines.begin() + (history->lines.size() - len));
- history->maxlen = len;
- history->maxtime = time;
- }
- else
- {
- ext.set(channel, new HistoryList(len, time));
- }
- channel->SetModeParam('H', parameter);
+ history->maxlen = len;
+ history->maxtime = time;
+ history->param = parameter;
}
else
{
- if (!channel->IsModeSet('H'))
- return MODEACTION_DENY;
- ext.unset(channel);
- channel->SetModeParam('H', "");
+ ext.set(channel, new HistoryList(len, time, parameter));
}
return MODEACTION_ALLOW;
}
+
+ void SerializeParam(Channel* chan, const HistoryList* history, std::string& out)
+ {
+ out.append(history->param);
+ }
};
class ModuleChanHistory : public Module
{
HistoryMode m;
bool sendnotice;
+ UserModeReference botmode;
+ bool dobots;
public:
- ModuleChanHistory() : m(this)
- {
- }
-
- void init()
+ ModuleChanHistory() : m(this), botmode(this, "bot")
{
- ServerInstance->Modules->AddService(m);
- ServerInstance->Modules->AddService(m.ext);
-
- Implementation eventlist[] = { I_OnPostJoin, I_OnUserMessage, I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- OnRehash(NULL);
}
- void OnRehash(User*)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ConfigTag* tag = ServerInstance->Config->ConfValue("chanhistory");
m.maxlines = tag->getInt("maxlines", 50);
sendnotice = tag->getBool("notice", true);
+ dobots = tag->getBool("bots", true);
}
- void OnUserMessage(User* user,void* dest,int target_type, const std::string &text, char status, const CUList&)
+ void OnUserMessage(User* user, void* dest, int target_type, const std::string &text, char status, const CUList&, MessageType msgtype) CXX11_OVERRIDE
{
- if (target_type == TYPE_CHANNEL && status == 0)
+ if ((target_type == TYPE_CHANNEL) && (status == 0) && (msgtype == MSG_PRIVMSG))
{
Channel* c = (Channel*)dest;
HistoryList* list = m.ext.get(c);
if (list)
{
- char buf[MAXBUF];
- snprintf(buf, MAXBUF, ":%s PRIVMSG %s :%s",
- user->GetFullHost().c_str(), c->name.c_str(), text.c_str());
- list->lines.push_back(HistoryItem(buf));
+ const std::string line = ":" + user->GetFullHost() + " PRIVMSG " + c->name + " :" + text;
+ list->lines.push_back(HistoryItem(line));
if (list->lines.size() > list->maxlen)
list->lines.pop_front();
}
}
}
- void OnPostJoin(Membership* memb)
+ void OnPostJoin(Membership* memb) CXX11_OVERRIDE
{
if (IS_REMOTE(memb->user))
return;
+ if (memb->user->IsModeSet(botmode) && !dobots)
+ return;
+
HistoryList* list = m.ext.get(memb->chan);
if (!list)
return;
@@ -165,8 +154,7 @@ class ModuleChanHistory : public Module
if (sendnotice)
{
- memb->user->WriteServ("NOTICE %s :Replaying up to %d lines of pre-join history spanning up to %d seconds",
- memb->chan->name.c_str(), list->maxlen, list->maxtime);
+ memb->user->WriteNotice("Replaying up to " + ConvToStr(list->maxlen) + " lines of pre-join history spanning up to " + ConvToStr(list->maxtime) + " seconds");
}
for(std::deque<HistoryItem>::iterator i = list->lines.begin(); i != list->lines.end(); ++i)
@@ -176,7 +164,7 @@ class ModuleChanHistory : public Module
}
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides channel history replayed on join", VF_VENDOR);
}
diff --git a/src/modules/m_chanlog.cpp b/src/modules/m_chanlog.cpp
index 6dbc0e7a8..736285be8 100644
--- a/src/modules/m_chanlog.cpp
+++ b/src/modules/m_chanlog.cpp
@@ -20,11 +20,8 @@
#include "inspircd.h"
-/* $ModDesc: Logs snomask output to channel(s). */
-
class ModuleChanLog : public Module
{
- private:
/*
* Multimap so people can redirect a snomask to multiple channels.
*/
@@ -32,19 +29,7 @@ class ModuleChanLog : public Module
ChanLogTargets logstreams;
public:
- void init()
- {
- Implementation eventlist[] = { I_OnRehash, I_OnSendSnotice };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
-
- OnRehash(NULL);
- }
-
- virtual ~ModuleChanLog()
- {
- }
-
- virtual void OnRehash(User *user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
std::string snomasks;
std::string channel;
@@ -59,100 +44,44 @@ class ModuleChanLog : public Module
if (channel.empty() || snomasks.empty())
{
- ServerInstance->Logs->Log("m_chanlog", DEFAULT, "Malformed chanlog tag, ignoring");
+ ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "Malformed chanlog tag, ignoring");
continue;
}
for (std::string::const_iterator it = snomasks.begin(); it != snomasks.end(); it++)
{
logstreams.insert(std::make_pair(*it, channel));
- ServerInstance->Logs->Log("m_chanlog", DEFAULT, "Logging %c to %s", *it, channel.c_str());
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Logging %c to %s", *it, channel.c_str());
}
}
}
- virtual ModResult OnSendSnotice(char &sno, std::string &desc, const std::string &msg)
+ ModResult OnSendSnotice(char &sno, std::string &desc, const std::string &msg) CXX11_OVERRIDE
{
std::pair<ChanLogTargets::const_iterator, ChanLogTargets::const_iterator> itpair = logstreams.equal_range(sno);
if (itpair.first == itpair.second)
return MOD_RES_PASSTHRU;
- char buf[MAXBUF];
- snprintf(buf, MAXBUF, "\2%s\2: %s", desc.c_str(), msg.c_str());
+ const std::string snotice = "\2" + desc + "\2: " + msg;
for (ChanLogTargets::const_iterator it = itpair.first; it != itpair.second; ++it)
{
Channel *c = ServerInstance->FindChan(it->second);
if (c)
{
- c->WriteChannelWithServ(ServerInstance->Config->ServerName, "PRIVMSG %s :%s", c->name.c_str(), buf);
- ServerInstance->PI->SendChannelPrivmsg(c, 0, buf);
+ c->WriteChannelWithServ(ServerInstance->Config->ServerName, "PRIVMSG %s :%s", c->name.c_str(), snotice.c_str());
+ ServerInstance->PI->SendMessage(c, 0, snotice);
}
}
return MOD_RES_PASSTHRU;
}
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Logs snomask output to channel(s).", VF_VENDOR);
}
};
-
MODULE_INIT(ModuleChanLog)
-
-
-
-
-
-
-
-
-
-/*
- * This is for the "old" chanlog module which intercepted messages going to the logfile..
- * I don't consider it all that useful, and it's quite dangerous if setup incorrectly, so
- * this is defined out but left intact in case someone wants to develop it further someday.
- *
- * -- w00t (aug 23rd, 2008)
- */
-#define OLD_CHANLOG 0
-
-#if OLD_CHANLOG
-class ChannelLogStream : public LogStream
-{
- private:
- std::string channel;
-
- public:
- ChannelLogStream(int loglevel, const std::string &chan) : LogStream(loglevel), channel(chan)
- {
- }
-
- virtual void OnLog(int loglevel, const std::string &type, const std::string &msg)
- {
- Channel *c = ServerInstance->FindChan(channel);
- static bool Logging = false;
-
- if (loglevel < this->loglvl)
- return;
-
- if (Logging)
- return;
-
- if (c)
- {
- Logging = true; // this avoids (rare chance) loops with logging server IO on networks
- char buf[MAXBUF];
- snprintf(buf, MAXBUF, "\2%s\2: %s", type.c_str(), msg.c_str());
-
- c->WriteChannelWithServ(ServerInstance->Config->ServerName, "PRIVMSG %s :%s", c->name.c_str(), buf);
- ServerInstance->PI->SendChannelPrivmsg(c, 0, buf);
- Logging = false;
- }
- }
-};
-#endif
-
diff --git a/src/modules/m_channames.cpp b/src/modules/m_channames.cpp
index 325e8fee1..1fb5b2a40 100644
--- a/src/modules/m_channames.cpp
+++ b/src/modules/m_channames.cpp
@@ -19,83 +19,77 @@
#include "inspircd.h"
-/* $ModDesc: Implements config tags which allow changing characters allowed in channel names */
-
static std::bitset<256> allowedmap;
-class NewIsChannelHandler : public HandlerBase2<bool, const char*, size_t>
+class NewIsChannelHandler : public HandlerBase1<bool, const std::string&>
{
public:
- NewIsChannelHandler() { }
- virtual ~NewIsChannelHandler() { }
- virtual bool Call(const char*, size_t);
+ bool Call(const std::string&);
};
-bool NewIsChannelHandler::Call(const char* c, size_t max)
+bool NewIsChannelHandler::Call(const std::string& channame)
{
- /* check for no name - don't check for !*chname, as if it is empty, it won't be '#'! */
- if (!c || *c++ != '#')
+ if (channame.empty() || channame.length() > ServerInstance->Config->Limits.ChanMax || channame[0] != '#')
+ return false;
+
+ for (std::string::const_iterator c = channame.begin(); c != channame.end(); ++c)
+ {
+ unsigned int i = *c & 0xFF;
+ if (!allowedmap[i])
return false;
+ }
- while (*c && --max)
- {
- unsigned int i = *c++ & 0xFF;
- if (!allowedmap[i])
- return false;
- }
- // a name of exactly max length will have max = 1 here; the null does not trigger --max
- return max;
+ return true;
}
class ModuleChannelNames : public Module
{
- private:
NewIsChannelHandler myhandler;
- caller2<bool, const char*, size_t> rememberer;
+ caller1<bool, const std::string&> rememberer;
bool badchan;
+ ChanModeReference permchannelmode;
public:
- ModuleChannelNames() : rememberer(ServerInstance->IsChannel), badchan(false)
+ ModuleChannelNames()
+ : rememberer(ServerInstance->IsChannel)
+ , badchan(false)
+ , permchannelmode(this, "permanent")
{
}
- void init()
+ void init() CXX11_OVERRIDE
{
ServerInstance->IsChannel = &myhandler;
- Implementation eventlist[] = { I_OnRehash, I_OnUserKick };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- OnRehash(NULL);
}
void ValidateChans()
{
badchan = true;
- std::vector<Channel*> chanvec;
- for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); ++i)
- {
- if (!ServerInstance->IsChannel(i->second->name.c_str(), MAXBUF))
- chanvec.push_back(i->second);
- }
- std::vector<Channel*>::reverse_iterator c2 = chanvec.rbegin();
- while (c2 != chanvec.rend())
+ const chan_hash& chans = ServerInstance->GetChans();
+ for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); )
{
- Channel* c = *c2++;
- if (c->IsModeSet('P') && c->GetUserCounter())
+ Channel* c = i->second;
+ // Move iterator before we begin kicking
+ ++i;
+ if (ServerInstance->IsChannel(c->name))
+ continue; // The name of this channel is still valid
+
+ if (c->IsModeSet(permchannelmode) && c->GetUserCounter())
{
std::vector<std::string> modes;
modes.push_back(c->name);
- modes.push_back("-P");
+ modes.push_back(std::string("-") + permchannelmode->GetModeChar());
- ServerInstance->SendGlobalMode(modes, ServerInstance->FakeClient);
+ ServerInstance->Modes->Process(modes, ServerInstance->FakeClient);
}
- const UserMembList* users = c->GetUsers();
- for(UserMembCIter j = users->begin(); j != users->end(); )
+ Channel::MemberMap& users = c->userlist;
+ for (Channel::MemberMap::iterator j = users.begin(); j != users.end(); )
{
if (IS_LOCAL(j->first))
{
// KickUser invalidates the iterator
- UserMembCIter it = j++;
- c->KickUser(ServerInstance->FakeClient, it->first, "Channel name no longer valid");
+ Channel::MemberMap::iterator it = j++;
+ c->KickUser(ServerInstance->FakeClient, it, "Channel name no longer valid");
}
else
++j;
@@ -104,7 +98,7 @@ class ModuleChannelNames : public Module
badchan = false;
}
- virtual void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ConfigTag* tag = ServerInstance->Config->ConfValue("channames");
std::string denyToken = tag->getString("denyrange");
@@ -134,24 +128,25 @@ class ModuleChannelNames : public Module
ValidateChans();
}
- virtual void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& except_list)
+ void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& except_list) CXX11_OVERRIDE
{
if (badchan)
{
- const UserMembList* users = memb->chan->GetUsers();
- for(UserMembCIter i = users->begin(); i != users->end(); i++)
+ const Channel::MemberMap& users = memb->chan->GetUsers();
+ for (Channel::MemberMap::const_iterator i = users.begin(); i != users.end(); ++i)
if (i->first != memb->user)
except_list.insert(i->first);
}
}
- virtual ~ModuleChannelNames()
+ CullResult cull() CXX11_OVERRIDE
{
ServerInstance->IsChannel = rememberer;
ValidateChans();
+ return Module::cull();
}
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Implements config tags which allow changing characters allowed in channel names", VF_VENDOR);
}
diff --git a/src/modules/m_channelban.cpp b/src/modules/m_channelban.cpp
index 6eec486ea..4d3f80e36 100644
--- a/src/modules/m_channelban.cpp
+++ b/src/modules/m_channelban.cpp
@@ -20,28 +20,15 @@
#include "inspircd.h"
-/* $ModDesc: Implements extban +b j: - matching channel bans */
-
class ModuleBadChannelExtban : public Module
{
- private:
public:
- void init()
- {
- Implementation eventlist[] = { I_OnCheckBan, I_On005Numeric };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- ~ModuleBadChannelExtban()
- {
- }
-
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Extban 'j' - channel status/join ban", VF_OPTCOMMON|VF_VENDOR);
}
- ModResult OnCheckBan(User *user, Channel *c, const std::string& mask)
+ ModResult OnCheckBan(User *user, Channel *c, const std::string& mask) CXX11_OVERRIDE
{
if ((mask.length() > 2) && (mask[0] == 'j') && (mask[1] == ':'))
{
@@ -53,17 +40,11 @@ class ModuleBadChannelExtban : public Module
rm = mask.substr(3);
status = mh->GetModeChar();
}
- for (UCListIter i = user->chans.begin(); i != user->chans.end(); i++)
+ for (User::ChanList::iterator i = user->chans.begin(); i != user->chans.end(); i++)
{
- if (InspIRCd::Match((**i).name, rm))
+ if (InspIRCd::Match((*i)->chan->name, rm))
{
- if (status)
- {
- Membership* memb = (**i).GetUser(user);
- if (memb && memb->hasMode(status))
- return MOD_RES_DENY;
- }
- else
+ if (!status || (*i)->hasMode(status))
return MOD_RES_DENY;
}
}
@@ -71,12 +52,10 @@ class ModuleBadChannelExtban : public Module
return MOD_RES_PASSTHRU;
}
- void On005Numeric(std::string &output)
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
- ServerInstance->AddExtBanChar('j');
+ tokens["EXTBAN"].push_back('j');
}
};
-
MODULE_INIT(ModuleBadChannelExtban)
-
diff --git a/src/modules/m_chanprotect.cpp b/src/modules/m_chanprotect.cpp
deleted file mode 100644
index affd0c8d6..000000000
--- a/src/modules/m_chanprotect.cpp
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2006-2009 Robin Burchell <robin+git@viroteck.net>
- * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
- * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com>
- * Copyright (C) 2004-2008 Craig Edwards <craigedwards@brainbox.cc>
- * Copyright (C) 2007 John Brooks <john.brooks@dereferenced.net>
- * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-
-/* $ModDesc: Provides channel modes +a and +q */
-
-#define PROTECT_VALUE 40000
-#define FOUNDER_VALUE 50000
-
-struct ChanProtectSettings
-{
- bool DeprivSelf;
- bool DeprivOthers;
- bool FirstInGetsFounder;
- bool booting;
- ChanProtectSettings() : booting(true) {}
-};
-
-static ChanProtectSettings settings;
-
-/** Handles basic operation of +qa channel modes
- */
-class FounderProtectBase
-{
- private:
- const std::string type;
- const char mode;
- const int list;
- const int end;
- public:
- FounderProtectBase(char Mode, const std::string &mtype, int l, int e) :
- type(mtype), mode(Mode), list(l), end(e)
- {
- }
-
- void RemoveMode(Channel* channel, irc::modestacker* stack)
- {
- const UserMembList* cl = channel->GetUsers();
- std::vector<std::string> mode_junk;
- mode_junk.push_back(channel->name);
- irc::modestacker modestack(false);
- std::deque<std::string> stackresult;
-
- for (UserMembCIter i = cl->begin(); i != cl->end(); i++)
- {
- if (i->second->hasMode(mode))
- {
- if (stack)
- stack->Push(mode, i->first->nick);
- else
- modestack.Push(mode, i->first->nick);
- }
- }
-
- if (stack)
- return;
-
- while (modestack.GetStackedLine(stackresult))
- {
- mode_junk.insert(mode_junk.end(), stackresult.begin(), stackresult.end());
- ServerInstance->SendMode(mode_junk, ServerInstance->FakeClient);
- mode_junk.erase(mode_junk.begin() + 1, mode_junk.end());
- }
- }
-
- void DisplayList(User* user, Channel* channel)
- {
- const UserMembList* cl = channel->GetUsers();
- for (UserMembCIter i = cl->begin(); i != cl->end(); ++i)
- {
- if (i->second->hasMode(mode))
- {
- user->WriteServ("%d %s %s %s", list, user->nick.c_str(), channel->name.c_str(), i->first->nick.c_str());
- }
- }
- user->WriteServ("%d %s %s :End of channel %s list", end, user->nick.c_str(), channel->name.c_str(), type.c_str());
- }
-
- bool CanRemoveOthers(User* u1, Channel* c)
- {
- Membership* m1 = c->GetUser(u1);
- return (settings.DeprivOthers && m1 && m1->hasMode(mode));
- }
-};
-
-/** Abstraction of FounderProtectBase for channel mode +q
- */
-class ChanFounder : public ModeHandler, public FounderProtectBase
-{
- public:
- ChanFounder(Module* Creator)
- : ModeHandler(Creator, "founder", 'q', PARAM_ALWAYS, MODETYPE_CHANNEL),
- FounderProtectBase('q', "founder", 386, 387)
- {
- ModeHandler::list = true;
- levelrequired = FOUNDER_VALUE;
- m_paramtype = TR_NICK;
- }
-
- void setPrefix(int pfx)
- {
- prefix = pfx;
- }
-
- unsigned int GetPrefixRank()
- {
- return FOUNDER_VALUE;
- }
-
- void RemoveMode(Channel* channel, irc::modestacker* stack)
- {
- FounderProtectBase::RemoveMode(channel, stack);
- }
-
- void RemoveMode(User* user, irc::modestacker* stack)
- {
- }
-
- ModResult AccessCheck(User* source, Channel* channel, std::string &parameter, bool adding)
- {
- User* theuser = ServerInstance->FindNick(parameter);
- // remove own privs?
- if (source == theuser && !adding && settings.DeprivSelf)
- return MOD_RES_ALLOW;
-
- if (!adding && FounderProtectBase::CanRemoveOthers(source, channel))
- {
- return MOD_RES_PASSTHRU;
- }
- else
- {
- source->WriteNumeric(468, "%s %s :Only servers may set channel mode +q", source->nick.c_str(), channel->name.c_str());
- return MOD_RES_DENY;
- }
- }
-
- ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
- {
- return MODEACTION_ALLOW;
- }
-
- void DisplayList(User* user, Channel* channel)
- {
- FounderProtectBase::DisplayList(user,channel);
- }
-};
-
-/** Abstraction of FounderProtectBase for channel mode +a
- */
-class ChanProtect : public ModeHandler, public FounderProtectBase
-{
- public:
- ChanProtect(Module* Creator)
- : ModeHandler(Creator, "admin", 'a', PARAM_ALWAYS, MODETYPE_CHANNEL),
- FounderProtectBase('a',"protected user", 388, 389)
- {
- ModeHandler::list = true;
- levelrequired = PROTECT_VALUE;
- m_paramtype = TR_NICK;
- }
-
- void setPrefix(int pfx)
- {
- prefix = pfx;
- }
-
-
- unsigned int GetPrefixRank()
- {
- return PROTECT_VALUE;
- }
-
- void RemoveMode(Channel* channel, irc::modestacker* stack)
- {
- FounderProtectBase::RemoveMode(channel, stack);
- }
-
- void RemoveMode(User* user, irc::modestacker* stack)
- {
- }
-
- ModResult AccessCheck(User* source, Channel* channel, std::string &parameter, bool adding)
- {
- User* theuser = ServerInstance->FindNick(parameter);
- // source has +q
- if (channel->GetPrefixValue(source) > PROTECT_VALUE)
- return MOD_RES_ALLOW;
-
- // removing own privs?
- if (source == theuser && !adding && settings.DeprivSelf)
- return MOD_RES_ALLOW;
-
- if (!adding && FounderProtectBase::CanRemoveOthers(source, channel))
- {
- return MOD_RES_PASSTHRU;
- }
- else
- {
- source->WriteNumeric(482, "%s %s :You are not a channel founder", source->nick.c_str(), channel->name.c_str());
- return MOD_RES_DENY;
- }
- }
-
- ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
- {
- return MODEACTION_ALLOW;
- }
-
- void DisplayList(User* user, Channel* channel)
- {
- FounderProtectBase::DisplayList(user, channel);
- }
-
-};
-
-class ModuleChanProtect : public Module
-{
- ChanProtect cp;
- ChanFounder cf;
- public:
- ModuleChanProtect() : cp(this), cf(this)
- {
- }
-
- void init()
- {
- /* Load config stuff */
- LoadSettings();
- settings.booting = false;
-
- ServerInstance->Modules->AddService(cf);
- ServerInstance->Modules->AddService(cp);
-
- Implementation eventlist[] = { I_OnUserPreJoin };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- void LoadSettings()
- {
- ConfigTag* tag = ServerInstance->Config->ConfValue("chanprotect");
-
- settings.FirstInGetsFounder = tag->getBool("noservices");
-
- std::string qpre = tag->getString("qprefix");
- char QPrefix = qpre.empty() ? 0 : qpre[0];
-
- std::string apre = tag->getString("aprefix");
- char APrefix = apre.empty() ? 0 : apre[0];
-
- if ((APrefix && QPrefix) && APrefix == QPrefix)
- throw ModuleException("What the smeg, why are both your +q and +a prefixes the same character?");
-
- if (settings.booting)
- {
- if (APrefix && ServerInstance->Modes->FindPrefix(APrefix) && ServerInstance->Modes->FindPrefix(APrefix) != &cp)
- throw ModuleException("Looks like the +a prefix you picked for m_chanprotect is already in use. Pick another.");
-
- if (QPrefix && ServerInstance->Modes->FindPrefix(QPrefix) && ServerInstance->Modes->FindPrefix(QPrefix) != &cf)
- throw ModuleException("Looks like the +q prefix you picked for m_chanprotect is already in use. Pick another.");
-
- cp.setPrefix(APrefix);
- cf.setPrefix(QPrefix);
- }
- settings.DeprivSelf = tag->getBool("deprotectself", true);
- settings.DeprivOthers = tag->getBool("deprotectothers", true);
- }
-
- ModResult OnUserPreJoin(User *user, Channel *chan, const char *cname, std::string &privs, const std::string &keygiven)
- {
- // if the user is the first user into the channel, mark them as the founder, but only if
- // the config option for it is set
-
- if (settings.FirstInGetsFounder && !chan)
- privs += 'q';
-
- return MOD_RES_PASSTHRU;
- }
-
- Version GetVersion()
- {
- return Version("Founder and Protect modes (+qa)", VF_VENDOR);
- }
-};
-
-MODULE_INIT(ModuleChanProtect)
diff --git a/src/modules/m_check.cpp b/src/modules/m_check.cpp
index 96b357f20..92f003a84 100644
--- a/src/modules/m_check.cpp
+++ b/src/modules/m_check.cpp
@@ -20,16 +20,51 @@
*/
-/* $ModDesc: Provides the /CHECK command to retrieve information on a user, channel, hostname or IP address */
-
#include "inspircd.h"
+#include "listmode.h"
/** Handle /CHECK
*/
class CommandCheck : public Command
{
+ UserModeReference snomaskmode;
+
+ std::string GetSnomasks(User* user)
+ {
+ std::string ret;
+ if (snomaskmode)
+ ret = snomaskmode->GetUserParameter(user);
+
+ if (ret.empty())
+ ret = "+";
+ return ret;
+ }
+
+ static void dumpListMode(User* user, const std::string& checkstr, const ListModeBase::ModeList* list)
+ {
+ if (!list)
+ return;
+
+ std::string buf = checkstr + " modelist";
+ const std::string::size_type headlen = buf.length();
+ const size_t maxline = ServerInstance->Config->Limits.MaxLine;
+ for (ListModeBase::ModeList::const_iterator i = list->begin(); i != list->end(); ++i)
+ {
+ if (buf.size() + i->mask.size() + 1 > maxline)
+ {
+ user->SendText(buf);
+ buf.erase(headlen);
+ }
+ buf.append(" ").append(i->mask);
+ }
+ if (buf.length() > headlen)
+ user->SendText(buf);
+ }
+
public:
- CommandCheck(Module* parent) : Command(parent,"CHECK", 1)
+ CommandCheck(Module* parent)
+ : Command(parent,"CHECK", 1)
+ , snomaskmode(parent, "snomask")
{
flags_needed = 'o'; syntax = "<nickname>|<ip>|<hostmask>|<channel> <server>";
}
@@ -90,26 +125,26 @@ class CommandCheck : public Command
user->SendText(checkstr + " realnuh " + targuser->GetFullRealHost());
user->SendText(checkstr + " realname " + targuser->fullname);
user->SendText(checkstr + " modes +" + targuser->FormatModes());
- user->SendText(checkstr + " snomasks +" + targuser->FormatNoticeMasks());
- user->SendText(checkstr + " server " + targuser->server);
+ user->SendText(checkstr + " snomasks " + GetSnomasks(targuser));
+ user->SendText(checkstr + " server " + targuser->server->GetName());
user->SendText(checkstr + " uid " + targuser->uuid);
user->SendText(checkstr + " signon " + timestring(targuser->signon));
user->SendText(checkstr + " nickts " + timestring(targuser->age));
if (loctarg)
- user->SendText(checkstr + " lastmsg " + timestring(targuser->idle_lastmsg));
+ user->SendText(checkstr + " lastmsg " + timestring(loctarg->idle_lastmsg));
- if (IS_AWAY(targuser))
+ if (targuser->IsAway())
{
/* user is away */
user->SendText(checkstr + " awaytime " + timestring(targuser->awaytime));
user->SendText(checkstr + " awaymsg " + targuser->awaymsg);
}
- if (IS_OPER(targuser))
+ if (targuser->IsOper())
{
OperInfo* oper = targuser->oper;
/* user is an oper of type ____ */
- user->SendText(checkstr + " opertype " + oper->NameStr());
+ user->SendText(checkstr + " opertype " + oper->name);
if (loctarg)
{
std::string umodes;
@@ -145,8 +180,8 @@ class CommandCheck : public Command
if (loctarg)
{
- user->SendText(checkstr + " clientaddr " + irc::sockets::satouser(loctarg->client_sa));
- user->SendText(checkstr + " serveraddr " + irc::sockets::satouser(loctarg->server_sa));
+ user->SendText(checkstr + " clientaddr " + loctarg->client_sa.str());
+ user->SendText(checkstr + " serveraddr " + loctarg->server_sa.str());
std::string classname = loctarg->GetClass()->name;
if (!classname.empty())
@@ -155,10 +190,14 @@ class CommandCheck : public Command
else
user->SendText(checkstr + " onip " + targuser->GetIPString());
- for (UCListIter i = targuser->chans.begin(); i != targuser->chans.end(); i++)
+ for (User::ChanList::iterator i = targuser->chans.begin(); i != targuser->chans.end(); i++)
{
- Channel* c = *i;
- chliststr.append(c->GetPrefixChar(targuser)).append(c->name).append(" ");
+ Membership* memb = *i;
+ Channel* c = memb->chan;
+ char prefix = memb->GetPrefixChar();
+ if (prefix)
+ chliststr.push_back(prefix);
+ chliststr.append(c->name).push_back(' ');
}
std::stringstream dump(chliststr);
@@ -185,32 +224,25 @@ class CommandCheck : public Command
/* now the ugly bit, spool current members of a channel. :| */
- const UserMembList *ulist= targchan->GetUsers();
+ const Channel::MemberMap& ulist = targchan->GetUsers();
/* note that unlike /names, we do NOT check +i vs in the channel */
- for (UserMembCIter i = ulist->begin(); i != ulist->end(); i++)
+ for (Channel::MemberMap::const_iterator i = ulist.begin(); i != ulist.end(); ++i)
{
- char tmpbuf[MAXBUF];
/*
- * Unlike Asuka, I define a clone as coming from the same host. --w00t
- */
- snprintf(tmpbuf, MAXBUF, "%-3lu %s%s (%s@%s) %s ", ServerInstance->Users->GlobalCloneCount(i->first), targchan->GetAllPrefixChars(i->first), i->first->nick.c_str(), i->first->ident.c_str(), i->first->dhost.c_str(), i->first->fullname.c_str());
- user->SendText(checkstr + " member " + tmpbuf);
+ * Unlike Asuka, I define a clone as coming from the same host. --w00t
+ */
+ const UserManager::CloneCounts& clonecount = ServerInstance->Users->GetCloneCounts(i->first);
+ user->SendText("%s member %-3u %s%s (%s@%s) %s ",
+ checkstr.c_str(), clonecount.global,
+ i->second->GetAllPrefixChars(), i->first->nick.c_str(),
+ i->first->ident.c_str(), i->first->dhost.c_str(), i->first->fullname.c_str());
}
- irc::modestacker modestack(true);
- for(BanList::iterator b = targchan->bans.begin(); b != targchan->bans.end(); ++b)
- {
- modestack.Push('b', b->data);
- }
- std::vector<std::string> stackresult;
- std::vector<TranslateType> dummy;
- while (modestack.GetStackedLine(stackresult))
- {
- creator->ProtoSendMode(user, TYPE_CHANNEL, targchan, stackresult, dummy);
- stackresult.clear();
- }
- FOREACH_MOD(I_OnSyncChannel,OnSyncChannel(targchan,creator,user));
+ const ModeParser::ListModeList& listmodes = ServerInstance->Modes->GetListModes();
+ for (ModeParser::ListModeList::const_iterator i = listmodes.begin(); i != listmodes.end(); ++i)
+ dumpListMode(user, checkstr, (*i)->GetList(targchan));
+
dumpExt(user, checkstr, targchan);
}
else
@@ -219,7 +251,8 @@ class CommandCheck : public Command
long x = 0;
/* hostname or other */
- for (user_hash::const_iterator a = ServerInstance->Users->clientlist->begin(); a != ServerInstance->Users->clientlist->end(); a++)
+ const user_hash& users = ServerInstance->Users->GetUsers();
+ for (user_hash::const_iterator a = users.begin(); a != users.end(); ++a)
{
if (InspIRCd::Match(a->second->host, parameters[0], ascii_case_insensitive_map) || InspIRCd::Match(a->second->dhost, parameters[0], ascii_case_insensitive_map))
{
@@ -250,42 +283,15 @@ class CommandCheck : public Command
}
};
-
class ModuleCheck : public Module
{
- private:
CommandCheck mycommand;
public:
ModuleCheck() : mycommand(this)
{
}
- void init()
- {
- ServerInstance->Modules->AddService(mycommand);
- }
-
- ~ModuleCheck()
- {
- }
-
- void ProtoSendMode(void* uv, TargetTypeFlags, void*, const std::vector<std::string>& result, const std::vector<TranslateType>&)
- {
- User* user = (User*)uv;
- std::string checkstr(":");
- checkstr.append(ServerInstance->Config->ServerName);
- checkstr.append(" 304 ");
- checkstr.append(user->nick);
- checkstr.append(" :CHECK modelist");
- for(unsigned int i=0; i < result.size(); i++)
- {
- checkstr.append(" ");
- checkstr.append(result[i]);
- }
- user->SendText(checkstr);
- }
-
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("CHECK command, view user, channel, IP address or hostname information", VF_VENDOR|VF_OPTCOMMON);
}
diff --git a/src/modules/m_chghost.cpp b/src/modules/m_chghost.cpp
index 6aaed7831..43b2a323b 100644
--- a/src/modules/m_chghost.cpp
+++ b/src/modules/m_chghost.cpp
@@ -21,13 +21,10 @@
#include "inspircd.h"
-/* $ModDesc: Provides support for the CHGHOST command */
-
/** Handle /CHGHOST
*/
class CommandChghost : public Command
{
- private:
char* hostmap;
public:
CommandChghost(Module* Creator, char* hmap) : Command(Creator,"CHGHOST", 2), hostmap(hmap)
@@ -35,16 +32,16 @@ class CommandChghost : public Command
allow_empty_last_param = false;
flags_needed = 'o';
syntax = "<nick> <newhost>";
- TRANSLATE3(TR_NICK, TR_TEXT, TR_END);
+ TRANSLATE2(TR_NICK, TR_TEXT);
}
CmdResult Handle(const std::vector<std::string> &parameters, User *user)
{
const char* x = parameters[1].c_str();
- if (parameters[1].length() > 63)
+ if (parameters[1].length() > ServerInstance->Config->Limits.MaxHost)
{
- user->WriteServ("NOTICE %s :*** CHGHOST: Host too long", user->nick.c_str());
+ user->WriteNotice("*** CHGHOST: Host too long");
return CMD_FAILURE;
}
@@ -52,7 +49,7 @@ class CommandChghost : public Command
{
if (!hostmap[(unsigned char)*x])
{
- user->WriteServ("NOTICE "+user->nick+" :*** CHGHOST: Invalid characters in hostname");
+ user->WriteNotice("*** CHGHOST: Invalid characters in hostname");
return CMD_FAILURE;
}
}
@@ -60,15 +57,15 @@ class CommandChghost : public Command
User* dest = ServerInstance->FindNick(parameters[0]);
// Allow services to change the host of unregistered users
- if ((!dest) || ((dest->registered != REG_ALL) && (!ServerInstance->ULine(user->server))))
+ if ((!dest) || ((dest->registered != REG_ALL) && (!user->server->IsULine())))
{
- user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel", user->nick.c_str(), parameters[0].c_str());
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", parameters[0].c_str());
return CMD_FAILURE;
}
if (IS_LOCAL(dest))
{
- if ((dest->ChangeDisplayedHost(parameters[1].c_str())) && (!ServerInstance->ULine(user->server)))
+ if ((dest->ChangeDisplayedHost(parameters[1])) && (!user->server->IsULine()))
{
// fix by brain - ulines set hosts silently
ServerInstance->SNO->WriteGlobalSno('a', user->nick+" used CHGHOST to make the displayed host of "+dest->nick+" become "+dest->dhost);
@@ -92,20 +89,13 @@ class ModuleChgHost : public Module
{
CommandChghost cmd;
char hostmap[256];
+
public:
ModuleChgHost() : cmd(this, hostmap)
{
}
- void init()
- {
- OnRehash(NULL);
- ServerInstance->Modules->AddService(cmd);
- Implementation eventlist[] = { I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
std::string hmap = ServerInstance->Config->ConfValue("hostname")->getString("charmap", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_/0123456789");
@@ -114,15 +104,10 @@ class ModuleChgHost : public Module
hostmap[(unsigned char)*n] = 1;
}
- ~ModuleChgHost()
- {
- }
-
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for the CHGHOST command", VF_OPTCOMMON | VF_VENDOR);
}
-
};
MODULE_INIT(ModuleChgHost)
diff --git a/src/modules/m_chgident.cpp b/src/modules/m_chgident.cpp
index 2112e45a3..c855216bf 100644
--- a/src/modules/m_chgident.cpp
+++ b/src/modules/m_chgident.cpp
@@ -22,8 +22,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides support for the CHGIDENT command */
-
/** Handle /CHGIDENT
*/
class CommandChgident : public Command
@@ -34,7 +32,7 @@ class CommandChgident : public Command
allow_empty_last_param = false;
flags_needed = 'o';
syntax = "<nick> <newident>";
- TRANSLATE3(TR_NICK, TR_TEXT, TR_END);
+ TRANSLATE2(TR_NICK, TR_TEXT);
}
CmdResult Handle(const std::vector<std::string> &parameters, User *user)
@@ -43,27 +41,27 @@ class CommandChgident : public Command
if ((!dest) || (dest->registered != REG_ALL))
{
- user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel", user->nick.c_str(), parameters[0].c_str());
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", parameters[0].c_str());
return CMD_FAILURE;
}
if (parameters[1].length() > ServerInstance->Config->Limits.IdentMax)
{
- user->WriteServ("NOTICE %s :*** CHGIDENT: Ident is too long", user->nick.c_str());
+ user->WriteNotice("*** CHGIDENT: Ident is too long");
return CMD_FAILURE;
}
- if (!ServerInstance->IsIdent(parameters[1].c_str()))
+ if (!ServerInstance->IsIdent(parameters[1]))
{
- user->WriteServ("NOTICE %s :*** CHGIDENT: Invalid characters in ident", user->nick.c_str());
+ user->WriteNotice("*** CHGIDENT: Invalid characters in ident");
return CMD_FAILURE;
}
if (IS_LOCAL(dest))
{
- dest->ChangeIdent(parameters[1].c_str());
+ dest->ChangeIdent(parameters[1]);
- if (!ServerInstance->ULine(user->server))
+ if (!user->server->IsULine())
ServerInstance->SNO->WriteGlobalSno('a', "%s used CHGIDENT to change %s's ident to '%s'", user->nick.c_str(), dest->nick.c_str(), dest->ident.c_str());
}
@@ -79,7 +77,6 @@ class CommandChgident : public Command
}
};
-
class ModuleChgIdent : public Module
{
CommandChgident cmd;
@@ -89,21 +86,10 @@ public:
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cmd);
- }
-
- virtual ~ModuleChgIdent()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for the CHGIDENT command", VF_OPTCOMMON | VF_VENDOR);
}
-
};
MODULE_INIT(ModuleChgIdent)
-
diff --git a/src/modules/m_chgname.cpp b/src/modules/m_chgname.cpp
index 73ae3d487..830d5070b 100644
--- a/src/modules/m_chgname.cpp
+++ b/src/modules/m_chgname.cpp
@@ -20,8 +20,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides support for the CHGNAME command */
-
/** Handle /CHGNAME
*/
class CommandChgname : public Command
@@ -32,7 +30,7 @@ class CommandChgname : public Command
allow_empty_last_param = false;
flags_needed = 'o';
syntax = "<nick> <newname>";
- TRANSLATE3(TR_NICK, TR_TEXT, TR_END);
+ TRANSLATE2(TR_NICK, TR_TEXT);
}
CmdResult Handle(const std::vector<std::string> &parameters, User *user)
@@ -41,25 +39,25 @@ class CommandChgname : public Command
if ((!dest) || (dest->registered != REG_ALL))
{
- user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel", user->nick.c_str(), parameters[0].c_str());
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", parameters[0].c_str());
return CMD_FAILURE;
}
if (parameters[1].empty())
{
- user->WriteServ("NOTICE %s :*** CHGNAME: GECOS must be specified", user->nick.c_str());
+ user->WriteNotice("*** CHGNAME: GECOS must be specified");
return CMD_FAILURE;
}
if (parameters[1].length() > ServerInstance->Config->Limits.MaxGecos)
{
- user->WriteServ("NOTICE %s :*** CHGNAME: GECOS too long", user->nick.c_str());
+ user->WriteNotice("*** CHGNAME: GECOS too long");
return CMD_FAILURE;
}
if (IS_LOCAL(dest))
{
- dest->ChangeName(parameters[1].c_str());
+ dest->ChangeName(parameters[1]);
ServerInstance->SNO->WriteGlobalSno('a', "%s used CHGNAME to change %s's GECOS to '%s'", user->nick.c_str(), dest->nick.c_str(), dest->fullname.c_str());
}
@@ -75,7 +73,6 @@ class CommandChgname : public Command
}
};
-
class ModuleChgName : public Module
{
CommandChgname cmd;
@@ -85,20 +82,10 @@ public:
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cmd);
- }
-
- virtual ~ModuleChgName()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for the CHGNAME command", VF_OPTCOMMON | VF_VENDOR);
}
-
};
MODULE_INIT(ModuleChgName)
diff --git a/src/modules/m_clearchan.cpp b/src/modules/m_clearchan.cpp
new file mode 100644
index 000000000..5fcec36f1
--- /dev/null
+++ b/src/modules/m_clearchan.cpp
@@ -0,0 +1,218 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "xline.h"
+
+class CommandClearChan : public Command
+{
+ public:
+ Channel* activechan;
+
+ CommandClearChan(Module* Creator)
+ : Command(Creator, "CLEARCHAN", 1, 3)
+ {
+ syntax = "<channel> [<KILL|KICK|G|Z>] [<reason>]";
+ flags_needed = 'o';
+
+ // Stop the linking mod from forwarding ENCAP'd CLEARCHAN commands, see below why
+ force_manual_route = true;
+ }
+
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user)
+ {
+ Channel* chan = activechan = ServerInstance->FindChan(parameters[0]);
+ if (!chan)
+ {
+ user->WriteNotice("The channel " + parameters[0] + " does not exist.");
+ return CMD_FAILURE;
+ }
+
+ // See what method the oper wants to use, default to KILL
+ std::string method("KILL");
+ if (parameters.size() > 1)
+ {
+ method = parameters[1];
+ std::transform(method.begin(), method.end(), method.begin(), ::toupper);
+ }
+
+ XLineFactory* xlf = NULL;
+ bool kick = (method == "KICK");
+ if ((!kick) && (method != "KILL"))
+ {
+ if ((method != "Z") && (method != "G"))
+ {
+ user->WriteNotice("Invalid method for clearing " + chan->name);
+ return CMD_FAILURE;
+ }
+
+ xlf = ServerInstance->XLines->GetFactory(method);
+ if (!xlf)
+ return CMD_FAILURE;
+ }
+
+ const std::string reason = parameters.size() > 2 ? parameters.back() : "Clearing " + chan->name;
+
+ if (!user->server->IsSilentULine())
+ ServerInstance->SNO->WriteToSnoMask((IS_LOCAL(user) ? 'a' : 'A'), user->nick + " has cleared \002" + chan->name + "\002 (" + method + "): " + reason);
+
+ user->WriteNotice("Clearing \002" + chan->name + "\002 (" + method + "): " + reason);
+
+ {
+ // Route this command manually so it is sent before the QUITs we are about to generate.
+ // The idea is that by the time our QUITs reach the next hop, it has already removed all their
+ // clients from the channel, meaning victims on other servers won't see the victims on this
+ // server quitting.
+ std::vector<std::string> eparams;
+ eparams.push_back(chan->name);
+ eparams.push_back(method);
+ eparams.push_back(":");
+ eparams.back().append(reason);
+ ServerInstance->PI->BroadcastEncap(this->name, eparams, user, user);
+ }
+
+ // Attach to the appropriate hook so we're able to hide the QUIT/KICK messages
+ Implementation hook = (kick ? I_OnUserKick : I_OnBuildNeighborList);
+ ServerInstance->Modules->Attach(hook, creator);
+
+ std::string mask;
+ // Now remove all local non-opers from the channel
+ Channel::MemberMap& users = chan->userlist;
+ for (Channel::MemberMap::iterator i = users.begin(); i != users.end(); )
+ {
+ User* curr = i->first;
+ const Channel::MemberMap::iterator currit = i;
+ ++i;
+
+ if (!IS_LOCAL(curr) || curr->IsOper())
+ continue;
+
+ // If kicking users, remove them and skip the QuitUser()
+ if (kick)
+ {
+ chan->KickUser(ServerInstance->FakeClient, currit, reason);
+ continue;
+ }
+
+ // If we are banning users then create the XLine and add it
+ if (xlf)
+ {
+ XLine* xline;
+ try
+ {
+ mask = ((method[0] == 'Z') ? curr->GetIPString() : "*@" + curr->host);
+ xline = xlf->Generate(ServerInstance->Time(), 60*60, user->nick, reason, mask);
+ }
+ catch (ModuleException& ex)
+ {
+ // Nothing, move on to the next user
+ continue;
+ }
+
+ if (!ServerInstance->XLines->AddLine(xline, user))
+ delete xline;
+ }
+
+ ServerInstance->Users->QuitUser(curr, reason);
+ }
+
+ ServerInstance->Modules->Detach(hook, creator);
+ if (xlf)
+ ServerInstance->XLines->ApplyLines();
+
+ return CMD_SUCCESS;
+ }
+};
+
+class ModuleClearChan : public Module
+{
+ CommandClearChan cmd;
+
+ public:
+ ModuleClearChan()
+ : cmd(this)
+ {
+ }
+
+ void init()
+ {
+ // Only attached while we are working; don't react to events otherwise
+ ServerInstance->Modules->DetachAll(this);
+ }
+
+ void OnBuildNeighborList(User* source, IncludeChanList& include, std::map<User*, bool>& exception) CXX11_OVERRIDE
+ {
+ bool found = false;
+ for (IncludeChanList::iterator i = include.begin(); i != include.end(); ++i)
+ {
+ if ((*i)->chan == cmd.activechan)
+ {
+ // Don't show the QUIT to anyone in the channel by default
+ include.erase(i);
+ found = true;
+ break;
+ }
+ }
+
+ const Channel::MemberMap& users = cmd.activechan->GetUsers();
+ for (Channel::MemberMap::const_iterator i = users.begin(); i != users.end(); ++i)
+ {
+ LocalUser* curr = IS_LOCAL(i->first);
+ if (!curr)
+ continue;
+
+ if (curr->IsOper())
+ {
+ // If another module has removed the channel we're working on from the list of channels
+ // to consider for sending the QUIT to then don't add exceptions for opers, because the
+ // module before us doesn't want them to see it or added the exceptions already.
+ // If there is a value for this oper in excepts already, this won't overwrite it.
+ if (found)
+ exception.insert(std::make_pair(curr, true));
+ continue;
+ }
+ else if (!include.empty() && curr->chans.size() > 1)
+ {
+ // This is a victim and potentially has another common channel with the user quitting,
+ // add a negative exception overwriting the previous value, if any.
+ exception[curr] = false;
+ }
+ }
+ }
+
+ void OnUserKick(User* source, Membership* memb, const std::string& reason, CUList& excepts) CXX11_OVERRIDE
+ {
+ // Hide the KICK from all non-opers
+ User* leaving = memb->user;
+ const Channel::MemberMap& users = memb->chan->GetUsers();
+ for (Channel::MemberMap::const_iterator i = users.begin(); i != users.end(); ++i)
+ {
+ User* curr = i->first;
+ if ((IS_LOCAL(curr)) && (!curr->IsOper()) && (curr != leaving))
+ excepts.insert(curr);
+ }
+ }
+
+ Version GetVersion() CXX11_OVERRIDE
+ {
+ return Version("Adds /CLEARCHAN that allows opers to masskick, masskill or mass-G/ZLine users on a channel", VF_VENDOR|VF_OPTCOMMON);
+ }
+};
+
+MODULE_INIT(ModuleClearChan)
diff --git a/src/modules/m_cloaking.cpp b/src/modules/m_cloaking.cpp
index 105d68833..5d62c9cf6 100644
--- a/src/modules/m_cloaking.cpp
+++ b/src/modules/m_cloaking.cpp
@@ -24,16 +24,10 @@
#include "inspircd.h"
-#include "hash.h"
-
-/* $ModDesc: Provides masking of user hostnames */
+#include "modules/hash.h"
enum CloakMode
{
- /** 1.2-compatible host-based cloak */
- MODE_COMPAT_HOST,
- /** 1.2-compatible IP-only cloak */
- MODE_COMPAT_IPONLY,
/** 2.0 cloak of "half" of the hostname plus the full IP hash */
MODE_HALF_CLOAK,
/** 2.0 cloak of IP hash, split at 2 common CIDR range points */
@@ -49,7 +43,6 @@ class CloakUser : public ModeHandler
{
public:
LocalStringExt ext;
-
std::string debounce_uid;
time_t debounce_ts;
int debounce_count;
@@ -70,7 +63,7 @@ class CloakUser : public ModeHandler
*/
if (!user)
{
- dest->SetMode('x',adding);
+ dest->SetMode(this, adding);
return MODEACTION_ALLOW;
}
@@ -87,7 +80,7 @@ class CloakUser : public ModeHandler
debounce_ts = ServerInstance->Time();
}
- if (adding == user->IsModeSet('x'))
+ if (adding == user->IsModeSet(this))
return MODEACTION_DENY;
/* don't allow this user to spam modechanges */
@@ -106,8 +99,8 @@ class CloakUser : public ModeHandler
}
if (cloak)
{
- user->ChangeDisplayedHost(cloak->c_str());
- user->SetMode('x',true);
+ user->ChangeDisplayedHost(*cloak);
+ user->SetMode(this, true);
return MODEACTION_ALLOW;
}
else
@@ -118,12 +111,11 @@ class CloakUser : public ModeHandler
/* User is removing the mode, so restore their real host
* and make it match the displayed one.
*/
- user->SetMode('x',false);
+ user->SetMode(this, false);
user->ChangeDisplayedHost(user->host.c_str());
return MODEACTION_ALLOW;
}
}
-
};
class CommandCloak : public Command
@@ -147,7 +139,6 @@ class ModuleCloaking : public Module
std::string prefix;
std::string suffix;
std::string key;
- unsigned int compatkey[4];
const char* xtab[4];
dynamic_reference<HashProvider> Hash;
@@ -155,18 +146,6 @@ class ModuleCloaking : public Module
{
}
- void init()
- {
- OnRehash(NULL);
-
- ServerInstance->Modules->AddService(cu);
- ServerInstance->Modules->AddService(ck);
- ServerInstance->Modules->AddService(cu.ext);
-
- Implementation eventlist[] = { I_OnRehash, I_OnCheckBan, I_OnUserConnect, I_OnChangeHost };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
/** This function takes a domain name string and returns just the last two domain parts,
* or the last domain part if only two are available. Failing that it just returns what it was given.
*
@@ -224,63 +203,6 @@ class ModuleCloaking : public Module
return rv;
}
- std::string CompatCloak4(const char* ip)
- {
- irc::sepstream seps(ip, '.');
- std::string octet[4];
- int i[4];
-
- for (int j = 0; j < 4; j++)
- {
- seps.GetToken(octet[j]);
- i[j] = atoi(octet[j].c_str());
- }
-
- octet[3] = octet[0] + "." + octet[1] + "." + octet[2] + "." + octet[3];
- octet[2] = octet[0] + "." + octet[1] + "." + octet[2];
- octet[1] = octet[0] + "." + octet[1];
-
- /* Reset the Hash module and send it our IV */
-
- std::string rv;
-
- /* Send the Hash module a different hex table for each octet group's Hash sum */
- for (int k = 0; k < 4; k++)
- {
- rv.append(Hash->sumIV(compatkey, xtab[(compatkey[k]+i[k]) % 4], octet[k]).substr(0,6));
- if (k < 3)
- rv.append(".");
- }
- /* Stick them all together */
- return rv;
- }
-
- std::string CompatCloak6(const char* ip)
- {
- std::vector<std::string> hashies;
- std::string item;
- int rounds = 0;
-
- /* Reset the Hash module and send it our IV */
-
- for (const char* input = ip; *input; input++)
- {
- item += *input;
- if (item.length() > 7)
- {
- hashies.push_back(Hash->sumIV(compatkey, xtab[(compatkey[0]+rounds) % 4], item).substr(0,8));
- item.clear();
- }
- rounds++;
- }
- if (!item.empty())
- {
- hashies.push_back(Hash->sumIV(compatkey, xtab[(compatkey[0]+rounds) % 4], item).substr(0,8));
- }
- /* Stick them all together */
- return irc::stringjoiner(":", hashies, 0, hashies.size() - 1).GetJoined();
- }
-
std::string SegmentIP(const irc::sockets::sockaddrs& ip, bool full)
{
std::string bindata;
@@ -348,7 +270,7 @@ class ModuleCloaking : public Module
return rv;
}
- ModResult OnCheckBan(User* user, Channel* chan, const std::string& mask)
+ ModResult OnCheckBan(User* user, Channel* chan, const std::string& mask) CXX11_OVERRIDE
{
LocalUser* lu = IS_LOCAL(user);
if (!lu)
@@ -359,9 +281,8 @@ class ModuleCloaking : public Module
/* Check if they have a cloaked host, but are not using it */
if (cloak && *cloak != user->dhost)
{
- char cmask[MAXBUF];
- snprintf(cmask, MAXBUF, "%s!%s@%s", user->nick.c_str(), user->ident.c_str(), cloak->c_str());
- if (InspIRCd::Match(cmask,mask))
+ const std::string cloakMask = user->nick + "!" + user->ident + "@" + *cloak;
+ if (InspIRCd::Match(cloakMask, mask))
return MOD_RES_DENY;
}
return MOD_RES_PASSTHRU;
@@ -375,32 +296,22 @@ class ModuleCloaking : public Module
// this unsets umode +x on every host change. If we are actually doing a +x
// mode change, we will call SetMode back to true AFTER the host change is done.
- void OnChangeHost(User* u, const std::string& host)
+ void OnChangeHost(User* u, const std::string& host) CXX11_OVERRIDE
{
- if(u->IsModeSet('x'))
+ if (u->IsModeSet(cu))
{
- u->SetMode('x', false);
- u->WriteServ("MODE %s -x", u->nick.c_str());
+ u->SetMode(cu, false);
+ u->WriteCommand("MODE", "-" + ConvToStr(cu.GetModeChar()));
}
}
- ~ModuleCloaking()
- {
- }
-
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
std::string testcloak = "broken";
if (Hash)
{
switch (mode)
{
- case MODE_COMPAT_HOST:
- testcloak = prefix + "-" + Hash->sumIV(compatkey, xtab[0], "*").substr(0,10);
- break;
- case MODE_COMPAT_IPONLY:
- testcloak = Hash->sumIV(compatkey, xtab[0], "*").substr(0,10);
- break;
case MODE_HALF_CLOAK:
testcloak = prefix + SegmentCloak("*", 3, 8) + suffix;
break;
@@ -411,82 +322,23 @@ class ModuleCloaking : public Module
return Version("Provides masking of user hostnames", VF_COMMON|VF_VENDOR, testcloak);
}
- void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ConfigTag* tag = ServerInstance->Config->ConfValue("cloak");
prefix = tag->getString("prefix");
suffix = tag->getString("suffix", ".IP");
std::string modestr = tag->getString("mode");
- if (modestr == "compat-host")
- mode = MODE_COMPAT_HOST;
- else if (modestr == "compat-ip")
- mode = MODE_COMPAT_IPONLY;
- else if (modestr == "half")
+ if (modestr == "half")
mode = MODE_HALF_CLOAK;
else if (modestr == "full")
mode = MODE_OPAQUE;
else
- throw ModuleException("Bad value for <cloak:mode>; must be one of compat-host, compat-ip, half, full");
-
- if (mode == MODE_COMPAT_HOST || mode == MODE_COMPAT_IPONLY)
- {
- bool lowercase = tag->getBool("lowercase");
-
- /* These are *not* using the need_positive parameter of ReadInteger -
- * that will limit the valid values to only the positive values in a
- * signed int. Instead, accept any value that fits into an int and
- * cast it to an unsigned int. That will, a bit oddly, give us the full
- * spectrum of an unsigned integer. - Special
- *
- * We must limit the keys or else we get different results on
- * amd64/x86 boxes. - psychon */
- const unsigned int limit = 0x80000000;
- compatkey[0] = (unsigned int) tag->getInt("key1");
- compatkey[1] = (unsigned int) tag->getInt("key2");
- compatkey[2] = (unsigned int) tag->getInt("key3");
- compatkey[3] = (unsigned int) tag->getInt("key4");
-
- if (!lowercase)
- {
- xtab[0] = "F92E45D871BCA630";
- xtab[1] = "A1B9D80C72E653F4";
- xtab[2] = "1ABC078934DEF562";
- xtab[3] = "ABCDEF5678901234";
- }
- else
- {
- xtab[0] = "f92e45d871bca630";
- xtab[1] = "a1b9d80c72e653f4";
- xtab[2] = "1abc078934def562";
- xtab[3] = "abcdef5678901234";
- }
-
- if (prefix.empty())
- prefix = ServerInstance->Config->Network;
+ throw ModuleException("Bad value for <cloak:mode>; must be half or full");
- if (!compatkey[0] || !compatkey[1] || !compatkey[2] || !compatkey[3] ||
- compatkey[0] >= limit || compatkey[1] >= limit || compatkey[2] >= limit || compatkey[3] >= limit)
- {
- std::string detail;
- if (!compatkey[0] || compatkey[0] >= limit)
- detail = "<cloak:key1> is not valid, it may be set to a too high/low value, or it may not exist.";
- else if (!compatkey[1] || compatkey[1] >= limit)
- detail = "<cloak:key2> is not valid, it may be set to a too high/low value, or it may not exist.";
- else if (!compatkey[2] || compatkey[2] >= limit)
- detail = "<cloak:key3> is not valid, it may be set to a too high/low value, or it may not exist.";
- else if (!compatkey[3] || compatkey[3] >= limit)
- detail = "<cloak:key4> is not valid, it may be set to a too high/low value, or it may not exist.";
-
- throw ModuleException("You have not defined cloak keys for m_cloaking!!! THIS IS INSECURE AND SHOULD BE CHECKED! - " + detail);
- }
- }
- else
- {
- key = tag->getString("key");
- if (key.empty() || key == "secret")
- throw ModuleException("You have not defined cloak keys for m_cloaking. Define <cloak:key> as a network-wide secret.");
- }
+ key = tag->getString("key");
+ if (key.empty() || key == "secret")
+ throw ModuleException("You have not defined cloak keys for m_cloaking. Define <cloak:key> as a network-wide secret.");
}
std::string GenCloak(const irc::sockets::sockaddrs& ip, const std::string& ipstr, const std::string& host)
@@ -495,29 +347,6 @@ class ModuleCloaking : public Module
switch (mode)
{
- case MODE_COMPAT_HOST:
- {
- if (ipstr != host)
- {
- std::string tail = LastTwoDomainParts(host);
-
- // xtab is not used here due to a bug in 1.2 cloaking
- chost = prefix + "-" + Hash->sumIV(compatkey, "0123456789abcdef", host).substr(0,8) + tail;
-
- /* Fix by brain - if the cloaked host is > the max length of a host (64 bytes
- * according to the DNS RFC) then they get cloaked as an IP.
- */
- if (chost.length() <= 64)
- break;
- }
- // fall through to IP cloak
- }
- case MODE_COMPAT_IPONLY:
- if (ip.sa.sa_family == AF_INET6)
- chost = CompatCloak6(ipstr.c_str());
- else
- chost = CompatCloak4(ipstr.c_str());
- break;
case MODE_HALF_CLOAK:
{
if (ipstr != host)
@@ -533,7 +362,7 @@ class ModuleCloaking : public Module
return chost;
}
- void OnUserConnect(LocalUser* dest)
+ void OnUserConnect(LocalUser* dest) CXX11_OVERRIDE
{
std::string* cloak = cu.ext.get(dest);
if (cloak)
@@ -554,7 +383,7 @@ CmdResult CommandCloak::Handle(const std::vector<std::string> &parameters, User
else
cloak = mod->GenCloak(sa, "", parameters[0]);
- user->WriteServ("NOTICE %s :*** Cloak for %s is %s", user->nick.c_str(), parameters[0].c_str(), cloak.c_str());
+ user->WriteNotice("*** Cloak for " + parameters[0] + " is " + cloak);
return CMD_SUCCESS;
}
diff --git a/src/modules/m_clones.cpp b/src/modules/m_clones.cpp
index 92b1bda78..c51c8d3b4 100644
--- a/src/modules/m_clones.cpp
+++ b/src/modules/m_clones.cpp
@@ -21,8 +21,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides the /CLONES command to retrieve information on clones. */
-
/** Handle /CLONES
*/
class CommandClones : public Command
@@ -50,11 +48,12 @@ class CommandClones : public Command
user->WriteServ(clonesstr + " START");
/* hostname or other */
- // XXX I really don't like marking global_clones public for this. at all. -- w00t
- for (clonemap::iterator x = ServerInstance->Users->global_clones.begin(); x != ServerInstance->Users->global_clones.end(); x++)
+ const UserManager::CloneMap& clonemap = ServerInstance->Users->GetCloneMap();
+ for (UserManager::CloneMap::const_iterator i = clonemap.begin(); i != clonemap.end(); ++i)
{
- if (x->second >= limit)
- user->WriteServ(clonesstr + " "+ ConvToStr(x->second) + " " + x->first.str());
+ const UserManager::CloneCounts& counts = i->second;
+ if (counts.global >= limit)
+ user->WriteServ(clonesstr + " " + ConvToStr(counts.global) + " " + i->first.str());
}
user->WriteServ(clonesstr + " END");
@@ -63,31 +62,18 @@ class CommandClones : public Command
}
};
-
class ModuleClones : public Module
{
- private:
CommandClones cmd;
public:
ModuleClones() : cmd(this)
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cmd);
- }
-
- virtual ~ModuleClones()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides the /CLONES command to retrieve information on clones.", VF_VENDOR);
}
-
-
};
MODULE_INIT(ModuleClones)
diff --git a/src/modules/m_close.cpp b/src/modules/m_close.cpp
index 8b0ea3417..f3c751f17 100644
--- a/src/modules/m_close.cpp
+++ b/src/modules/m_close.cpp
@@ -20,8 +20,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides /CLOSE functionality */
-
/** Handle /CLOSE
*/
class CommandClose : public Command
@@ -30,13 +28,15 @@ class CommandClose : public Command
/* Command 'close', needs operator */
CommandClose(Module* Creator) : Command(Creator,"CLOSE", 0)
{
- flags_needed = 'o'; }
+ flags_needed = 'o';
+ }
CmdResult Handle (const std::vector<std::string> &parameters, User *src)
{
std::map<std::string,int> closed;
- for (LocalUserList::const_iterator u = ServerInstance->Users->local_users.begin(); u != ServerInstance->Users->local_users.end(); ++u)
+ const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers();
+ for (UserManager::LocalList::const_iterator u = list.begin(); u != list.end(); ++u)
{
LocalUser* user = *u;
if (user->registered != REG_ALL)
@@ -50,13 +50,14 @@ class CommandClose : public Command
int total = 0;
for (std::map<std::string,int>::iterator ci = closed.begin(); ci != closed.end(); ci++)
{
- src->WriteServ("NOTICE %s :*** Closed %d unknown connection%s from [%s]",src->nick.c_str(),(*ci).second,((*ci).second>1)?"s":"",(*ci).first.c_str());
- total += (*ci).second;
+ src->WriteNotice("*** Closed " + ConvToStr(ci->second) + " unknown " + (ci->second == 1 ? "connection" : "connections") +
+ " from [" + ci->first + "]");
+ total += ci->second;
}
if (total)
- src->WriteServ("NOTICE %s :*** %i unknown connection%s closed",src->nick.c_str(),total,(total>1)?"s":"");
+ src->WriteNotice("*** " + ConvToStr(total) + " unknown " + (total == 1 ? "connection" : "connections") + " closed");
else
- src->WriteServ("NOTICE %s :*** No unknown connections found",src->nick.c_str());
+ src->WriteNotice("*** No unknown connections found");
return CMD_SUCCESS;
}
@@ -71,16 +72,7 @@ class ModuleClose : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cmd);
- }
-
- virtual ~ModuleClose()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides /CLOSE functionality", VF_VENDOR);
}
diff --git a/src/modules/m_commonchans.cpp b/src/modules/m_commonchans.cpp
index afa17add4..eab53b9bc 100644
--- a/src/modules/m_commonchans.cpp
+++ b/src/modules/m_commonchans.cpp
@@ -19,8 +19,6 @@
#include "inspircd.h"
-/* $ModDesc: Adds user mode +c, which if set, users must be on a common channel with you to private message you */
-
/** Handles user mode +c
*/
class PrivacyMode : public SimpleUserModeHandler
@@ -37,41 +35,24 @@ class ModulePrivacyMode : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(pm);
- Implementation eventlist[] = { I_OnUserPreMessage, I_OnUserPreNotice };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- virtual ~ModulePrivacyMode()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Adds user mode +c, which if set, users must be on a common channel with you to private message you", VF_VENDOR);
}
- virtual ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+ ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE
{
if (target_type == TYPE_USER)
{
User* t = (User*)dest;
- if (!IS_OPER(user) && (t->IsModeSet('c')) && (!ServerInstance->ULine(user->server)) && !user->SharesChannelWith(t))
+ if (!user->IsOper() && (t->IsModeSet(pm)) && (!user->server->IsULine()) && !user->SharesChannelWith(t))
{
- user->WriteNumeric(ERR_CANTSENDTOUSER, "%s %s :You are not permitted to send private messages to this user (+c set)", user->nick.c_str(), t->nick.c_str());
+ user->WriteNumeric(ERR_CANTSENDTOUSER, "%s :You are not permitted to send private messages to this user (+c set)", t->nick.c_str());
return MOD_RES_DENY;
}
}
return MOD_RES_PASSTHRU;
}
-
- virtual ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
- {
- return OnUserPreMessage(user, dest, target_type, text, status, exempt_list);
- }
};
-
MODULE_INIT(ModulePrivacyMode)
diff --git a/src/modules/m_conn_join.cpp b/src/modules/m_conn_join.cpp
index 6b13ab1aa..d5a095e7f 100644
--- a/src/modules/m_conn_join.cpp
+++ b/src/modules/m_conn_join.cpp
@@ -22,45 +22,93 @@
#include "inspircd.h"
-/* $ModDesc: Forces users to join the specified channel(s) on connect */
+static void JoinChannels(LocalUser* u, const std::string& chanlist)
+{
+ irc::commasepstream chans(chanlist);
+ std::string chan;
+
+ while (chans.GetToken(chan))
+ {
+ if (ServerInstance->IsChannel(chan))
+ Channel::JoinUser(u, chan);
+ }
+}
+
+class JoinTimer : public Timer
+{
+ private:
+ LocalUser* const user;
+ const std::string channels;
+ SimpleExtItem<JoinTimer>& ext;
+
+ public:
+ JoinTimer(LocalUser* u, SimpleExtItem<JoinTimer>& ex, const std::string& chans, unsigned int delay)
+ : Timer(delay, false)
+ , user(u), channels(chans), ext(ex)
+ {
+ ServerInstance->Timers.AddTimer(this);
+ }
+
+ bool Tick(time_t time) CXX11_OVERRIDE
+ {
+ if (user->chans.empty())
+ JoinChannels(user, channels);
+
+ ext.unset(user);
+ return false;
+ }
+};
class ModuleConnJoin : public Module
{
- public:
- void init()
- {
- Implementation eventlist[] = { I_OnPostConnect };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
+ SimpleExtItem<JoinTimer> ext;
+ std::string defchans;
+ unsigned int defdelay;
- void Prioritize()
- {
- ServerInstance->Modules->SetPriority(this, I_OnPostConnect, PRIORITY_LAST);
- }
+ public:
+ ModuleConnJoin() : ext("join_timer", this)
+ {
+ }
- Version GetVersion()
- {
- return Version("Forces users to join the specified channel(s) on connect", VF_VENDOR);
- }
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
+ {
+ ConfigTag* tag = ServerInstance->Config->ConfValue("autojoin");
+ defchans = tag->getString("channel");
+ defdelay = tag->getInt("delay", 0, 0, 60);
+ }
- void OnPostConnect(User* user)
- {
- if (!IS_LOCAL(user))
- return;
+ void Prioritize()
+ {
+ ServerInstance->Modules->SetPriority(this, I_OnPostConnect, PRIORITY_LAST);
+ }
- std::string chanlist = ServerInstance->Config->ConfValue("autojoin")->getString("channel");
- chanlist = user->GetClass()->config->getString("autojoin", chanlist);
+ Version GetVersion() CXX11_OVERRIDE
+ {
+ return Version("Forces users to join the specified channel(s) on connect", VF_VENDOR);
+ }
- irc::commasepstream chans(chanlist);
- std::string chan;
+ void OnPostConnect(User* user) CXX11_OVERRIDE
+ {
+ LocalUser* localuser = IS_LOCAL(user);
+ if (!localuser)
+ return;
- while (chans.GetToken(chan))
- {
- if (ServerInstance->IsChannel(chan.c_str(), ServerInstance->Config->Limits.ChanMax))
- Channel::JoinUser(user, chan.c_str(), false, "", false, ServerInstance->Time());
- }
+ std::string chanlist = localuser->GetClass()->config->getString("autojoin");
+ unsigned int chandelay = localuser->GetClass()->config->getInt("autojoindelay", 0, 0, 60);
+
+ if (chanlist.empty())
+ {
+ if (defchans.empty())
+ return;
+ chanlist = defchans;
+ chandelay = defdelay;
}
-};
+ if (!chandelay)
+ JoinChannels(localuser, chanlist);
+ else
+ ext.set(localuser, new JoinTimer(localuser, ext, chanlist, chandelay));
+ }
+};
MODULE_INIT(ModuleConnJoin)
diff --git a/src/modules/m_conn_umodes.cpp b/src/modules/m_conn_umodes.cpp
index a21462ddf..1e3ea1a49 100644
--- a/src/modules/m_conn_umodes.cpp
+++ b/src/modules/m_conn_umodes.cpp
@@ -22,32 +22,21 @@
#include "inspircd.h"
-/* $ModDesc: Sets (and unsets) modes on users when they connect */
-
class ModuleModesOnConnect : public Module
{
public:
- void init()
- {
- ServerInstance->Modules->Attach(I_OnUserConnect, this);
- }
-
void Prioritize()
{
// for things like +x on connect, important, otherwise we have to resort to config order (bleh) -- w00t
ServerInstance->Modules->SetPriority(this, I_OnUserConnect, PRIORITY_FIRST);
}
- virtual ~ModuleModesOnConnect()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Sets (and unsets) modes on users when they connect", VF_VENDOR);
}
- virtual void OnUserConnect(LocalUser* user)
+ void OnUserConnect(LocalUser* user) CXX11_OVERRIDE
{
// Backup and zero out the disabled usermodes, so that we can override them here.
char save[64];
@@ -62,26 +51,14 @@ class ModuleModesOnConnect : public Module
std::string buf;
std::stringstream ss(ThisModes);
- std::vector<std::string> tokens;
-
- // split ThisUserModes into modes and mode params
- while (ss >> buf)
- tokens.push_back(buf);
-
std::vector<std::string> modes;
modes.push_back(user->nick);
- modes.push_back(tokens[0]);
- if (tokens.size() > 1)
- {
- // process mode params
- for (unsigned int k = 1; k < tokens.size(); k++)
- {
- modes.push_back(tokens[k]);
- }
- }
+ // split ThisUserModes into modes and mode params
+ while (ss >> buf)
+ modes.push_back(buf);
- ServerInstance->Parser->CallHandler("MODE", modes, user);
+ ServerInstance->Modes->Process(modes, user);
}
memcpy(ServerInstance->Config->DisabledUModes, save, 64);
diff --git a/src/modules/m_conn_waitpong.cpp b/src/modules/m_conn_waitpong.cpp
index 1d48220a6..496b04c2d 100644
--- a/src/modules/m_conn_waitpong.cpp
+++ b/src/modules/m_conn_waitpong.cpp
@@ -24,8 +24,6 @@
#include "inspircd.h"
-/* $ModDesc: Forces connecting clients to send a PONG message back to the server before they can complete their connection */
-
class ModuleWaitPong : public Module
{
bool sendsnotice;
@@ -38,35 +36,27 @@ class ModuleWaitPong : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(ext);
- OnRehash(NULL);
- Implementation eventlist[] = { I_OnUserRegister, I_OnCheckReady, I_OnPreCommand, I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ConfigTag* tag = ServerInstance->Config->ConfValue("waitpong");
sendsnotice = tag->getBool("sendsnotice", true);
killonbadreply = tag->getBool("killonbadreply", true);
}
- ModResult OnUserRegister(LocalUser* user)
+ ModResult OnUserRegister(LocalUser* user) CXX11_OVERRIDE
{
std::string pingrpl = ServerInstance->GenRandomStr(10);
user->Write("PING :%s", pingrpl.c_str());
if(sendsnotice)
- user->WriteServ("NOTICE %s :*** If you are having problems connecting due to ping timeouts, please type /quote PONG %s or /raw PONG %s now.", user->nick.c_str(), pingrpl.c_str(), pingrpl.c_str());
+ user->WriteNotice("*** If you are having problems connecting due to ping timeouts, please type /quote PONG " + pingrpl + " or /raw PONG " + pingrpl + " now.");
ext.set(user, pingrpl);
return MOD_RES_PASSTHRU;
}
- ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser* user, bool validated, const std::string &original_line)
+ ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser* user, bool validated, const std::string &original_line) CXX11_OVERRIDE
{
if (command == "PONG")
{
@@ -90,20 +80,15 @@ class ModuleWaitPong : public Module
return MOD_RES_PASSTHRU;
}
- ModResult OnCheckReady(LocalUser* user)
+ ModResult OnCheckReady(LocalUser* user) CXX11_OVERRIDE
{
return ext.get(user) ? MOD_RES_DENY : MOD_RES_PASSTHRU;
}
- ~ModuleWaitPong()
- {
- }
-
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Require pong prior to registration", VF_VENDOR);
}
-
};
MODULE_INIT(ModuleWaitPong)
diff --git a/src/modules/m_connectban.cpp b/src/modules/m_connectban.cpp
index 26120add9..fcb4b09ed 100644
--- a/src/modules/m_connectban.cpp
+++ b/src/modules/m_connectban.cpp
@@ -20,61 +20,39 @@
#include "inspircd.h"
#include "xline.h"
-/* $ModDesc: Throttles the connections of IP ranges who try to connect flood. */
-
class ModuleConnectBan : public Module
{
- private:
- clonemap connects;
+ typedef std::map<irc::sockets::cidr_mask, unsigned int> ConnectMap;
+ ConnectMap connects;
unsigned int threshold;
unsigned int banduration;
unsigned int ipv4_cidr;
unsigned int ipv6_cidr;
- public:
- void init()
- {
- Implementation eventlist[] = { I_OnSetUserIP, I_OnGarbageCollect, I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- OnRehash(NULL);
- }
+ std::string banmessage;
- virtual ~ModuleConnectBan()
- {
- }
-
- virtual Version GetVersion()
+ public:
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Throttles the connections of IP ranges who try to connect flood.", VF_VENDOR);
}
- virtual void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ConfigTag* tag = ServerInstance->Config->ConfValue("connectban");
- ipv4_cidr = tag->getInt("ipv4cidr", 32);
- if (ipv4_cidr == 0)
- ipv4_cidr = 32;
-
- ipv6_cidr = tag->getInt("ipv6cidr", 128);
- if (ipv6_cidr == 0)
- ipv6_cidr = 128;
-
- threshold = tag->getInt("threshold", 10);
- if (threshold == 0)
- threshold = 10;
-
- banduration = ServerInstance->Duration(tag->getString("duration", "10m"));
- if (banduration == 0)
- banduration = 10*60;
+ ipv4_cidr = tag->getInt("ipv4cidr", 32, 1, 32);
+ ipv6_cidr = tag->getInt("ipv6cidr", 128, 1, 128);
+ threshold = tag->getInt("threshold", 10, 1);
+ banduration = tag->getDuration("duration", 10*60, 1);
+ banmessage = tag->getString("banmessage", "Your IP range has been attempting to connect too many times in too short a duration. Wait a while, and you will be able to connect.");
}
- virtual void OnSetUserIP(LocalUser* u)
+ void OnSetUserIP(LocalUser* u) CXX11_OVERRIDE
{
if (u->exempt)
return;
int range = 32;
- clonemap::iterator i;
switch (u->client_sa.sa.sa_family)
{
@@ -87,7 +65,7 @@ class ModuleConnectBan : public Module
}
irc::sockets::cidr_mask mask(u->client_sa, range);
- i = connects.find(mask);
+ ConnectMap::iterator i = connects.find(mask);
if (i != connects.end())
{
@@ -96,7 +74,7 @@ class ModuleConnectBan : public Module
if (i->second >= threshold)
{
// Create zline for set duration.
- ZLine* zl = new ZLine(ServerInstance->Time(), banduration, ServerInstance->Config->ServerName, "Your IP range has been attempting to connect too many times in too short a duration. Wait a while, and you will be able to connect.", mask.str());
+ ZLine* zl = new ZLine(ServerInstance->Time(), banduration, ServerInstance->Config->ServerName, banmessage, mask.str());
if (!ServerInstance->XLines->AddLine(zl, NULL))
{
delete zl;
@@ -104,7 +82,7 @@ class ModuleConnectBan : public Module
}
ServerInstance->XLines->ApplyLines();
std::string maskstr = mask.str();
- std::string timestr = ServerInstance->TimeString(zl->expiry);
+ std::string timestr = InspIRCd::TimeString(zl->expiry);
ServerInstance->SNO->WriteGlobalSno('x',"Module m_connectban added Z:line on *@%s to expire on %s: Connect flooding",
maskstr.c_str(), timestr.c_str());
ServerInstance->SNO->WriteGlobalSno('a', "Connect flooding from IP range %s (%d)", maskstr.c_str(), threshold);
@@ -117,9 +95,9 @@ class ModuleConnectBan : public Module
}
}
- virtual void OnGarbageCollect()
+ void OnGarbageCollect()
{
- ServerInstance->Logs->Log("m_connectban",DEBUG, "Clearing map.");
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Clearing map.");
connects.clear();
}
};
diff --git a/src/modules/m_connflood.cpp b/src/modules/m_connflood.cpp
index f77691e32..2ab906e27 100644
--- a/src/modules/m_connflood.cpp
+++ b/src/modules/m_connflood.cpp
@@ -21,11 +21,8 @@
#include "inspircd.h"
-/* $ModDesc: Connection throttle */
-
class ModuleConnFlood : public Module
{
-private:
int seconds, timeout, boot_wait;
unsigned int conns;
unsigned int maxconns;
@@ -39,19 +36,12 @@ public:
{
}
- void init()
- {
- InitConf();
- Implementation eventlist[] = { I_OnRehash, I_OnUserRegister };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Connection throttle", VF_VENDOR);
}
- void InitConf()
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
/* read configuration variables */
ConfigTag* tag = ServerInstance->Config->ConfValue("connflood");
@@ -67,7 +57,7 @@ public:
first = ServerInstance->Time();
}
- virtual ModResult OnUserRegister(LocalUser* user)
+ ModResult OnUserRegister(LocalUser* user) CXX11_OVERRIDE
{
if (user->exempt)
return MOD_RES_PASSTHRU;
@@ -114,12 +104,6 @@ public:
}
return MOD_RES_PASSTHRU;
}
-
- virtual void OnRehash(User* user)
- {
- InitConf();
- }
-
};
MODULE_INIT(ModuleConnFlood)
diff --git a/src/modules/m_customprefix.cpp b/src/modules/m_customprefix.cpp
index dfc60e082..65c2cbd31 100644
--- a/src/modules/m_customprefix.cpp
+++ b/src/modules/m_customprefix.cpp
@@ -19,89 +19,38 @@
#include "inspircd.h"
-/* $ModDesc: Allows custom prefix modes to be created. */
-
-class CustomPrefixMode : public ModeHandler
+class CustomPrefixMode : public PrefixMode
{
public:
reference<ConfigTag> tag;
- int rank;
bool depriv;
+
CustomPrefixMode(Module* parent, ConfigTag* Tag)
- : ModeHandler(parent, Tag->getString("name"), 0, PARAM_ALWAYS, MODETYPE_CHANNEL), tag(Tag)
+ : PrefixMode(parent, Tag->getString("name"), 0)
+ , tag(Tag)
{
- list = true;
- m_paramtype = TR_NICK;
std::string v = tag->getString("prefix");
prefix = v.c_str()[0];
v = tag->getString("letter");
mode = v.c_str()[0];
- rank = tag->getInt("rank");
- levelrequired = tag->getInt("ranktoset", rank);
+ prefixrank = tag->getInt("rank");
+ levelrequired = tag->getInt("ranktoset", prefixrank);
depriv = tag->getBool("depriv", true);
}
- unsigned int GetPrefixRank()
- {
- return rank;
- }
-
ModResult AccessCheck(User* src, Channel*, std::string& value, bool adding)
{
if (!adding && src->nick == value && depriv)
return MOD_RES_ALLOW;
return MOD_RES_PASSTHRU;
}
-
- void RemoveMode(Channel* channel, irc::modestacker* stack)
- {
- const UserMembList* cl = channel->GetUsers();
- std::vector<std::string> mode_junk;
- mode_junk.push_back(channel->name);
- irc::modestacker modestack(false);
- std::deque<std::string> stackresult;
-
- for (UserMembCIter i = cl->begin(); i != cl->end(); i++)
- {
- if (i->second->hasMode(mode))
- {
- if (stack)
- stack->Push(this->GetModeChar(), i->first->nick);
- else
- modestack.Push(this->GetModeChar(), i->first->nick);
- }
- }
-
- if (stack)
- return;
-
- while (modestack.GetStackedLine(stackresult))
- {
- mode_junk.insert(mode_junk.end(), stackresult.begin(), stackresult.end());
- ServerInstance->SendMode(mode_junk, ServerInstance->FakeClient);
- mode_junk.erase(mode_junk.begin() + 1, mode_junk.end());
- }
- }
-
- void RemoveMode(User* user, irc::modestacker* stack)
- {
- }
-
- ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
- {
- return MODEACTION_ALLOW;
- }
};
class ModuleCustomPrefix : public Module
{
std::vector<CustomPrefixMode*> modes;
public:
- ModuleCustomPrefix()
- {
- }
-
- void init()
+ void init() CXX11_OVERRIDE
{
ConfigTagList tags = ServerInstance->Config->ConfTags("customprefix");
while (tags.first != tags.second)
@@ -110,7 +59,7 @@ class ModuleCustomPrefix : public Module
tags.first++;
CustomPrefixMode* mh = new CustomPrefixMode(this, tag);
modes.push_back(mh);
- if (mh->rank <= 0)
+ if (mh->GetPrefixRank() == 0)
throw ModuleException("Rank must be specified for prefix at " + tag->getTagLocation());
if (!isalpha(mh->GetModeChar()))
throw ModuleException("Mode must be a letter for prefix at " + tag->getTagLocation());
@@ -120,18 +69,17 @@ class ModuleCustomPrefix : public Module
}
catch (ModuleException& e)
{
- throw ModuleException(e.err + " (while creating mode from " + tag->getTagLocation() + ")");
+ throw ModuleException(e.GetReason() + " (while creating mode from " + tag->getTagLocation() + ")");
}
}
}
~ModuleCustomPrefix()
{
- for (std::vector<CustomPrefixMode*>::iterator i = modes.begin(); i != modes.end(); i++)
- delete *i;
+ stdalgo::delete_all(modes);
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides custom prefix channel modes", VF_VENDOR);
}
diff --git a/src/modules/m_customtitle.cpp b/src/modules/m_customtitle.cpp
index c65645bc9..3386e8cd7 100644
--- a/src/modules/m_customtitle.cpp
+++ b/src/modules/m_customtitle.cpp
@@ -21,8 +21,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides the TITLE command which allows setting of CUSTOM WHOIS TITLE line */
-
/** Handle /TITLE
*/
class CommandTitle : public Command
@@ -35,27 +33,10 @@ class CommandTitle : public Command
syntax = "<user> <password>";
}
- bool OneOfMatches(const char* host, const char* ip, const char* hostlist)
- {
- std::stringstream hl(hostlist);
- std::string xhost;
- while (hl >> xhost)
- {
- if (InspIRCd::Match(host, xhost, ascii_case_insensitive_map) || InspIRCd::MatchCIDR(ip, xhost, ascii_case_insensitive_map))
- {
- return true;
- }
- }
- return false;
- }
-
CmdResult Handle(const std::vector<std::string> &parameters, User* user)
{
- char TheHost[MAXBUF];
- char TheIP[MAXBUF];
-
- snprintf(TheHost,MAXBUF,"%s@%s",user->ident.c_str(), user->host.c_str());
- snprintf(TheIP, MAXBUF,"%s@%s",user->ident.c_str(), user->GetIPString());
+ const std::string userHost = user->ident + "@" + user->host;
+ const std::string userIP = user->ident + "@" + user->GetIPString();
ConfigTagList tags = ServerInstance->Config->ConfTags("title");
for (ConfigIter i = tags.first; i != tags.second; ++i)
@@ -67,22 +48,23 @@ class CommandTitle : public Command
std::string title = i->second->getString("title");
std::string vhost = i->second->getString("vhost");
- if (Name == parameters[0] && !ServerInstance->PassCompare(user, pass, parameters[1], hash) && OneOfMatches(TheHost,TheIP,host.c_str()) && !title.empty())
+ if (Name == parameters[0] && ServerInstance->PassCompare(user, pass, parameters[1], hash) &&
+ InspIRCd::MatchMask(host, userHost, userIP) && !title.empty())
{
ctitle.set(user, title);
ServerInstance->PI->SendMetaData(user, "ctitle", title);
if (!vhost.empty())
- user->ChangeDisplayedHost(vhost.c_str());
+ user->ChangeDisplayedHost(vhost);
- user->WriteServ("NOTICE %s :Custom title set to '%s'",user->nick.c_str(), title.c_str());
+ user->WriteNotice("Custom title set to '" + title + "'");
return CMD_SUCCESS;
}
}
- user->WriteServ("NOTICE %s :Invalid title credentials",user->nick.c_str());
+ user->WriteNotice("Invalid title credentials");
return CMD_SUCCESS;
}
@@ -97,15 +79,8 @@ class ModuleCustomTitle : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cmd);
- ServerInstance->Modules->AddService(cmd.ctitle);
- ServerInstance->Modules->Attach(I_OnWhoisLine, this);
- }
-
// :kenny.chatspike.net 320 Brain Azhrarn :is getting paid to play games.
- ModResult OnWhoisLine(User* user, User* dest, int &numeric, std::string &text)
+ ModResult OnWhoisLine(User* user, User* dest, int &numeric, std::string &text) CXX11_OVERRIDE
{
/* We use this and not OnWhois because this triggers for remote, too */
if (numeric == 312)
@@ -114,18 +89,14 @@ class ModuleCustomTitle : public Module
const std::string* ctitle = cmd.ctitle.get(dest);
if (ctitle)
{
- ServerInstance->SendWhoisLine(user, dest, 320, "%s %s :%s",user->nick.c_str(), dest->nick.c_str(), ctitle->c_str());
+ ServerInstance->SendWhoisLine(user, dest, 320, "%s :%s", dest->nick.c_str(), ctitle->c_str());
}
}
/* Don't block anything */
return MOD_RES_PASSTHRU;
}
- ~ModuleCustomTitle()
- {
- }
-
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Custom Title for users", VF_OPTCOMMON | VF_VENDOR);
}
diff --git a/src/modules/m_cycle.cpp b/src/modules/m_cycle.cpp
index 383e7b5a2..c8b6bd8b4 100644
--- a/src/modules/m_cycle.cpp
+++ b/src/modules/m_cycle.cpp
@@ -20,23 +20,21 @@
#include "inspircd.h"
-/* $ModDesc: Provides command CYCLE, acts as a server-side HOP command to part and rejoin a channel. */
-
/** Handle /CYCLE
*/
-class CommandCycle : public Command
+class CommandCycle : public SplitCommand
{
public:
- CommandCycle(Module* Creator) : Command(Creator,"CYCLE", 1)
+ CommandCycle(Module* Creator)
+ : SplitCommand(Creator, "CYCLE", 1)
{
Penalty = 3; syntax = "<channel> :[reason]";
- TRANSLATE3(TR_TEXT, TR_TEXT, TR_END);
}
- CmdResult Handle (const std::vector<std::string> &parameters, User *user)
+ CmdResult HandleLocal(const std::vector<std::string> &parameters, LocalUser* user)
{
Channel* channel = ServerInstance->FindChan(parameters[0]);
- std::string reason = ConvToStr("Cycling");
+ std::string reason = "Cycling";
if (parameters.size() > 1)
{
@@ -46,34 +44,27 @@ class CommandCycle : public Command
if (!channel)
{
- user->WriteNumeric(403, "%s %s :No such channel", user->nick.c_str(), parameters[0].c_str());
+ user->WriteNumeric(ERR_NOSUCHCHANNEL, "%s :No such channel", parameters[0].c_str());
return CMD_FAILURE;
}
if (channel->HasUser(user))
{
- /*
- * technically, this is only ever sent locally, but pays to be safe ;p
- */
- if (IS_LOCAL(user))
+ if (channel->GetPrefixValue(user) < VOICE_VALUE && channel->IsBanned(user))
{
- if (channel->GetPrefixValue(user) < VOICE_VALUE && channel->IsBanned(user))
- {
- /* banned, boned. drop the message. */
- user->WriteServ("NOTICE "+user->nick+" :*** You may not cycle, as you are banned on channel " + channel->name);
- return CMD_FAILURE;
- }
-
- channel->PartUser(user, reason);
-
- Channel::JoinUser(user, parameters[0].c_str(), true, "", false, ServerInstance->Time());
+ // User is banned, send an error and don't cycle them
+ user->WriteNotice("*** You may not cycle, as you are banned on channel " + channel->name);
+ return CMD_FAILURE;
}
+ channel->PartUser(user, reason);
+ Channel::JoinUser(user, parameters[0], true);
+
return CMD_SUCCESS;
}
else
{
- user->WriteNumeric(442, "%s %s :You're not on that channel", user->nick.c_str(), channel->name.c_str());
+ user->WriteNumeric(ERR_NOTONCHANNEL, "%s :You're not on that channel", channel->name.c_str());
}
return CMD_FAILURE;
@@ -84,26 +75,17 @@ class CommandCycle : public Command
class ModuleCycle : public Module
{
CommandCycle cmd;
+
public:
ModuleCycle()
: cmd(this)
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cmd);
- }
-
- virtual ~ModuleCycle()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides command CYCLE, acts as a server-side HOP command to part and rejoin a channel.", VF_VENDOR);
}
-
};
MODULE_INIT(ModuleCycle)
diff --git a/src/modules/m_dccallow.cpp b/src/modules/m_dccallow.cpp
index b42d12968..cc7fbd323 100644
--- a/src/modules/m_dccallow.cpp
+++ b/src/modules/m_dccallow.cpp
@@ -25,8 +25,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides support for the /DCCALLOW command */
-
class BannedFileList
{
public:
@@ -53,12 +51,16 @@ typedef std::vector<DCCAllow> dccallowlist;
dccallowlist* dl;
typedef std::vector<BannedFileList> bannedfilelist;
bannedfilelist bfl;
-SimpleExtItem<dccallowlist>* ext;
+typedef SimpleExtItem<dccallowlist> DCCAllowExt;
class CommandDccallow : public Command
{
+ DCCAllowExt& ext;
+
public:
- CommandDccallow(Module* parent) : Command(parent, "DCCALLOW", 0)
+ CommandDccallow(Module* parent, DCCAllowExt& Ext)
+ : Command(parent, "DCCALLOW", 0)
+ , ext(Ext)
{
syntax = "[(+|-)<nick> [<time>]]|[LIST|HELP]";
/* XXX we need to fix this so it can work with translation stuff (i.e. move +- into a seperate param */
@@ -94,7 +96,7 @@ class CommandDccallow : public Command
}
else
{
- user->WriteNumeric(998, "%s :DCCALLOW command not understood. For help on DCCALLOW, type /DCCALLOW HELP", user->nick.c_str());
+ user->WriteNumeric(998, ":DCCALLOW command not understood. For help on DCCALLOW, type /DCCALLOW HELP");
return CMD_FAILURE;
}
}
@@ -108,7 +110,7 @@ class CommandDccallow : public Command
if (action == '-')
{
// check if it contains any entries
- dl = ext->get(user);
+ dl = ext.get(user);
if (dl)
{
for (dccallowlist::iterator i = dl->begin(); i != dl->end(); ++i)
@@ -117,7 +119,7 @@ class CommandDccallow : public Command
if (i->nickname == target->nick)
{
dl->erase(i);
- user->WriteNumeric(995, "%s %s :Removed %s from your DCCALLOW list", user->nick.c_str(), user->nick.c_str(), target->nick.c_str());
+ user->WriteNumeric(995, "%s :Removed %s from your DCCALLOW list", user->nick.c_str(), target->nick.c_str());
break;
}
}
@@ -127,15 +129,15 @@ class CommandDccallow : public Command
{
if (target == user)
{
- user->WriteNumeric(996, "%s %s :You cannot add yourself to your own DCCALLOW list!", user->nick.c_str(), user->nick.c_str());
+ user->WriteNumeric(996, "%s :You cannot add yourself to your own DCCALLOW list!", user->nick.c_str());
return CMD_FAILURE;
}
- dl = ext->get(user);
+ dl = ext.get(user);
if (!dl)
{
dl = new dccallowlist;
- ext->set(user, dl);
+ ext.set(user, dl);
// add this user to the userlist
ul.push_back(user);
}
@@ -144,7 +146,7 @@ class CommandDccallow : public Command
{
if (k->nickname == target->nick)
{
- user->WriteNumeric(996, "%s %s :%s is already on your DCCALLOW list", user->nick.c_str(), user->nick.c_str(), target->nick.c_str());
+ user->WriteNumeric(996, "%s :%s is already on your DCCALLOW list", user->nick.c_str(), target->nick.c_str());
return CMD_FAILURE;
}
}
@@ -152,10 +154,10 @@ class CommandDccallow : public Command
std::string mask = target->nick+"!"+target->ident+"@"+target->dhost;
std::string default_length = ServerInstance->Config->ConfValue("dccallow")->getString("length");
- long length;
+ unsigned long length;
if (parameters.size() < 2)
{
- length = ServerInstance->Duration(default_length);
+ length = InspIRCd::Duration(default_length);
}
else if (!atoi(parameters[1].c_str()))
{
@@ -163,10 +165,10 @@ class CommandDccallow : public Command
}
else
{
- length = ServerInstance->Duration(parameters[1]);
+ length = InspIRCd::Duration(parameters[1]);
}
- if (!ServerInstance->IsValidMask(mask))
+ if (!InspIRCd::IsValidMask(mask))
{
return CMD_FAILURE;
}
@@ -175,11 +177,11 @@ class CommandDccallow : public Command
if (length > 0)
{
- user->WriteNumeric(993, "%s %s :Added %s to DCCALLOW list for %ld seconds", user->nick.c_str(), user->nick.c_str(), target->nick.c_str(), length);
+ user->WriteNumeric(993, "%s :Added %s to DCCALLOW list for %ld seconds", user->nick.c_str(), target->nick.c_str(), length);
}
else
{
- user->WriteNumeric(994, "%s %s :Added %s to DCCALLOW list for this session", user->nick.c_str(), user->nick.c_str(), target->nick.c_str());
+ user->WriteNumeric(994, "%s :Added %s to DCCALLOW list for this session", user->nick.c_str(), target->nick.c_str());
}
/* route it. */
@@ -189,7 +191,7 @@ class CommandDccallow : public Command
else
{
// nick doesn't exist
- user->WriteNumeric(401, "%s %s :No such nick/channel", user->nick.c_str(), nick.c_str());
+ user->WriteNumeric(401, "%s :No such nick/channel", nick.c_str());
return CMD_FAILURE;
}
}
@@ -203,26 +205,26 @@ class CommandDccallow : public Command
void DisplayHelp(User* user)
{
- user->WriteNumeric(998, "%s :DCCALLOW [(+|-)<nick> [<time>]]|[LIST|HELP]", user->nick.c_str());
- user->WriteNumeric(998, "%s :You may allow DCCs from specific users by specifying a", user->nick.c_str());
- user->WriteNumeric(998, "%s :DCC allow for the user you want to receive DCCs from.", user->nick.c_str());
- user->WriteNumeric(998, "%s :For example, to allow the user Brain to send you inspircd.exe", user->nick.c_str());
- user->WriteNumeric(998, "%s :you would type:", user->nick.c_str());
- user->WriteNumeric(998, "%s :/DCCALLOW +Brain", user->nick.c_str());
- user->WriteNumeric(998, "%s :Brain would then be able to send you files. They would have to", user->nick.c_str());
- user->WriteNumeric(998, "%s :resend the file again if the server gave them an error message", user->nick.c_str());
- user->WriteNumeric(998, "%s :before you added them to your DCCALLOW list.", user->nick.c_str());
- user->WriteNumeric(998, "%s :DCCALLOW entries will be temporary by default, if you want to add", user->nick.c_str());
- user->WriteNumeric(998, "%s :them to your DCCALLOW list until you leave IRC, type:", user->nick.c_str());
- user->WriteNumeric(998, "%s :/DCCALLOW +Brain 0", user->nick.c_str());
- user->WriteNumeric(998, "%s :To remove the user from your DCCALLOW list, type:", user->nick.c_str());
- user->WriteNumeric(998, "%s :/DCCALLOW -Brain", user->nick.c_str());
- user->WriteNumeric(998, "%s :To see the users in your DCCALLOW list, type:", user->nick.c_str());
- user->WriteNumeric(998, "%s :/DCCALLOW LIST", user->nick.c_str());
- user->WriteNumeric(998, "%s :NOTE: If the user leaves IRC or changes their nickname", user->nick.c_str());
- user->WriteNumeric(998, "%s : they will be removed from your DCCALLOW list.", user->nick.c_str());
- user->WriteNumeric(998, "%s : your DCCALLOW list will be deleted when you leave IRC.", user->nick.c_str());
- user->WriteNumeric(999, "%s :End of DCCALLOW HELP", user->nick.c_str());
+ user->WriteNumeric(998, ":DCCALLOW [(+|-)<nick> [<time>]]|[LIST|HELP]");
+ user->WriteNumeric(998, ":You may allow DCCs from specific users by specifying a");
+ user->WriteNumeric(998, ":DCC allow for the user you want to receive DCCs from.");
+ user->WriteNumeric(998, ":For example, to allow the user Brain to send you inspircd.exe");
+ user->WriteNumeric(998, ":you would type:");
+ user->WriteNumeric(998, ":/DCCALLOW +Brain");
+ user->WriteNumeric(998, ":Brain would then be able to send you files. They would have to");
+ user->WriteNumeric(998, ":resend the file again if the server gave them an error message");
+ user->WriteNumeric(998, ":before you added them to your DCCALLOW list.");
+ user->WriteNumeric(998, ":DCCALLOW entries will be temporary by default, if you want to add");
+ user->WriteNumeric(998, ":them to your DCCALLOW list until you leave IRC, type:");
+ user->WriteNumeric(998, ":/DCCALLOW +Brain 0");
+ user->WriteNumeric(998, ":To remove the user from your DCCALLOW list, type:");
+ user->WriteNumeric(998, ":/DCCALLOW -Brain");
+ user->WriteNumeric(998, ":To see the users in your DCCALLOW list, type:");
+ user->WriteNumeric(998, ":/DCCALLOW LIST");
+ user->WriteNumeric(998, ":NOTE: If the user leaves IRC or changes their nickname");
+ user->WriteNumeric(998, ": they will be removed from your DCCALLOW list.");
+ user->WriteNumeric(998, ": your DCCALLOW list will be deleted when you leave IRC.");
+ user->WriteNumeric(999, ":End of DCCALLOW HELP");
LocalUser* localuser = IS_LOCAL(user);
if (localuser)
@@ -232,51 +234,37 @@ class CommandDccallow : public Command
void DisplayDCCAllowList(User* user)
{
// display current DCCALLOW list
- user->WriteNumeric(990, "%s :Users on your DCCALLOW list:", user->nick.c_str());
+ user->WriteNumeric(990, ":Users on your DCCALLOW list:");
- dl = ext->get(user);
+ dl = ext.get(user);
if (dl)
{
for (dccallowlist::const_iterator c = dl->begin(); c != dl->end(); ++c)
{
- user->WriteNumeric(991, "%s %s :%s (%s)", user->nick.c_str(), user->nick.c_str(), c->nickname.c_str(), c->hostmask.c_str());
+ user->WriteNumeric(991, "%s :%s (%s)", user->nick.c_str(), c->nickname.c_str(), c->hostmask.c_str());
}
}
- user->WriteNumeric(992, "%s :End of DCCALLOW list", user->nick.c_str());
+ user->WriteNumeric(992, ":End of DCCALLOW list");
}
};
class ModuleDCCAllow : public Module
{
+ DCCAllowExt ext;
CommandDccallow cmd;
- public:
+ public:
ModuleDCCAllow()
- : cmd(this)
- {
- ext = NULL;
- }
-
- void init()
- {
- ext = new SimpleExtItem<dccallowlist>("dccallow", this);
- ServerInstance->Modules->AddService(*ext);
- ServerInstance->Modules->AddService(cmd);
- ReadFileConf();
- Implementation eventlist[] = { I_OnUserPreMessage, I_OnUserPreNotice, I_OnUserQuit, I_OnUserPostNick, I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- virtual void OnRehash(User* user)
+ : ext("dccallow", this)
+ , cmd(this, ext)
{
- ReadFileConf();
}
- virtual void OnUserQuit(User* user, const std::string &reason, const std::string &oper_message)
+ void OnUserQuit(User* user, const std::string &reason, const std::string &oper_message) CXX11_OVERRIDE
{
- dccallowlist* udl = ext->get(user);
+ dccallowlist* udl = ext.get(user);
// remove their DCCALLOW list if they have one
if (udl)
@@ -291,17 +279,12 @@ class ModuleDCCAllow : public Module
RemoveNick(user);
}
- virtual void OnUserPostNick(User* user, const std::string &oldnick)
+ void OnUserPostNick(User* user, const std::string &oldnick) CXX11_OVERRIDE
{
RemoveNick(user);
}
- virtual ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string &text, char status, CUList &exempt_list)
- {
- return OnUserPreNotice(user, dest, target_type, text, status, exempt_list);
- }
-
- virtual ModResult OnUserPreNotice(User* user, void* dest, int target_type, std::string &text, char status, CUList &exempt_list)
+ ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE
{
if (!IS_LOCAL(user))
return MOD_RES_PASSTHRU;
@@ -323,7 +306,7 @@ class ModuleDCCAllow : public Module
if (strncmp(text.c_str(), "\1DCC ", 5) == 0)
{
- dl = ext->get(u);
+ dl = ext.get(u);
if (dl && dl->size())
{
for (dccallowlist::const_iterator iter = dl->begin(); iter != dl->end(); ++iter)
@@ -369,16 +352,16 @@ class ModuleDCCAllow : public Module
if ((!found) && (defaultaction == "allow"))
return MOD_RES_PASSTHRU;
- user->WriteServ("NOTICE %s :The user %s is not accepting DCC SENDs from you. Your file %s was not sent.", user->nick.c_str(), u->nick.c_str(), filename.c_str());
- u->WriteServ("NOTICE %s :%s (%s@%s) attempted to send you a file named %s, which was blocked.", u->nick.c_str(), user->nick.c_str(), user->ident.c_str(), user->dhost.c_str(), filename.c_str());
- u->WriteServ("NOTICE %s :If you trust %s and were expecting this, you can type /DCCALLOW HELP for information on the DCCALLOW system.", u->nick.c_str(), user->nick.c_str());
+ user->WriteNotice("The user " + u->nick + " is not accepting DCC SENDs from you. Your file " + filename + " was not sent.");
+ u->WriteNotice(user->nick + " (" + user->ident + "@" + user->dhost + ") attempted to send you a file named " + filename + ", which was blocked.");
+ u->WriteNotice("If you trust " + user->nick + " and were expecting this, you can type /DCCALLOW HELP for information on the DCCALLOW system.");
return MOD_RES_DENY;
}
else if ((type == "CHAT") && (blockchat))
{
- user->WriteServ("NOTICE %s :The user %s is not accepting DCC CHAT requests from you.", user->nick.c_str(), u->nick.c_str());
- u->WriteServ("NOTICE %s :%s (%s@%s) attempted to initiate a DCC CHAT session, which was blocked.", u->nick.c_str(), user->nick.c_str(), user->ident.c_str(), user->dhost.c_str());
- u->WriteServ("NOTICE %s :If you trust %s and were expecting this, you can type /DCCALLOW HELP for information on the DCCALLOW system.", u->nick.c_str(), user->nick.c_str());
+ user->WriteNotice("The user " + u->nick + " is not accepting DCC CHAT requests from you.");
+ u->WriteNotice(user->nick + " (" + user->ident + "@" + user->dhost + ") attempted to initiate a DCC CHAT session, which was blocked.");
+ u->WriteNotice("If you trust " + user->nick + " and were expecting this, you can type /DCCALLOW HELP for information on the DCCALLOW system.");
return MOD_RES_DENY;
}
}
@@ -392,7 +375,7 @@ class ModuleDCCAllow : public Module
for (userlist::iterator iter = ul.begin(); iter != ul.end();)
{
User* u = (User*)(*iter);
- dl = ext->get(u);
+ dl = ext.get(u);
if (dl)
{
if (dl->size())
@@ -402,7 +385,7 @@ class ModuleDCCAllow : public Module
{
if (iter2->length != 0 && (iter2->set_on + iter2->length) <= ServerInstance->Time())
{
- u->WriteNumeric(997, "%s %s :DCCALLOW entry for %s has expired", u->nick.c_str(), u->nick.c_str(), iter2->nickname.c_str());
+ u->WriteNumeric(997, "%s :DCCALLOW entry for %s has expired", u->nick.c_str(), iter2->nickname.c_str());
iter2 = dl->erase(iter2);
}
else
@@ -426,7 +409,7 @@ class ModuleDCCAllow : public Module
for (userlist::iterator iter = ul.begin(); iter != ul.end();)
{
User *u = (User*)(*iter);
- dl = ext->get(u);
+ dl = ext.get(u);
if (dl)
{
if (dl->size())
@@ -436,8 +419,8 @@ class ModuleDCCAllow : public Module
if (i->nickname == user->nick)
{
- u->WriteServ("NOTICE %s :%s left the network or changed their nickname and has been removed from your DCCALLOW list", u->nick.c_str(), i->nickname.c_str());
- u->WriteNumeric(995, "%s %s :Removed %s from your DCCALLOW list", u->nick.c_str(), u->nick.c_str(), i->nickname.c_str());
+ u->WriteNotice(i->nickname + " left the network or changed their nickname and has been removed from your DCCALLOW list");
+ u->WriteNumeric(995, "%s :Removed %s from your DCCALLOW list", u->nick.c_str(), i->nickname.c_str());
dl->erase(i);
break;
}
@@ -466,7 +449,7 @@ class ModuleDCCAllow : public Module
}
}
- void ReadFileConf()
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
bfl.clear();
ConfigTagList tags = ServerInstance->Config->ConfTags("banfile");
@@ -479,12 +462,7 @@ class ModuleDCCAllow : public Module
}
}
- virtual ~ModuleDCCAllow()
- {
- delete ext;
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for the /DCCALLOW command", VF_COMMON | VF_VENDOR);
}
diff --git a/src/modules/m_deaf.cpp b/src/modules/m_deaf.cpp
index 43b24cfae..fd9b322c0 100644
--- a/src/modules/m_deaf.cpp
+++ b/src/modules/m_deaf.cpp
@@ -21,8 +21,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides usermode +d to block channel messages and channel notices */
-
/** User mode +d - filter out channel messages and channel notices
*/
class User_d : public ModeHandler
@@ -32,31 +30,20 @@ class User_d : public ModeHandler
ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
{
+ if (adding == dest->IsModeSet(this))
+ return MODEACTION_DENY;
+
if (adding)
- {
- if (!dest->IsModeSet('d'))
- {
- dest->WriteServ("NOTICE %s :*** You have enabled usermode +d, deaf mode. This mode means you WILL NOT receive any messages from any channels you are in. If you did NOT mean to do this, use /mode %s -d.", dest->nick.c_str(), dest->nick.c_str());
- dest->SetMode('d',true);
- return MODEACTION_ALLOW;
- }
- }
- else
- {
- if (dest->IsModeSet('d'))
- {
- dest->SetMode('d',false);
- return MODEACTION_ALLOW;
- }
- }
- return MODEACTION_DENY;
+ dest->WriteNotice("*** You have enabled usermode +d, deaf mode. This mode means you WILL NOT receive any messages from any channels you are in. If you did NOT mean to do this, use /mode " + dest->nick + " -d.");
+
+ dest->SetMode(this, adding);
+ return MODEACTION_ALLOW;
}
};
class ModuleDeaf : public Module
{
User_d m1;
-
std::string deaf_bypasschars;
std::string deaf_bypasschars_uline;
@@ -66,84 +53,40 @@ class ModuleDeaf : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(m1);
-
- OnRehash(NULL);
- Implementation eventlist[] = { I_OnUserPreMessage, I_OnUserPreNotice, I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- virtual void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ConfigTag* tag = ServerInstance->Config->ConfValue("deaf");
deaf_bypasschars = tag->getString("bypasschars");
deaf_bypasschars_uline = tag->getString("bypasscharsuline");
}
- virtual ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
- {
- if (target_type == TYPE_CHANNEL)
- {
- Channel* chan = (Channel*)dest;
- if (chan)
- this->BuildDeafList(MSG_NOTICE, chan, user, status, text, exempt_list);
- }
-
- return MOD_RES_PASSTHRU;
- }
-
- virtual ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+ ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE
{
- if (target_type == TYPE_CHANNEL)
- {
- Channel* chan = (Channel*)dest;
- if (chan)
- this->BuildDeafList(MSG_PRIVMSG, chan, user, status, text, exempt_list);
- }
+ if (target_type != TYPE_CHANNEL)
+ return MOD_RES_PASSTHRU;
- return MOD_RES_PASSTHRU;
- }
-
- virtual void BuildDeafList(MessageType message_type, Channel* chan, User* sender, char status, const std::string &text, CUList &exempt_list)
- {
- const UserMembList *ulist = chan->GetUsers();
- bool is_a_uline;
- bool is_bypasschar, is_bypasschar_avail;
- bool is_bypasschar_uline, is_bypasschar_uline_avail;
-
- is_bypasschar = is_bypasschar_avail = is_bypasschar_uline = is_bypasschar_uline_avail = 0;
- if (!deaf_bypasschars.empty())
- {
- is_bypasschar_avail = 1;
- if (deaf_bypasschars.find(text[0], 0) != std::string::npos)
- is_bypasschar = 1;
- }
- if (!deaf_bypasschars_uline.empty())
- {
- is_bypasschar_uline_avail = 1;
- if (deaf_bypasschars_uline.find(text[0], 0) != std::string::npos)
- is_bypasschar_uline = 1;
- }
+ Channel* chan = static_cast<Channel*>(dest);
+ bool is_bypasschar = (deaf_bypasschars.find(text[0]) != std::string::npos);
+ bool is_bypasschar_uline = (deaf_bypasschars_uline.find(text[0]) != std::string::npos);
/*
* If we have no bypasschars_uline in config, and this is a bypasschar (regular)
* Than it is obviously going to get through +d, no build required
*/
- if (!is_bypasschar_uline_avail && is_bypasschar)
- return;
+ if (!deaf_bypasschars_uline.empty() && is_bypasschar)
+ return MOD_RES_PASSTHRU;
- for (UserMembCIter i = ulist->begin(); i != ulist->end(); i++)
+ const Channel::MemberMap& ulist = chan->GetUsers();
+ for (Channel::MemberMap::const_iterator i = ulist.begin(); i != ulist.end(); ++i)
{
/* not +d ? */
- if (!i->first->IsModeSet('d'))
+ if (!i->first->IsModeSet(m1))
continue; /* deliver message */
/* matched both U-line only and regular bypasses */
if (is_bypasschar && is_bypasschar_uline)
continue; /* deliver message */
- is_a_uline = ServerInstance->ULine(i->first->server);
+ bool is_a_uline = i->first->server->IsULine();
/* matched a U-line only bypass */
if (is_bypasschar_uline && is_a_uline)
continue; /* deliver message */
@@ -151,23 +94,20 @@ class ModuleDeaf : public Module
if (is_bypasschar && !is_a_uline)
continue; /* deliver message */
- if (status && !strchr(chan->GetAllPrefixChars(i->first), status))
+ if (status && !strchr(i->second->GetAllPrefixChars(), status))
continue;
/* don't deliver message! */
exempt_list.insert(i->first);
}
- }
- virtual ~ModuleDeaf()
- {
+ return MOD_RES_PASSTHRU;
}
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides usermode +d to block channel messages and channel notices", VF_VENDOR);
}
-
};
MODULE_INIT(ModuleDeaf)
diff --git a/src/modules/m_delayjoin.cpp b/src/modules/m_delayjoin.cpp
index a9a92e67a..55ffd08d7 100644
--- a/src/modules/m_delayjoin.cpp
+++ b/src/modules/m_delayjoin.cpp
@@ -20,14 +20,10 @@
*/
-/* $ModDesc: Allows for delay-join channels (+D) where users don't appear to join until they speak */
-
#include "inspircd.h"
-#include <stdarg.h>
class DelayJoinMode : public ModeHandler
{
- private:
CUList empty;
public:
DelayJoinMode(Module* Parent) : ModeHandler(Parent, "delayjoin", 'D', PARAM_NONE, MODETYPE_CHANNEL)
@@ -47,29 +43,21 @@ class ModuleDelayJoin : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(djm);
- ServerInstance->Modules->AddService(unjoined);
- Implementation eventlist[] = { I_OnUserJoin, I_OnUserPart, I_OnUserKick, I_OnBuildNeighborList, I_OnNamesListItem, I_OnText, I_OnRawMode };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
- ~ModuleDelayJoin();
- Version GetVersion();
- void OnNamesListItem(User* issuer, Membership*, std::string &prefixes, std::string &nick);
- void OnUserJoin(Membership*, bool, bool, CUList&);
+ Version GetVersion() CXX11_OVERRIDE;
+ ModResult OnNamesListItem(User* issuer, Membership*, std::string& prefixes, std::string& nick) CXX11_OVERRIDE;
+ void OnUserJoin(Membership*, bool, bool, CUList&) CXX11_OVERRIDE;
void CleanUser(User* user);
- void OnUserPart(Membership*, std::string &partmessage, CUList&);
- void OnUserKick(User* source, Membership*, const std::string &reason, CUList&);
- void OnBuildNeighborList(User* source, UserChanList &include, std::map<User*,bool> &exception);
- void OnText(User* user, void* dest, int target_type, const std::string &text, char status, CUList &exempt_list);
- ModResult OnRawMode(User* user, Channel* channel, const char mode, const std::string &param, bool adding, int pcnt);
+ void OnUserPart(Membership*, std::string &partmessage, CUList&) CXX11_OVERRIDE;
+ void OnUserKick(User* source, Membership*, const std::string &reason, CUList&) CXX11_OVERRIDE;
+ void OnBuildNeighborList(User* source, IncludeChanList& include, std::map<User*, bool>& exception) CXX11_OVERRIDE;
+ void OnText(User* user, void* dest, int target_type, const std::string &text, char status, CUList &exempt_list) CXX11_OVERRIDE;
+ ModResult OnRawMode(User* user, Channel* channel, ModeHandler* mh, const std::string& param, bool adding) CXX11_OVERRIDE;
};
ModeAction DelayJoinMode::OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
{
/* no change */
- if (channel->IsModeSet('D') == adding)
+ if (channel->IsModeSet(this) == adding)
return MODEACTION_DENY;
if (!adding)
@@ -78,38 +66,36 @@ ModeAction DelayJoinMode::OnModeChange(User* source, User* dest, Channel* channe
* Make all users visible, as +D is being removed. If we don't do this,
* they remain permanently invisible on this channel!
*/
- const UserMembList* names = channel->GetUsers();
- for (UserMembCIter n = names->begin(); n != names->end(); ++n)
+ const Channel::MemberMap& users = channel->GetUsers();
+ for (Channel::MemberMap::const_iterator n = users.begin(); n != users.end(); ++n)
creator->OnText(n->first, channel, TYPE_CHANNEL, "", 0, empty);
}
- channel->SetMode('D', adding);
+ channel->SetMode(this, adding);
return MODEACTION_ALLOW;
}
-ModuleDelayJoin::~ModuleDelayJoin()
-{
-}
-
Version ModuleDelayJoin::GetVersion()
{
return Version("Allows for delay-join channels (+D) where users don't appear to join until they speak", VF_VENDOR);
}
-void ModuleDelayJoin::OnNamesListItem(User* issuer, Membership* memb, std::string &prefixes, std::string &nick)
+ModResult ModuleDelayJoin::OnNamesListItem(User* issuer, Membership* memb, std::string& prefixes, std::string& nick)
{
/* don't prevent the user from seeing themself */
if (issuer == memb->user)
- return;
+ return MOD_RES_PASSTHRU;
/* If the user is hidden by delayed join, hide them from the NAMES list */
if (unjoined.get(memb))
- nick.clear();
+ return MOD_RES_DENY;
+
+ return MOD_RES_PASSTHRU;
}
static void populate(CUList& except, Membership* memb)
{
- const UserMembList* users = memb->chan->GetUsers();
- for(UserMembCIter i = users->begin(); i != users->end(); i++)
+ const Channel::MemberMap& users = memb->chan->GetUsers();
+ for (Channel::MemberMap::const_iterator i = users.begin(); i != users.end(); ++i)
{
if (i->first == memb->user || !IS_LOCAL(i->first))
continue;
@@ -119,7 +105,7 @@ static void populate(CUList& except, Membership* memb)
void ModuleDelayJoin::OnUserJoin(Membership* memb, bool sync, bool created, CUList& except)
{
- if (memb->chan->IsModeSet('D'))
+ if (memb->chan->IsModeSet(djm))
{
unjoined.set(memb, 1);
populate(except, memb);
@@ -138,15 +124,15 @@ void ModuleDelayJoin::OnUserKick(User* source, Membership* memb, const std::stri
populate(except, memb);
}
-void ModuleDelayJoin::OnBuildNeighborList(User* source, UserChanList &include, std::map<User*,bool> &exception)
+void ModuleDelayJoin::OnBuildNeighborList(User* source, IncludeChanList& include, std::map<User*, bool>& exception)
{
- UCListIter i = include.begin();
- while (i != include.end())
+ for (IncludeChanList::iterator i = include.begin(); i != include.end(); )
{
- Channel* c = *i++;
- Membership* memb = c->GetUser(source);
- if (memb && unjoined.get(memb))
- include.erase(c);
+ Membership* memb = *i;
+ if (unjoined.get(memb))
+ i = include.erase(i);
+ else
+ ++i;
}
}
@@ -177,7 +163,7 @@ void ModuleDelayJoin::OnText(User* user, void* dest, int target_type, const std:
}
/* make the user visible if he receives any mode change */
-ModResult ModuleDelayJoin::OnRawMode(User* user, Channel* channel, const char mode, const std::string &param, bool adding, int pcnt)
+ModResult ModuleDelayJoin::OnRawMode(User* user, Channel* channel, ModeHandler* mh, const std::string& param, bool adding)
{
if (!user || !channel || param.empty())
return MOD_RES_PASSTHRU;
diff --git a/src/modules/m_delaymsg.cpp b/src/modules/m_delaymsg.cpp
index cfc06866a..06a05db02 100644
--- a/src/modules/m_delaymsg.cpp
+++ b/src/modules/m_delaymsg.cpp
@@ -19,13 +19,12 @@
#include "inspircd.h"
-/* $ModDesc: Provides channelmode +d <int>, to deny messages to a channel until <int> seconds. */
-
-class DelayMsgMode : public ModeHandler
+class DelayMsgMode : public ParamMode<DelayMsgMode, LocalIntExt>
{
public:
LocalIntExt jointime;
- DelayMsgMode(Module* Parent) : ModeHandler(Parent, "delaymsg", 'd', PARAM_SETONLY, MODETYPE_CHANNEL)
+ DelayMsgMode(Module* Parent)
+ : ParamMode<DelayMsgMode, LocalIntExt>(Parent, "delaymsg", 'd')
, jointime("delaymsg", Parent)
{
levelrequired = OP_VALUE;
@@ -36,62 +35,49 @@ class DelayMsgMode : public ModeHandler
return (atoi(their_param.c_str()) < atoi(our_param.c_str()));
}
- ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding);
+ ModeAction OnSet(User* source, Channel* chan, std::string& parameter);
+ void OnUnset(User* source, Channel* chan);
+
+ void SerializeParam(Channel* chan, int n, std::string& out)
+ {
+ out += ConvToStr(n);
+ }
};
class ModuleDelayMsg : public Module
{
- private:
DelayMsgMode djm;
public:
ModuleDelayMsg() : djm(this)
{
}
- void init()
- {
- ServerInstance->Modules->AddService(djm);
- ServerInstance->Modules->AddService(djm.jointime);
- Implementation eventlist[] = { I_OnUserJoin, I_OnUserPreMessage};
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
- Version GetVersion();
- void OnUserJoin(Membership* memb, bool sync, bool created, CUList&);
- ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string &text, char status, CUList &exempt_list);
+ Version GetVersion() CXX11_OVERRIDE;
+ void OnUserJoin(Membership* memb, bool sync, bool created, CUList&) CXX11_OVERRIDE;
+ ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE;
};
-ModeAction DelayMsgMode::OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
+ModeAction DelayMsgMode::OnSet(User* source, Channel* chan, std::string& parameter)
{
- if (adding)
- {
- if ((channel->IsModeSet('d')) && (channel->GetModeParameter('d') == parameter))
- return MODEACTION_DENY;
-
- /* Setting a new limit, sanity check */
- long limit = atoi(parameter.c_str());
-
- /* Wrap low values at 32768 */
- if (limit < 0)
- limit = 0x7FFF;
+ // Setting a new limit, sanity check
+ unsigned int limit = ConvToInt(parameter);
+ if (limit == 0)
+ limit = 1;
- parameter = ConvToStr(limit);
- }
- else
- {
- if (!channel->IsModeSet('d'))
- return MODEACTION_DENY;
-
- /*
- * Clean up metadata
- */
- const UserMembList* names = channel->GetUsers();
- for (UserMembCIter n = names->begin(); n != names->end(); ++n)
- jointime.set(n->second, 0);
- }
- channel->SetModeParam('d', adding ? parameter : "");
+ ext.set(chan, limit);
return MODEACTION_ALLOW;
}
+void DelayMsgMode::OnUnset(User* source, Channel* chan)
+{
+ /*
+ * Clean up metadata
+ */
+ const Channel::MemberMap& users = chan->GetUsers();
+ for (Channel::MemberMap::const_iterator n = users.begin(); n != users.end(); ++n)
+ jointime.set(n->second, 0);
+}
+
Version ModuleDelayMsg::GetVersion()
{
return Version("Provides channelmode +d <int>, to deny messages to a channel until <int> seconds.", VF_VENDOR);
@@ -99,19 +85,19 @@ Version ModuleDelayMsg::GetVersion()
void ModuleDelayMsg::OnUserJoin(Membership* memb, bool sync, bool created, CUList&)
{
- if ((IS_LOCAL(memb->user)) && (memb->chan->IsModeSet('d')))
+ if ((IS_LOCAL(memb->user)) && (memb->chan->IsModeSet(djm)))
{
djm.jointime.set(memb, ServerInstance->Time());
}
}
-ModResult ModuleDelayMsg::OnUserPreMessage(User* user, void* dest, int target_type, std::string &text, char status, CUList &exempt_list)
+ModResult ModuleDelayMsg::OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype)
{
/* Server origin */
if ((!user) || (!IS_LOCAL(user)))
return MOD_RES_PASSTHRU;
- if (target_type != TYPE_CHANNEL)
+ if ((target_type != TYPE_CHANNEL) || (msgtype != MSG_PRIVMSG))
return MOD_RES_PASSTHRU;
Channel* channel = (Channel*) dest;
@@ -125,14 +111,14 @@ ModResult ModuleDelayMsg::OnUserPreMessage(User* user, void* dest, int target_ty
if (ts == 0)
return MOD_RES_PASSTHRU;
- std::string len = channel->GetModeParameter('d');
+ int len = djm.ext.get(channel);
- if (ts + atoi(len.c_str()) > ServerInstance->Time())
+ if ((ts + len) > ServerInstance->Time())
{
if (channel->GetPrefixValue(user) < VOICE_VALUE)
{
- user->WriteNumeric(404, "%s %s :You must wait %s seconds after joining to send to channel (+d)",
- user->nick.c_str(), channel->name.c_str(), len.c_str());
+ user->WriteNumeric(ERR_CANNOTSENDTOCHAN, "%s :You must wait %d seconds after joining to send to channel (+d)",
+ channel->name.c_str(), len);
return MOD_RES_DENY;
}
}
@@ -145,4 +131,3 @@ ModResult ModuleDelayMsg::OnUserPreMessage(User* user, void* dest, int target_ty
}
MODULE_INIT(ModuleDelayMsg)
-
diff --git a/src/modules/m_denychans.cpp b/src/modules/m_denychans.cpp
index 39d9e0d34..6378ba273 100644
--- a/src/modules/m_denychans.cpp
+++ b/src/modules/m_denychans.cpp
@@ -22,18 +22,17 @@
#include "inspircd.h"
-/* $ModDesc: Implements config tags which allow blocking of joins to channels */
-
class ModuleDenyChannels : public Module
{
+ ChanModeReference redirectmode;
+
public:
- void init()
+ ModuleDenyChannels()
+ : redirectmode(this, "redirect")
{
- Implementation eventlist[] = { I_OnUserPreJoin, I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
}
- virtual void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
/* check for redirect validity and loops/chains */
ConfigTagList tags = ServerInstance->Config->ConfTags("badchan");
@@ -45,10 +44,10 @@ class ModuleDenyChannels : public Module
if (!redirect.empty())
{
- if (!ServerInstance->IsChannel(redirect.c_str(), ServerInstance->Config->Limits.ChanMax))
+ if (!ServerInstance->IsChannel(redirect))
{
- if (user)
- user->WriteServ("NOTICE %s :Invalid badchan redirect '%s'", user->nick.c_str(), redirect.c_str());
+ if (status.srcuser)
+ status.srcuser->WriteNotice("Invalid badchan redirect '" + redirect + "'");
throw ModuleException("Invalid badchan redirect, not a channel");
}
@@ -67,8 +66,8 @@ class ModuleDenyChannels : public Module
if (!goodchan)
{
/* <badchan:redirect> is a badchan */
- if (user)
- user->WriteServ("NOTICE %s :Badchan %s redirects to badchan %s", user->nick.c_str(), name.c_str(), redirect.c_str());
+ if (status.srcuser)
+ status.srcuser->WriteNotice("Badchan " + name + " redirects to badchan " + redirect);
throw ModuleException("Badchan redirect loop");
}
}
@@ -77,24 +76,20 @@ class ModuleDenyChannels : public Module
}
}
- virtual ~ModuleDenyChannels()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Implements config tags which allow blocking of joins to channels", VF_VENDOR);
}
- virtual ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven)
+ ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE
{
ConfigTagList tags = ServerInstance->Config->ConfTags("badchan");
for (ConfigIter j = tags.first; j != tags.second; ++j)
{
if (InspIRCd::Match(cname, j->second->getString("name")))
{
- if (IS_OPER(user) && j->second->getBool("allowopers"))
+ if (user->IsOper() && j->second->getBool("allowopers"))
{
return MOD_RES_PASSTHRU;
}
@@ -112,19 +107,19 @@ class ModuleDenyChannels : public Module
}
}
- if (ServerInstance->IsChannel(redirect.c_str(), ServerInstance->Config->Limits.ChanMax))
+ if (ServerInstance->IsChannel(redirect))
{
/* simple way to avoid potential loops: don't redirect to +L channels */
Channel *newchan = ServerInstance->FindChan(redirect);
- if ((!newchan) || (!(newchan->IsModeSet('L'))))
+ if ((!newchan) || (!newchan->IsModeSet(redirectmode)))
{
- user->WriteNumeric(926, "%s %s :Channel %s is forbidden, redirecting to %s: %s",user->nick.c_str(),cname,cname,redirect.c_str(), reason.c_str());
- Channel::JoinUser(user,redirect.c_str(),false,"",false,ServerInstance->Time());
+ user->WriteNumeric(926, "%s :Channel %s is forbidden, redirecting to %s: %s", cname.c_str(),cname.c_str(),redirect.c_str(), reason.c_str());
+ Channel::JoinUser(user, redirect);
return MOD_RES_DENY;
}
}
- user->WriteNumeric(926, "%s %s :Channel %s is forbidden: %s",user->nick.c_str(),cname,cname,reason.c_str());
+ user->WriteNumeric(926, "%s :Channel %s is forbidden: %s", cname.c_str(),cname.c_str(),reason.c_str());
return MOD_RES_DENY;
}
}
diff --git a/src/modules/m_devoice.cpp b/src/modules/m_devoice.cpp
index 2b5de2bd6..901f77b1a 100644
--- a/src/modules/m_devoice.cpp
+++ b/src/modules/m_devoice.cpp
@@ -24,8 +24,6 @@
* Syntax: /DEVOICE <#chan>
*/
-/* $ModDesc: Provides voiced users with the ability to devoice themselves. */
-
#include "inspircd.h"
/** Handle /DEVOICE
@@ -36,24 +34,17 @@ class CommandDevoice : public Command
CommandDevoice(Module* Creator) : Command(Creator,"DEVOICE", 1)
{
syntax = "<channel>";
- TRANSLATE2(TR_TEXT, TR_END);
}
CmdResult Handle (const std::vector<std::string> &parameters, User *user)
{
- Channel* c = ServerInstance->FindChan(parameters[0]);
- if (c && c->HasUser(user))
- {
- std::vector<std::string> modes;
- modes.push_back(parameters[0]);
- modes.push_back("-v");
- modes.push_back(user->nick);
-
- ServerInstance->SendGlobalMode(modes, ServerInstance->FakeClient);
- return CMD_SUCCESS;
- }
+ std::vector<std::string> modes;
+ modes.push_back(parameters[0]);
+ modes.push_back("-v");
+ modes.push_back(user->nick);
- return CMD_FAILURE;
+ ServerInstance->Modes->Process(modes, ServerInstance->FakeClient);
+ return CMD_SUCCESS;
}
};
@@ -65,16 +56,7 @@ class ModuleDeVoice : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cmd);
- }
-
- virtual ~ModuleDeVoice()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides voiced users with the ability to devoice themselves.", VF_VENDOR);
}
diff --git a/src/modules/m_dnsbl.cpp b/src/modules/m_dnsbl.cpp
index d4101686a..63dda547f 100644
--- a/src/modules/m_dnsbl.cpp
+++ b/src/modules/m_dnsbl.cpp
@@ -23,8 +23,7 @@
#include "inspircd.h"
#include "xline.h"
-
-/* $ModDesc: Provides handling of DNS blacklists */
+#include "modules/dns.h"
/* Class holding data for a single entry */
class DNSBLConfEntry : public refcountbase
@@ -40,13 +39,12 @@ class DNSBLConfEntry : public refcountbase
unsigned char records[256];
unsigned long stats_hits, stats_misses;
DNSBLConfEntry(): type(A_BITMASK),duration(86400),bitmask(0),stats_hits(0), stats_misses(0) {}
- ~DNSBLConfEntry() { }
};
/** Resolver for CGI:IRC hostnames encoded in ident/GECOS
*/
-class DNSBLResolver : public Resolver
+class DNSBLResolver : public DNS::Request
{
std::string theiruid;
LocalStringExt& nameExt;
@@ -55,170 +53,167 @@ class DNSBLResolver : public Resolver
public:
- DNSBLResolver(Module *me, LocalStringExt& match, LocalIntExt& ctr, const std::string &hostname, LocalUser* u, reference<DNSBLConfEntry> conf, bool &cached)
- : Resolver(hostname, DNS_QUERY_A, cached, me), theiruid(u->uuid), nameExt(match), countExt(ctr), ConfEntry(conf)
+ DNSBLResolver(DNS::Manager *mgr, Module *me, LocalStringExt& match, LocalIntExt& ctr, const std::string &hostname, LocalUser* u, reference<DNSBLConfEntry> conf)
+ : DNS::Request(mgr, me, hostname, DNS::QUERY_A, true), theiruid(u->uuid), nameExt(match), countExt(ctr), ConfEntry(conf)
{
}
/* Note: This may be called multiple times for multiple A record results */
- virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached)
+ void OnLookupComplete(const DNS::Query *r) CXX11_OVERRIDE
{
/* Check the user still exists */
LocalUser* them = (LocalUser*)ServerInstance->FindUUID(theiruid);
- if (them)
+ if (!them)
+ return;
+
+ const DNS::ResourceRecord &ans_record = r->answers[0];
+
+ int i = countExt.get(them);
+ if (i)
+ countExt.set(them, i - 1);
+
+ // Now we calculate the bitmask: 256*(256*(256*a+b)+c)+d
+
+ unsigned int bitmask = 0, record = 0;
+ bool match = false;
+ in_addr resultip;
+
+ inet_aton(ans_record.rdata.c_str(), &resultip);
+
+ switch (ConfEntry->type)
{
- int i = countExt.get(them);
- if (i)
- countExt.set(them, i - 1);
- // Now we calculate the bitmask: 256*(256*(256*a+b)+c)+d
- if(result.length())
+ case DNSBLConfEntry::A_BITMASK:
+ bitmask = resultip.s_addr >> 24; /* Last octet (network byte order) */
+ bitmask &= ConfEntry->bitmask;
+ match = (bitmask != 0);
+ break;
+ case DNSBLConfEntry::A_RECORD:
+ record = resultip.s_addr >> 24; /* Last octet */
+ match = (ConfEntry->records[record] == 1);
+ break;
+ }
+
+ if (match)
+ {
+ std::string reason = ConfEntry->reason;
+ std::string::size_type x = reason.find("%ip%");
+ while (x != std::string::npos)
{
- unsigned int bitmask = 0, record = 0;
- bool match = false;
- in_addr resultip;
+ reason.erase(x, 4);
+ reason.insert(x, them->GetIPString());
+ x = reason.find("%ip%");
+ }
- inet_aton(result.c_str(), &resultip);
+ ConfEntry->stats_hits++;
- switch (ConfEntry->type)
+ switch (ConfEntry->banaction)
+ {
+ case DNSBLConfEntry::I_KILL:
{
- case DNSBLConfEntry::A_BITMASK:
- bitmask = resultip.s_addr >> 24; /* Last octet (network byte order) */
- bitmask &= ConfEntry->bitmask;
- match = (bitmask != 0);
- break;
- case DNSBLConfEntry::A_RECORD:
- record = resultip.s_addr >> 24; /* Last octet */
- match = (ConfEntry->records[record] == 1);
+ ServerInstance->Users->QuitUser(them, "Killed (" + reason + ")");
break;
}
-
- if (match)
+ case DNSBLConfEntry::I_MARK:
{
- std::string reason = ConfEntry->reason;
- std::string::size_type x = reason.find("%ip%");
- while (x != std::string::npos)
+ if (!ConfEntry->ident.empty())
{
- reason.erase(x, 4);
- reason.insert(x, them->GetIPString());
- x = reason.find("%ip%");
+ them->WriteNumeric(304, ":Your ident has been set to " + ConfEntry->ident + " because you matched " + reason);
+ them->ChangeIdent(ConfEntry->ident);
}
- ConfEntry->stats_hits++;
-
- switch (ConfEntry->banaction)
+ if (!ConfEntry->host.empty())
{
- case DNSBLConfEntry::I_KILL:
- {
- ServerInstance->Users->QuitUser(them, "Killed (" + reason + ")");
- break;
- }
- case DNSBLConfEntry::I_MARK:
- {
- if (!ConfEntry->ident.empty())
- {
- them->WriteServ("304 " + them->nick + " :Your ident has been set to " + ConfEntry->ident + " because you matched " + reason);
- them->ChangeIdent(ConfEntry->ident.c_str());
- }
-
- if (!ConfEntry->host.empty())
- {
- them->WriteServ("304 " + them->nick + " :Your host has been set to " + ConfEntry->host + " because you matched " + reason);
- them->ChangeDisplayedHost(ConfEntry->host.c_str());
- }
-
- nameExt.set(them, ConfEntry->name);
- break;
- }
- case DNSBLConfEntry::I_KLINE:
- {
- KLine* kl = new KLine(ServerInstance->Time(), ConfEntry->duration, ServerInstance->Config->ServerName.c_str(), reason.c_str(),
- "*", them->GetIPString());
- if (ServerInstance->XLines->AddLine(kl,NULL))
- {
- std::string timestr = ServerInstance->TimeString(kl->expiry);
- ServerInstance->SNO->WriteGlobalSno('x',"K:line added due to DNSBL match on *@%s to expire on %s: %s",
- them->GetIPString(), timestr.c_str(), reason.c_str());
- ServerInstance->XLines->ApplyLines();
- }
- else
- {
- delete kl;
- return;
- }
- break;
- }
- case DNSBLConfEntry::I_GLINE:
- {
- GLine* gl = new GLine(ServerInstance->Time(), ConfEntry->duration, ServerInstance->Config->ServerName.c_str(), reason.c_str(),
- "*", them->GetIPString());
- if (ServerInstance->XLines->AddLine(gl,NULL))
- {
- std::string timestr = ServerInstance->TimeString(gl->expiry);
- ServerInstance->SNO->WriteGlobalSno('x',"G:line added due to DNSBL match on *@%s to expire on %s: %s",
- them->GetIPString(), timestr.c_str(), reason.c_str());
- ServerInstance->XLines->ApplyLines();
- }
- else
- {
- delete gl;
- return;
- }
- break;
- }
- case DNSBLConfEntry::I_ZLINE:
- {
- ZLine* zl = new ZLine(ServerInstance->Time(), ConfEntry->duration, ServerInstance->Config->ServerName.c_str(), reason.c_str(),
- them->GetIPString());
- if (ServerInstance->XLines->AddLine(zl,NULL))
- {
- std::string timestr = ServerInstance->TimeString(zl->expiry);
- ServerInstance->SNO->WriteGlobalSno('x',"Z:line added due to DNSBL match on *@%s to expire on %s: %s",
- them->GetIPString(), timestr.c_str(), reason.c_str());
- ServerInstance->XLines->ApplyLines();
- }
- else
- {
- delete zl;
- return;
- }
- break;
- }
- case DNSBLConfEntry::I_UNKNOWN:
- {
- break;
- }
- break;
+ them->WriteNumeric(304, ":Your host has been set to " + ConfEntry->host + " because you matched " + reason);
+ them->ChangeDisplayedHost(ConfEntry->host);
}
- ServerInstance->SNO->WriteGlobalSno('a', "Connecting user %s%s detected as being on a DNS blacklist (%s) with result %d", them->nick.empty() ? "<unknown>" : "", them->GetFullRealHost().c_str(), ConfEntry->domain.c_str(), (ConfEntry->type==DNSBLConfEntry::A_BITMASK) ? bitmask : record);
+ nameExt.set(them, ConfEntry->name);
+ break;
+ }
+ case DNSBLConfEntry::I_KLINE:
+ {
+ KLine* kl = new KLine(ServerInstance->Time(), ConfEntry->duration, ServerInstance->Config->ServerName.c_str(), reason.c_str(),
+ "*", them->GetIPString());
+ if (ServerInstance->XLines->AddLine(kl,NULL))
+ {
+ std::string timestr = InspIRCd::TimeString(kl->expiry);
+ ServerInstance->SNO->WriteGlobalSno('x',"K:line added due to DNSBL match on *@%s to expire on %s: %s",
+ them->GetIPString().c_str(), timestr.c_str(), reason.c_str());
+ ServerInstance->XLines->ApplyLines();
+ }
+ else
+ {
+ delete kl;
+ return;
+ }
+ break;
+ }
+ case DNSBLConfEntry::I_GLINE:
+ {
+ GLine* gl = new GLine(ServerInstance->Time(), ConfEntry->duration, ServerInstance->Config->ServerName.c_str(), reason.c_str(),
+ "*", them->GetIPString());
+ if (ServerInstance->XLines->AddLine(gl,NULL))
+ {
+ std::string timestr = InspIRCd::TimeString(gl->expiry);
+ ServerInstance->SNO->WriteGlobalSno('x',"G:line added due to DNSBL match on *@%s to expire on %s: %s",
+ them->GetIPString().c_str(), timestr.c_str(), reason.c_str());
+ ServerInstance->XLines->ApplyLines();
+ }
+ else
+ {
+ delete gl;
+ return;
+ }
+ break;
+ }
+ case DNSBLConfEntry::I_ZLINE:
+ {
+ ZLine* zl = new ZLine(ServerInstance->Time(), ConfEntry->duration, ServerInstance->Config->ServerName.c_str(), reason.c_str(),
+ them->GetIPString());
+ if (ServerInstance->XLines->AddLine(zl,NULL))
+ {
+ std::string timestr = InspIRCd::TimeString(zl->expiry);
+ ServerInstance->SNO->WriteGlobalSno('x',"Z:line added due to DNSBL match on *@%s to expire on %s: %s",
+ them->GetIPString().c_str(), timestr.c_str(), reason.c_str());
+ ServerInstance->XLines->ApplyLines();
+ }
+ else
+ {
+ delete zl;
+ return;
+ }
+ break;
}
- else
- ConfEntry->stats_misses++;
+ case DNSBLConfEntry::I_UNKNOWN:
+ default:
+ break;
}
- else
- ConfEntry->stats_misses++;
+
+ ServerInstance->SNO->WriteGlobalSno('a', "Connecting user %s%s detected as being on a DNS blacklist (%s) with result %d", them->nick.empty() ? "<unknown>" : "", them->GetFullRealHost().c_str(), ConfEntry->domain.c_str(), (ConfEntry->type==DNSBLConfEntry::A_BITMASK) ? bitmask : record);
}
+ else
+ ConfEntry->stats_misses++;
}
- virtual void OnError(ResolverError e, const std::string &errormessage)
+ void OnError(const DNS::Query *q) CXX11_OVERRIDE
{
LocalUser* them = (LocalUser*)ServerInstance->FindUUID(theiruid);
- if (them)
- {
- int i = countExt.get(them);
- if (i)
- countExt.set(them, i - 1);
- }
- }
+ if (!them)
+ return;
- virtual ~DNSBLResolver()
- {
+ int i = countExt.get(them);
+ if (i)
+ countExt.set(them, i - 1);
+
+ if (q->error == DNS::ERROR_NO_RECORDS || q->error == DNS::ERROR_DOMAIN_NOT_FOUND)
+ ConfEntry->stats_misses++;
}
};
class ModuleDNSBL : public Module
{
std::vector<reference<DNSBLConfEntry> > DNSBLConfEntries;
+ dynamic_reference<DNS::Manager> DNS;
LocalStringExt nameExt;
LocalIntExt countExt;
@@ -241,25 +236,16 @@ class ModuleDNSBL : public Module
return DNSBLConfEntry::I_UNKNOWN;
}
public:
- ModuleDNSBL() : nameExt("dnsbl_match", this), countExt("dnsbl_pending", this) { }
+ ModuleDNSBL() : DNS(this, "DNS"), nameExt("dnsbl_match", this), countExt("dnsbl_pending", this) { }
- void init()
- {
- ReadConf();
- ServerInstance->Modules->AddService(nameExt);
- ServerInstance->Modules->AddService(countExt);
- Implementation eventlist[] = { I_OnRehash, I_OnSetUserIP, I_OnStats, I_OnSetConnectClass, I_OnCheckReady };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides handling of DNS blacklists", VF_VENDOR);
}
/** Fill our conf vector with data
*/
- void ReadConf()
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
DNSBLConfEntries.clear();
@@ -291,7 +277,7 @@ class ModuleDNSBL : public Module
}
e->banaction = str2banaction(tag->getString("action"));
- e->duration = ServerInstance->Duration(tag->getString("duration", "60"));
+ e->duration = tag->getDuration("duration", 60, 1);
/* Use portparser for record replies */
@@ -316,11 +302,6 @@ class ModuleDNSBL : public Module
std::string location = tag->getTagLocation();
ServerInstance->SNO->WriteGlobalSno('a', "DNSBL(%s): Invalid banaction", location.c_str());
}
- else if (e->duration <= 0)
- {
- std::string location = tag->getTagLocation();
- ServerInstance->SNO->WriteGlobalSno('a', "DNSBL(%s): Invalid duration", location.c_str());
- }
else
{
if (e->reason.empty())
@@ -336,14 +317,9 @@ class ModuleDNSBL : public Module
}
}
- void OnRehash(User* user)
- {
- ReadConf();
- }
-
- void OnSetUserIP(LocalUser* user)
+ void OnSetUserIP(LocalUser* user) CXX11_OVERRIDE
{
- if ((user->exempt) || (user->client_sa.sa.sa_family != AF_INET))
+ if ((user->exempt) || (user->client_sa.sa.sa_family != AF_INET) || !DNS)
return;
if (user->MyClass)
@@ -352,40 +328,42 @@ class ModuleDNSBL : public Module
return;
}
else
- ServerInstance->Logs->Log("m_dnsbl", DEBUG, "User has no connect class in OnSetUserIP");
-
- unsigned char a, b, c, d;
- char reversedipbuf[128];
- std::string reversedip;
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "User has no connect class in OnSetUserIP");
- d = (unsigned char) (user->client_sa.in4.sin_addr.s_addr >> 24) & 0xFF;
- c = (unsigned char) (user->client_sa.in4.sin_addr.s_addr >> 16) & 0xFF;
- b = (unsigned char) (user->client_sa.in4.sin_addr.s_addr >> 8) & 0xFF;
- a = (unsigned char) user->client_sa.in4.sin_addr.s_addr & 0xFF;
+ unsigned int a, b, c, d;
+ d = (unsigned int) (user->client_sa.in4.sin_addr.s_addr >> 24) & 0xFF;
+ c = (unsigned int) (user->client_sa.in4.sin_addr.s_addr >> 16) & 0xFF;
+ b = (unsigned int) (user->client_sa.in4.sin_addr.s_addr >> 8) & 0xFF;
+ a = (unsigned int) user->client_sa.in4.sin_addr.s_addr & 0xFF;
- snprintf(reversedipbuf, 128, "%d.%d.%d.%d", d, c, b, a);
- reversedip = std::string(reversedipbuf);
+ const std::string reversedip = ConvToStr(d) + "." + ConvToStr(c) + "." + ConvToStr(b) + "." + ConvToStr(a);
countExt.set(user, DNSBLConfEntries.size());
// For each DNSBL, we will run through this lookup
- unsigned int i = 0;
- while (i < DNSBLConfEntries.size())
+ for (unsigned i = 0; i < DNSBLConfEntries.size(); ++i)
{
// Fill hostname with a dnsbl style host (d.c.b.a.domain.tld)
std::string hostname = reversedip + "." + DNSBLConfEntries[i]->domain;
/* now we'd need to fire off lookups for `hostname'. */
- bool cached;
- DNSBLResolver *r = new DNSBLResolver(this, nameExt, countExt, hostname, user, DNSBLConfEntries[i], cached);
- ServerInstance->AddResolver(r, cached);
+ DNSBLResolver *r = new DNSBLResolver(*this->DNS, this, nameExt, countExt, hostname, user, DNSBLConfEntries[i]);
+ try
+ {
+ this->DNS->Process(r);
+ }
+ catch (DNS::Exception &ex)
+ {
+ delete r;
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, ex.GetReason());
+ }
+
if (user->quitting)
break;
- i++;
}
}
- ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass)
+ ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass) CXX11_OVERRIDE
{
std::string dnsbl;
if (!myclass->config->readString("dnsbl", dnsbl))
@@ -396,15 +374,15 @@ class ModuleDNSBL : public Module
return MOD_RES_PASSTHRU;
return MOD_RES_DENY;
}
-
- ModResult OnCheckReady(LocalUser *user)
+
+ ModResult OnCheckReady(LocalUser *user) CXX11_OVERRIDE
{
if (countExt.get(user))
return MOD_RES_DENY;
return MOD_RES_PASSTHRU;
}
- ModResult OnStats(char symbol, User* user, string_list &results)
+ ModResult OnStats(char symbol, User* user, string_list &results) CXX11_OVERRIDE
{
if (symbol != 'd')
return MOD_RES_PASSTHRU;
@@ -416,12 +394,12 @@ class ModuleDNSBL : public Module
total_hits += (*i)->stats_hits;
total_misses += (*i)->stats_misses;
- results.push_back(ServerInstance->Config->ServerName + " 304 " + user->nick + " :DNSBLSTATS DNSbl \"" + (*i)->name + "\" had " +
+ results.push_back("304 " + user->nick + " :DNSBLSTATS DNSbl \"" + (*i)->name + "\" had " +
ConvToStr((*i)->stats_hits) + " hits and " + ConvToStr((*i)->stats_misses) + " misses");
}
- results.push_back(ServerInstance->Config->ServerName + " 304 " + user->nick + " :DNSBLSTATS Total hits: " + ConvToStr(total_hits));
- results.push_back(ServerInstance->Config->ServerName + " 304 " + user->nick + " :DNSBLSTATS Total misses: " + ConvToStr(total_misses));
+ results.push_back("304 " + user->nick + " :DNSBLSTATS Total hits: " + ConvToStr(total_hits));
+ results.push_back("304 " + user->nick + " :DNSBLSTATS Total misses: " + ConvToStr(total_misses));
return MOD_RES_PASSTHRU;
}
diff --git a/src/modules/m_exemptchanops.cpp b/src/modules/m_exemptchanops.cpp
index 8d6d65af2..43ae21a1c 100644
--- a/src/modules/m_exemptchanops.cpp
+++ b/src/modules/m_exemptchanops.cpp
@@ -18,9 +18,7 @@
#include "inspircd.h"
-#include "u_listmode.h"
-
-/* $ModDesc: Provides the ability to allow channel operators to be exempt from certain modes. */
+#include "listmode.h"
/** Handles channel mode +X
*/
@@ -31,30 +29,28 @@ class ExemptChanOps : public ListModeBase
bool ValidateParam(User* user, Channel* chan, std::string &word)
{
- // TODO actually make sure there's a prop for this
- if ((word.length() > 35) || (word.empty()))
+ if (!ServerInstance->Modes->FindMode(word, MODETYPE_CHANNEL))
{
- user->WriteNumeric(955, "%s %s %s :word is too %s for exemptchanops list",user->nick.c_str(), chan->name.c_str(), word.c_str(), (word.empty() ? "short" : "long"));
+ user->WriteNumeric(955, "%s %s :Mode doesn't exist", chan->name.c_str(), word.c_str());
return false;
}
return true;
}
- bool TellListTooLong(User* user, Channel* chan, std::string &word)
+ void TellListTooLong(User* user, Channel* chan, std::string &word)
{
- user->WriteNumeric(959, "%s %s %s :Channel exemptchanops list is full", user->nick.c_str(), chan->name.c_str(), word.c_str());
- return true;
+ user->WriteNumeric(959, "%s %s :Channel exemptchanops list is full", chan->name.c_str(), word.c_str());
}
void TellAlreadyOnList(User* user, Channel* chan, std::string &word)
{
- user->WriteNumeric(957, "%s %s :The word %s is already on the exemptchanops list",user->nick.c_str(), chan->name.c_str(), word.c_str());
+ user->WriteNumeric(957, "%s :The word %s is already on the exemptchanops list", chan->name.c_str(), word.c_str());
}
void TellNotSet(User* user, Channel* chan, std::string &word)
{
- user->WriteNumeric(958, "%s %s :No such exemptchanops word is set",user->nick.c_str(), chan->name.c_str());
+ user->WriteNumeric(958, "%s :No such exemptchanops word is set", chan->name.c_str());
}
};
@@ -63,18 +59,14 @@ class ExemptHandler : public HandlerBase3<ModResult, User*, Channel*, const std:
public:
ExemptChanOps ec;
ExemptHandler(Module* me) : ec(me) {}
-
- ModeHandler* FindMode(const std::string& mid)
+
+ PrefixMode* FindMode(const std::string& mid)
{
if (mid.length() == 1)
- return ServerInstance->Modes->FindMode(mid[0], MODETYPE_CHANNEL);
- for(char c='A'; c <= 'z'; c++)
- {
- ModeHandler* mh = ServerInstance->Modes->FindMode(c, MODETYPE_CHANNEL);
- if (mh && mh->name == mid)
- return mh;
- }
- return NULL;
+ return ServerInstance->Modes->FindPrefixMode(mid[0]);
+
+ ModeHandler* mh = ServerInstance->Modes->FindMode(mid, MODETYPE_CHANNEL);
+ return mh ? mh->IsPrefixMode() : NULL;
}
ModResult Call(User* user, Channel* chan, const std::string& restriction)
@@ -82,21 +74,21 @@ class ExemptHandler : public HandlerBase3<ModResult, User*, Channel*, const std:
unsigned int mypfx = chan->GetPrefixValue(user);
std::string minmode;
- modelist* list = ec.extItem.get(chan);
+ ListModeBase::ModeList* list = ec.GetList(chan);
if (list)
{
- for (modelist::iterator i = list->begin(); i != list->end(); ++i)
+ for (ListModeBase::ModeList::iterator i = list->begin(); i != list->end(); ++i)
{
std::string::size_type pos = (*i).mask.find(':');
if (pos == std::string::npos)
continue;
- if ((*i).mask.substr(0,pos) == restriction)
+ if (!i->mask.compare(0, pos, restriction))
minmode = (*i).mask.substr(pos + 1);
}
}
- ModeHandler* mh = FindMode(minmode);
+ PrefixMode* mh = FindMode(minmode);
if (mh && mypfx >= mh->GetPrefixRank())
return MOD_RES_ALLOW;
if (mh || minmode == "*")
@@ -108,23 +100,16 @@ class ExemptHandler : public HandlerBase3<ModResult, User*, Channel*, const std:
class ModuleExemptChanOps : public Module
{
- std::string defaults;
ExemptHandler eh;
public:
-
ModuleExemptChanOps() : eh(this)
{
}
- void init()
+ void init() CXX11_OVERRIDE
{
- ServerInstance->Modules->AddService(eh.ec);
- Implementation eventlist[] = { I_OnRehash, I_OnSyncChannel };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
ServerInstance->OnCheckExemption = &eh;
-
- OnRehash(NULL);
}
~ModuleExemptChanOps()
@@ -132,20 +117,15 @@ class ModuleExemptChanOps : public Module
ServerInstance->OnCheckExemption = &ServerInstance->HandleOnCheckExemption;
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides the ability to allow channel operators to be exempt from certain modes.",VF_VENDOR);
}
- void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
eh.ec.DoRehash();
}
-
- void OnSyncChannel(Channel* chan, Module* proto, void* opaque)
- {
- eh.ec.DoSyncChannel(chan, proto, opaque);
- }
};
MODULE_INIT(ModuleExemptChanOps)
diff --git a/src/modules/m_filter.cpp b/src/modules/m_filter.cpp
index 4090f5600..9acce033a 100644
--- a/src/modules/m_filter.cpp
+++ b/src/modules/m_filter.cpp
@@ -22,11 +22,7 @@
#include "inspircd.h"
#include "xline.h"
-#include "m_regex.h"
-
-/* $ModDesc: Text (spam) filtering */
-
-class ModuleFilter;
+#include "modules/regex.h"
enum FilterFlags
{
@@ -48,6 +44,7 @@ enum FilterAction
class FilterResult
{
public:
+ Regex* regex;
std::string freeform;
std::string reason;
FilterAction action;
@@ -60,9 +57,12 @@ class FilterResult
bool flag_notice;
bool flag_strip_color;
- FilterResult(const std::string& free, const std::string& rea, FilterAction act, long gt, const std::string& fla) :
- freeform(free), reason(rea), action(act), gline_time(gt)
+ FilterResult(dynamic_reference<RegexFactory>& RegexEngine, const std::string& free, const std::string& rea, FilterAction act, long gt, const std::string& fla)
+ : freeform(free), reason(rea), action(act), gline_time(gt)
{
+ if (!RegexEngine)
+ throw ModuleException("Regex module implementing '"+RegexEngine.GetProvider()+"' is not loaded!");
+ regex = RegexEngine->Create(free);
this->FillFlags(fla);
}
@@ -154,17 +154,10 @@ class CommandFilter : public Command
}
};
-class ImplFilter : public FilterResult
-{
- public:
- Regex* regex;
-
- ImplFilter(ModuleFilter* mymodule, const std::string &rea, FilterAction act, long glinetime, const std::string &pat, const std::string &flgs);
-};
-
-
class ModuleFilter : public Module
{
+ typedef std::set<std::string, irc::insensitive_swo> ExemptTargetSet;
+
bool initing;
RegexFactory* factory;
void FreeFilters();
@@ -173,28 +166,30 @@ class ModuleFilter : public Module
CommandFilter filtcommand;
dynamic_reference<RegexFactory> RegexEngine;
- std::vector<ImplFilter> filters;
+ std::vector<FilterResult> filters;
int flags;
- std::set<std::string> exemptfromfilter; // List of channel names excluded from filtering.
+ // List of channel names excluded from filtering.
+ ExemptTargetSet exemptedchans;
+
+ // List of target nicknames excluded from filtering.
+ ExemptTargetSet exemptednicks;
ModuleFilter();
- void init();
CullResult cull();
- ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list);
+ ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE;
FilterResult* FilterMatch(User* user, const std::string &text, int flags);
bool DeleteFilter(const std::string &freeform);
std::pair<bool, std::string> AddFilter(const std::string &freeform, FilterAction type, const std::string &reason, long duration, const std::string &flags);
- ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list);
- void OnRehash(User* user);
- Version GetVersion();
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE;
+ Version GetVersion() CXX11_OVERRIDE;
std::string EncodeFilter(FilterResult* filter);
FilterResult DecodeFilter(const std::string &data);
- void OnSyncNetwork(Module* proto, void* opaque);
- void OnDecodeMetaData(Extensible* target, const std::string &extname, const std::string &extdata);
- ModResult OnStats(char symbol, User* user, string_list &results);
- ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line);
- void OnUnloadModule(Module* mod);
+ void OnSyncNetwork(ProtocolInterface::Server& server) CXX11_OVERRIDE;
+ void OnDecodeMetaData(Extensible* target, const std::string &extname, const std::string &extdata) CXX11_OVERRIDE;
+ ModResult OnStats(char symbol, User* user, string_list &results) CXX11_OVERRIDE;
+ ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line) CXX11_OVERRIDE;
+ void OnUnloadModule(Module* mod) CXX11_OVERRIDE;
bool AppliesToMe(User* user, FilterResult* filter, int flags);
void ReadFilters();
static bool StringToFilterAction(const std::string& str, FilterAction& fa);
@@ -209,13 +204,13 @@ CmdResult CommandFilter::Handle(const std::vector<std::string> &parameters, User
Module *me = creator;
if (static_cast<ModuleFilter *>(me)->DeleteFilter(parameters[0]))
{
- user->WriteServ("NOTICE %s :*** Removed filter '%s'", user->nick.c_str(), parameters[0].c_str());
+ user->WriteNotice("*** Removed filter '" + parameters[0] + "'");
ServerInstance->SNO->WriteToSnoMask(IS_LOCAL(user) ? 'a' : 'A', "FILTER: "+user->nick+" removed filter '"+parameters[0]+"'");
return CMD_SUCCESS;
}
else
{
- user->WriteServ("NOTICE %s :*** Filter '%s' not found in list, try /stats s.", user->nick.c_str(), parameters[0].c_str());
+ user->WriteNotice("*** Filter '" + parameters[0] + "' not found in list, try /stats s.");
return CMD_FAILURE;
}
}
@@ -232,7 +227,7 @@ CmdResult CommandFilter::Handle(const std::vector<std::string> &parameters, User
if (!ModuleFilter::StringToFilterAction(parameters[1], type))
{
- user->WriteServ("NOTICE %s :*** Invalid filter type '%s'. Supported types are 'gline', 'none', 'block', 'silent' and 'kill'.", user->nick.c_str(), parameters[1].c_str());
+ user->WriteNotice("*** Invalid filter type '" + parameters[1] + "'. Supported types are 'gline', 'none', 'block', 'silent' and 'kill'.");
return CMD_FAILURE;
}
@@ -240,12 +235,12 @@ CmdResult CommandFilter::Handle(const std::vector<std::string> &parameters, User
{
if (parameters.size() >= 5)
{
- duration = ServerInstance->Duration(parameters[3]);
+ duration = InspIRCd::Duration(parameters[3]);
reasonindex = 4;
}
else
{
- user->WriteServ("NOTICE %s :*** Not enough parameters: When setting a gline type filter, a gline duration must be specified as the third parameter.", user->nick.c_str());
+ user->WriteNotice("*** Not enough parameters: When setting a gline type filter, a gline duration must be specified as the third parameter.");
return CMD_FAILURE;
}
}
@@ -258,9 +253,9 @@ CmdResult CommandFilter::Handle(const std::vector<std::string> &parameters, User
std::pair<bool, std::string> result = static_cast<ModuleFilter *>(me)->AddFilter(freeform, type, parameters[reasonindex], duration, flags);
if (result.first)
{
- user->WriteServ("NOTICE %s :*** Added filter '%s', type '%s'%s%s, flags '%s', reason: '%s'", user->nick.c_str(), freeform.c_str(),
- parameters[1].c_str(), (duration ? ", duration " : ""), (duration ? parameters[3].c_str() : ""),
- flags.c_str(), parameters[reasonindex].c_str());
+ user->WriteNotice("*** Added filter '" + freeform + "', type '" + parameters[1] + "'" +
+ (duration ? ", duration " + parameters[3] : "") + ", flags '" + flags + "', reason: '" +
+ parameters[reasonindex] + "'");
ServerInstance->SNO->WriteToSnoMask(IS_LOCAL(user) ? 'a' : 'A', "FILTER: "+user->nick+" added filter '"+freeform+"', type '"+parameters[1]+"', "+(duration ? "duration "+parameters[3]+", " : "")+"flags '"+flags+"', reason: "+parameters[reasonindex]);
@@ -268,13 +263,13 @@ CmdResult CommandFilter::Handle(const std::vector<std::string> &parameters, User
}
else
{
- user->WriteServ("NOTICE %s :*** Filter '%s' could not be added: %s", user->nick.c_str(), freeform.c_str(), result.second.c_str());
+ user->WriteNotice("*** Filter '" + freeform + "' could not be added: " + result.second);
return CMD_FAILURE;
}
}
else
{
- user->WriteServ("NOTICE %s :*** Not enough parameters.", user->nick.c_str());
+ user->WriteNotice("*** Not enough parameters.");
return CMD_FAILURE;
}
@@ -283,7 +278,7 @@ CmdResult CommandFilter::Handle(const std::vector<std::string> &parameters, User
bool ModuleFilter::AppliesToMe(User* user, FilterResult* filter, int iflags)
{
- if ((filter->flag_no_opers) && IS_OPER(user))
+ if ((filter->flag_no_opers) && user->IsOper())
return false;
if ((iflags & FLAG_PRIVMSG) && (!filter->flag_privmsg))
return false;
@@ -301,14 +296,6 @@ ModuleFilter::ModuleFilter()
{
}
-void ModuleFilter::init()
-{
- ServerInstance->Modules->AddService(filtcommand);
- Implementation eventlist[] = { I_OnPreCommand, I_OnStats, I_OnSyncNetwork, I_OnDecodeMetaData, I_OnUserPreMessage, I_OnUserPreNotice, I_OnRehash, I_OnUnloadModule };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- OnRehash(NULL);
-}
-
CullResult ModuleFilter::cull()
{
FreeFilters();
@@ -317,29 +304,19 @@ CullResult ModuleFilter::cull()
void ModuleFilter::FreeFilters()
{
- for (std::vector<ImplFilter>::const_iterator i = filters.begin(); i != filters.end(); ++i)
+ for (std::vector<FilterResult>::const_iterator i = filters.begin(); i != filters.end(); ++i)
delete i->regex;
filters.clear();
}
-ModResult ModuleFilter::OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+ModResult ModuleFilter::OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype)
{
+ // Leave remote users and servers alone
if (!IS_LOCAL(user))
return MOD_RES_PASSTHRU;
- flags = FLAG_PRIVMSG;
- return OnUserPreNotice(user,dest,target_type,text,status,exempt_list);
-}
-
-ModResult ModuleFilter::OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
-{
- /* Leave ulines alone */
- if ((ServerInstance->ULine(user->server)) || (!IS_LOCAL(user)))
- return MOD_RES_PASSTHRU;
-
- if (!flags)
- flags = FLAG_NOTICE;
+ flags = (msgtype == MSG_PRIVMSG) ? FLAG_PRIVMSG : FLAG_NOTICE;
FilterResult* f = this->FilterMatch(user, text, flags);
if (f)
@@ -348,12 +325,16 @@ ModResult ModuleFilter::OnUserPreNotice(User* user,void* dest,int target_type, s
if (target_type == TYPE_USER)
{
User* t = (User*)dest;
+ // Check if the target nick is exempted, if yes, ignore this message
+ if (exemptednicks.count(t->nick))
+ return MOD_RES_PASSTHRU;
+
target = t->nick;
}
else if (target_type == TYPE_CHANNEL)
{
Channel* t = (Channel*)dest;
- if (exemptfromfilter.find(t->name) != exemptfromfilter.end())
+ if (exemptedchans.count(t->name))
return MOD_RES_PASSTHRU;
target = t->name;
@@ -362,16 +343,16 @@ ModResult ModuleFilter::OnUserPreNotice(User* user,void* dest,int target_type, s
{
ServerInstance->SNO->WriteGlobalSno('a', "FILTER: "+user->nick+" had their message filtered, target was "+target+": "+f->reason);
if (target_type == TYPE_CHANNEL)
- user->WriteNumeric(404, "%s %s :Message to channel blocked and opers notified (%s)",user->nick.c_str(), target.c_str(), f->reason.c_str());
+ user->WriteNumeric(ERR_CANNOTSENDTOCHAN, "%s :Message to channel blocked and opers notified (%s)", target.c_str(), f->reason.c_str());
else
- user->WriteServ("NOTICE "+user->nick+" :Your message to "+target+" was blocked and opers notified: "+f->reason);
+ user->WriteNotice("Your message to "+target+" was blocked and opers notified: "+f->reason);
}
else if (f->action == FA_SILENT)
{
if (target_type == TYPE_CHANNEL)
- user->WriteNumeric(404, "%s %s :Message to channel blocked (%s)",user->nick.c_str(), target.c_str(), f->reason.c_str());
+ user->WriteNumeric(ERR_CANNOTSENDTOCHAN, "%s :Message to channel blocked (%s)", target.c_str(), f->reason.c_str());
else
- user->WriteServ("NOTICE "+user->nick+" :Your message to "+target+" was blocked: "+f->reason);
+ user->WriteNotice("Your message to "+target+" was blocked: "+f->reason);
}
else if (f->action == FA_KILL)
{
@@ -388,7 +369,7 @@ ModResult ModuleFilter::OnUserPreNotice(User* user,void* dest,int target_type, s
delete gl;
}
- ServerInstance->Logs->Log("FILTER",DEFAULT,"FILTER: "+ user->nick + " had their message filtered, target was " + target + ": " + f->reason + " Action: " + ModuleFilter::FilterActionToString(f->action));
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, user->nick + " had their message filtered, target was " + target + ": " + f->reason + " Action: " + ModuleFilter::FilterActionToString(f->action));
return MOD_RES_DENY;
}
return MOD_RES_PASSTHRU;
@@ -396,7 +377,7 @@ ModResult ModuleFilter::OnUserPreNotice(User* user,void* dest,int target_type, s
ModResult ModuleFilter::OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line)
{
- if (validated && IS_LOCAL(user))
+ if (validated)
{
flags = 0;
bool parting;
@@ -416,7 +397,7 @@ ModResult ModuleFilter::OnPreCommand(std::string &command, std::vector<std::stri
if (parameters.size() < 2)
return MOD_RES_PASSTHRU;
- if (exemptfromfilter.find(parameters[0]) != exemptfromfilter.end())
+ if (exemptedchans.count(parameters[0]))
return MOD_RES_PASSTHRU;
parting = true;
@@ -446,7 +427,7 @@ ModResult ModuleFilter::OnPreCommand(std::string &command, std::vector<std::stri
/* Are they parting, if so, kill is applicable */
if ((parting) && (f->action == FA_KILL))
{
- user->WriteServ("NOTICE %s :*** Your PART message was filtered: %s", user->nick.c_str(), f->reason.c_str());
+ user->WriteNotice("*** Your PART message was filtered: " + f->reason);
ServerInstance->Users->QuitUser(user, "Filtered: " + f->reason);
}
if (f->action == FA_GLINE)
@@ -466,15 +447,25 @@ ModResult ModuleFilter::OnPreCommand(std::string &command, std::vector<std::stri
return MOD_RES_PASSTHRU;
}
-void ModuleFilter::OnRehash(User* user)
+void ModuleFilter::ReadConfig(ConfigStatus& status)
{
ConfigTagList tags = ServerInstance->Config->ConfTags("exemptfromfilter");
- exemptfromfilter.clear();
+ exemptedchans.clear();
+ exemptednicks.clear();
+
for (ConfigIter i = tags.first; i != tags.second; ++i)
{
- std::string chan = i->second->getString("channel");
- if (!chan.empty())
- exemptfromfilter.insert(chan);
+ ConfigTag* tag = i->second;
+
+ // If "target" is not found, try the old "channel" key to keep compatibility with 2.0 configs
+ const std::string target = tag->getString("target", tag->getString("channel"));
+ if (!target.empty())
+ {
+ if (target[0] == '#')
+ exemptedchans.insert(target);
+ else
+ exemptednicks.insert(target);
+ }
}
std::string newrxengine = ServerInstance->Config->ConfValue("filteropts")->getString("engine");
@@ -554,11 +545,11 @@ FilterResult ModuleFilter::DecodeFilter(const std::string &data)
return res;
}
-void ModuleFilter::OnSyncNetwork(Module* proto, void* opaque)
+void ModuleFilter::OnSyncNetwork(ProtocolInterface::Server& server)
{
- for (std::vector<ImplFilter>::iterator i = filters.begin(); i != filters.end(); ++i)
+ for (std::vector<FilterResult>::iterator i = filters.begin(); i != filters.end(); ++i)
{
- proto->ProtoSendMetaData(opaque, NULL, "filter", EncodeFilter(&(*i)));
+ server.SendMetaData("filter", EncodeFilter(&(*i)));
}
}
@@ -573,27 +564,19 @@ void ModuleFilter::OnDecodeMetaData(Extensible* target, const std::string &extna
}
catch (ModuleException& e)
{
- ServerInstance->Logs->Log("m_filter", DEBUG, "Error when unserializing filter: " + std::string(e.GetReason()));
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Error when unserializing filter: " + e.GetReason());
}
}
}
-ImplFilter::ImplFilter(ModuleFilter* mymodule, const std::string &rea, FilterAction act, long glinetime, const std::string &pat, const std::string &flgs)
- : FilterResult(pat, rea, act, glinetime, flgs)
-{
- if (!mymodule->RegexEngine)
- throw ModuleException("Regex module implementing '"+mymodule->RegexEngine.GetProvider()+"' is not loaded!");
- regex = mymodule->RegexEngine->Create(pat);
-}
-
FilterResult* ModuleFilter::FilterMatch(User* user, const std::string &text, int flgs)
{
static std::string stripped_text;
stripped_text.clear();
- for (std::vector<ImplFilter>::iterator index = filters.begin(); index != filters.end(); index++)
+ for (std::vector<FilterResult>::iterator i = filters.begin(); i != filters.end(); ++i)
{
- FilterResult* filter = dynamic_cast<FilterResult*>(&(*index));
+ FilterResult* filter = &*i;
/* Skip ones that dont apply to us */
if (!AppliesToMe(user, filter, flgs))
@@ -605,20 +588,15 @@ FilterResult* ModuleFilter::FilterMatch(User* user, const std::string &text, int
InspIRCd::StripColor(stripped_text);
}
- //ServerInstance->Logs->Log("m_filter", DEBUG, "Match '%s' against '%s'", text.c_str(), index->freeform.c_str());
- if (index->regex->Matches(filter->flag_strip_color ? stripped_text : text))
- {
- //ServerInstance->Logs->Log("m_filter", DEBUG, "MATCH");
- return &*index;
- }
- //ServerInstance->Logs->Log("m_filter", DEBUG, "NO MATCH");
+ if (filter->regex->Matches(filter->flag_strip_color ? stripped_text : text))
+ return filter;
}
return NULL;
}
bool ModuleFilter::DeleteFilter(const std::string &freeform)
{
- for (std::vector<ImplFilter>::iterator i = filters.begin(); i != filters.end(); i++)
+ for (std::vector<FilterResult>::iterator i = filters.begin(); i != filters.end(); i++)
{
if (i->freeform == freeform)
{
@@ -632,7 +610,7 @@ bool ModuleFilter::DeleteFilter(const std::string &freeform)
std::pair<bool, std::string> ModuleFilter::AddFilter(const std::string &freeform, FilterAction type, const std::string &reason, long duration, const std::string &flgs)
{
- for (std::vector<ImplFilter>::iterator i = filters.begin(); i != filters.end(); i++)
+ for (std::vector<FilterResult>::iterator i = filters.begin(); i != filters.end(); i++)
{
if (i->freeform == freeform)
{
@@ -642,11 +620,11 @@ std::pair<bool, std::string> ModuleFilter::AddFilter(const std::string &freeform
try
{
- filters.push_back(ImplFilter(this, reason, type, duration, freeform, flgs));
+ filters.push_back(FilterResult(RegexEngine, freeform, reason, type, duration, flgs));
}
catch (ModuleException &e)
{
- ServerInstance->Logs->Log("m_filter", DEFAULT, "Error in regular expression '%s': %s", freeform.c_str(), e.GetReason());
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Error in regular expression '%s': %s", freeform.c_str(), e.GetReason().c_str());
return std::make_pair(false, e.GetReason());
}
return std::make_pair(true, "");
@@ -695,7 +673,7 @@ void ModuleFilter::ReadFilters()
std::string reason = i->second->getString("reason");
std::string action = i->second->getString("action");
std::string flgs = i->second->getString("flags");
- long gline_time = ServerInstance->Duration(i->second->getString("duration"));
+ unsigned long gline_time = i->second->getDuration("duration", 10*60, 1);
if (flgs.empty())
flgs = "*";
@@ -705,12 +683,12 @@ void ModuleFilter::ReadFilters()
try
{
- filters.push_back(ImplFilter(this, reason, fa, gline_time, pattern, flgs));
- ServerInstance->Logs->Log("m_filter", DEFAULT, "Regular expression %s loaded.", pattern.c_str());
+ filters.push_back(FilterResult(RegexEngine, pattern, reason, fa, gline_time, flgs));
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Regular expression %s loaded.", pattern.c_str());
}
catch (ModuleException &e)
{
- ServerInstance->Logs->Log("m_filter", DEFAULT, "Error in regular expression '%s': %s", pattern.c_str(), e.GetReason());
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Error in regular expression '%s': %s", pattern.c_str(), e.GetReason().c_str());
}
}
}
@@ -719,13 +697,17 @@ ModResult ModuleFilter::OnStats(char symbol, User* user, string_list &results)
{
if (symbol == 's')
{
- for (std::vector<ImplFilter>::iterator i = filters.begin(); i != filters.end(); i++)
+ for (std::vector<FilterResult>::iterator i = filters.begin(); i != filters.end(); i++)
+ {
+ results.push_back("223 "+user->nick+" :"+RegexEngine.GetProvider()+":"+i->freeform+" "+i->GetFlags()+" "+FilterActionToString(i->action)+" "+ConvToStr(i->gline_time)+" :"+i->reason);
+ }
+ for (ExemptTargetSet::const_iterator i = exemptedchans.begin(); i != exemptedchans.end(); ++i)
{
- results.push_back(ServerInstance->Config->ServerName+" 223 "+user->nick+" :"+RegexEngine.GetProvider()+":"+i->freeform+" "+i->GetFlags()+" "+FilterActionToString(i->action)+" "+ConvToStr(i->gline_time)+" :"+i->reason);
+ results.push_back("223 "+user->nick+" :EXEMPT "+(*i));
}
- for (std::set<std::string>::iterator i = exemptfromfilter.begin(); i != exemptfromfilter.end(); ++i)
+ for (ExemptTargetSet::const_iterator i = exemptednicks.begin(); i != exemptednicks.end(); ++i)
{
- results.push_back(ServerInstance->Config->ServerName+" 223 "+user->nick+" :EXEMPT "+(*i));
+ results.push_back("223 "+user->nick+" :EXEMPT "+(*i));
}
}
return MOD_RES_PASSTHRU;
diff --git a/src/modules/m_flashpolicyd.cpp b/src/modules/m_flashpolicyd.cpp
new file mode 100644
index 000000000..95b82848f
--- /dev/null
+++ b/src/modules/m_flashpolicyd.cpp
@@ -0,0 +1,158 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2013 Daniel Vassdal <shutter@canternet.org>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+
+class FlashPDSocket;
+
+namespace
+{
+ std::set<FlashPDSocket*> sockets;
+ std::string policy_reply;
+ const std::string expected_request("<policy-file-request/>\0", 23);
+}
+
+class FlashPDSocket : public BufferedSocket
+{
+ public:
+ time_t created;
+
+ FlashPDSocket(int newfd)
+ : BufferedSocket(newfd)
+ , created(ServerInstance->Time())
+ {
+ }
+
+ ~FlashPDSocket()
+ {
+ sockets.erase(this);
+ }
+
+ void OnError(BufferedSocketError) CXX11_OVERRIDE
+ {
+ AddToCull();
+ }
+
+ void OnDataReady() CXX11_OVERRIDE
+ {
+ if (recvq == expected_request)
+ WriteData(policy_reply);
+ AddToCull();
+ }
+
+ void AddToCull()
+ {
+ if (created == 0)
+ return;
+
+ created = 0;
+ Close();
+ ServerInstance->GlobalCulls.AddItem(this);
+ }
+};
+
+class ModuleFlashPD : public Module
+{
+ time_t timeout;
+
+ public:
+ void OnBackgroundTimer(time_t curtime) CXX11_OVERRIDE
+ {
+ for (std::set<FlashPDSocket*>::const_iterator i = sockets.begin(); i != sockets.end(); ++i)
+ {
+ FlashPDSocket* sock = *i;
+ if ((sock->created + timeout <= curtime) && (sock->created != 0))
+ sock->AddToCull();
+ }
+ }
+
+ ModResult OnAcceptConnection(int nfd, ListenSocket* from, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) CXX11_OVERRIDE
+ {
+ if (from->bind_tag->getString("type") != "flashpolicyd")
+ return MOD_RES_PASSTHRU;
+
+ if (policy_reply.empty())
+ return MOD_RES_DENY;
+
+ sockets.insert(new FlashPDSocket(nfd));
+ return MOD_RES_ALLOW;
+ }
+
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
+ {
+ ConfigTag* tag = ServerInstance->Config->ConfValue("flashpolicyd");
+ timeout = tag->getInt("timeout", 5, 1);
+ std::string file = tag->getString("file");
+
+ if (!file.empty())
+ {
+ try
+ {
+ FileReader reader(file);
+ policy_reply = reader.GetString();
+ }
+ catch (CoreException&)
+ {
+ const std::string error_message = "A file was specified for FlashPD, but it could not be loaded.";
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, error_message);
+ ServerInstance->SNO->WriteGlobalSno('a', error_message);
+ policy_reply.clear();
+ }
+ return;
+ }
+
+ // A file was not specified. Set the default setting.
+ // We allow access to all client ports by default
+ std::string to_ports;
+ for (std::vector<ListenSocket*>::const_iterator i = ServerInstance->ports.begin(); i != ServerInstance->ports.end(); ++i)
+ {
+ ListenSocket* ls = *i;
+ if (ls->bind_tag->getString("type", "clients") != "clients" || ls->bind_tag->getString("ssl", "plaintext") != "plaintext")
+ continue;
+
+ to_ports.append(ConvToStr(ls->bind_port)).push_back(',');
+ }
+ to_ports.erase(to_ports.size() - 1);
+
+ policy_reply =
+"<?xml version=\"1.0\"?>\
+<!DOCTYPE cross-domain-policy SYSTEM \"/xml/dtds/cross-domain-policy.dtd\">\
+<cross-domain-policy>\
+<site-control permitted-cross-domain-policies=\"master-only\"/>\
+<allow-access-from domain=\"*\" to-ports=\"" + to_ports + "\" />\
+</cross-domain-policy>";
+ }
+
+ CullResult cull()
+ {
+ for (std::set<FlashPDSocket*>::const_iterator i = sockets.begin(); i != sockets.end(); ++i)
+ {
+ FlashPDSocket* sock = *i;
+ sock->AddToCull();
+ }
+ return Module::cull();
+ }
+
+ Version GetVersion() CXX11_OVERRIDE
+ {
+ return Version("Flash Policy Daemon. Allows Flash IRC clients to connect", VF_VENDOR);
+ }
+};
+
+MODULE_INIT(ModuleFlashPD)
diff --git a/src/modules/m_gecosban.cpp b/src/modules/m_gecosban.cpp
index 1497c1b87..a15f19418 100644
--- a/src/modules/m_gecosban.cpp
+++ b/src/modules/m_gecosban.cpp
@@ -19,27 +19,15 @@
#include "inspircd.h"
-/* $ModDesc: Implements extban +b r: - realname (gecos) bans */
-
class ModuleGecosBan : public Module
{
public:
- void init()
- {
- Implementation eventlist[] = { I_OnCheckBan, I_On005Numeric };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- ~ModuleGecosBan()
- {
- }
-
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Extban 'r' - realname (gecos) ban", VF_OPTCOMMON|VF_VENDOR);
}
- ModResult OnCheckBan(User *user, Channel *c, const std::string& mask)
+ ModResult OnCheckBan(User *user, Channel *c, const std::string& mask) CXX11_OVERRIDE
{
if ((mask.length() > 2) && (mask[0] == 'r') && (mask[1] == ':'))
{
@@ -49,9 +37,9 @@ class ModuleGecosBan : public Module
return MOD_RES_PASSTHRU;
}
- void On005Numeric(std::string &output)
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
- ServerInstance->AddExtBanChar('r');
+ tokens["EXTBAN"].push_back('r');
}
};
diff --git a/src/modules/m_globalload.cpp b/src/modules/m_globalload.cpp
index 9e0ec7705..8ee8472e6 100644
--- a/src/modules/m_globalload.cpp
+++ b/src/modules/m_globalload.cpp
@@ -22,8 +22,6 @@
*/
-/* $ModDesc: Allows global loading of a module. */
-
#include "inspircd.h"
/** Handle /GLOADMODULE
@@ -35,7 +33,6 @@ class CommandGloadmodule : public Command
{
flags_needed = 'o';
syntax = "<modulename> [servermask]";
- TRANSLATE3(TR_TEXT, TR_TEXT, TR_END);
}
CmdResult Handle (const std::vector<std::string> &parameters, User *user)
@@ -47,11 +44,11 @@ class CommandGloadmodule : public Command
if (ServerInstance->Modules->Load(parameters[0].c_str()))
{
ServerInstance->SNO->WriteToSnoMask('a', "NEW MODULE '%s' GLOBALLY LOADED BY '%s'",parameters[0].c_str(), user->nick.c_str());
- user->WriteNumeric(975, "%s %s :Module successfully loaded.",user->nick.c_str(), parameters[0].c_str());
+ user->WriteNumeric(RPL_LOADEDMODULE, "%s :Module successfully loaded.", parameters[0].c_str());
}
else
{
- user->WriteNumeric(974, "%s %s :%s",user->nick.c_str(), parameters[0].c_str(), ServerInstance->Modules->LastError().c_str());
+ user->WriteNumeric(ERR_CANTLOADMODULE, "%s :%s", parameters[0].c_str(), ServerInstance->Modules->LastError().c_str());
}
}
else
@@ -79,6 +76,13 @@ class CommandGunloadmodule : public Command
CmdResult Handle (const std::vector<std::string> &parameters, User *user)
{
+ if (!ServerInstance->Config->ConfValue("security")->getBool("allowcoreunload") &&
+ InspIRCd::Match(parameters[0], "core_*.so", ascii_case_insensitive_map))
+ {
+ user->WriteNumeric(ERR_CANTUNLOADMODULE, "%s :You cannot unload core commands!", parameters[0].c_str());
+ return CMD_FAILURE;
+ }
+
std::string servername = parameters.size() > 1 ? parameters[1] : "*";
if (InspIRCd::Match(ServerInstance->Config->ServerName.c_str(), servername))
@@ -94,11 +98,11 @@ class CommandGunloadmodule : public Command
}
else
{
- user->WriteNumeric(972, "%s %s :%s",user->nick.c_str(), parameters[0].c_str(), ServerInstance->Modules->LastError().c_str());
+ user->WriteNumeric(ERR_CANTUNLOADMODULE, "%s :%s", parameters[0].c_str(), ServerInstance->Modules->LastError().c_str());
}
}
else
- user->SendText(":%s 972 %s %s :No such module", ServerInstance->Config->ServerName.c_str(), user->nick.c_str(), parameters[0].c_str());
+ user->SendText(":%s %03d %s %s :No such module", ServerInstance->Config->ServerName.c_str(), ERR_CANTUNLOADMODULE, user->nick.c_str(), parameters[0].c_str());
}
else
ServerInstance->SNO->WriteToSnoMask('a', "MODULE '%s' GLOBAL UNLOAD BY '%s' (not unloaded here)",parameters[0].c_str(), user->nick.c_str());
@@ -125,8 +129,8 @@ class GReloadModuleWorker : public HandlerBase1<void, bool>
ServerInstance->SNO->WriteToSnoMask('a', "MODULE '%s' GLOBALLY RELOADED BY '%s'%s", name.c_str(), nick.c_str(), result ? "" : " (failed here)");
User* user = ServerInstance->FindNick(uid);
if (user)
- user->WriteNumeric(975, "%s %s :Module %ssuccessfully reloaded.",
- user->nick.c_str(), name.c_str(), result ? "" : "un");
+ user->WriteNumeric(RPL_LOADEDMODULE, "%s :Module %ssuccessfully reloaded.",
+ name.c_str(), result ? "" : "un");
ServerInstance->GlobalCulls.AddItem(this);
}
};
@@ -157,7 +161,7 @@ class CommandGreloadmodule : public Command
}
else
{
- user->WriteNumeric(975, "%s %s :Could not find module by that name", user->nick.c_str(), parameters[0].c_str());
+ user->WriteNumeric(RPL_LOADEDMODULE, "%s :Could not find module by that name", parameters[0].c_str());
return CMD_FAILURE;
}
}
@@ -185,22 +189,10 @@ class ModuleGlobalLoad : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cmd1);
- ServerInstance->Modules->AddService(cmd2);
- ServerInstance->Modules->AddService(cmd3);
- }
-
- ~ModuleGlobalLoad()
- {
- }
-
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Allows global loading of a module.", VF_COMMON | VF_VENDOR);
}
};
MODULE_INIT(ModuleGlobalLoad)
-
diff --git a/src/modules/m_globops.cpp b/src/modules/m_globops.cpp
index 85d84252b..1cb87324b 100644
--- a/src/modules/m_globops.cpp
+++ b/src/modules/m_globops.cpp
@@ -23,8 +23,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides support for GLOBOPS and snomask +g */
-
/** Handle /GLOBOPS
*/
class CommandGlobops : public Command
@@ -33,7 +31,6 @@ class CommandGlobops : public Command
CommandGlobops(Module* Creator) : Command(Creator,"GLOBOPS", 1,1)
{
flags_needed = 'o'; syntax = "<any-text>";
- TRANSLATE2(TR_TEXT, TR_END);
}
CmdResult Handle (const std::vector<std::string> &parameters, User *user)
@@ -49,17 +46,15 @@ class ModuleGlobops : public Module
public:
ModuleGlobops() : cmd(this) {}
- void init()
+ void init() CXX11_OVERRIDE
{
- ServerInstance->Modules->AddService(cmd);
ServerInstance->SNO->EnableSnomask('g',"GLOBOPS");
}
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for GLOBOPS and snomask +g", VF_VENDOR);
}
-
};
MODULE_INIT(ModuleGlobops)
diff --git a/src/modules/m_halfop.cpp b/src/modules/m_halfop.cpp
deleted file mode 100644
index 3194fcde8..000000000
--- a/src/modules/m_halfop.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-/* $ModDesc: Channel half-operator mode provider */
-
-#include "inspircd.h"
-
-class ModeChannelHalfOp : public ModeHandler
-{
- public:
- ModeChannelHalfOp(Module* parent);
- ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding);
- unsigned int GetPrefixRank();
- void RemoveMode(Channel* channel, irc::modestacker* stack = NULL);
- void RemoveMode(User* user, irc::modestacker* stack = NULL);
-
- ModResult AccessCheck(User* src, Channel*, std::string& value, bool adding)
- {
- if (!adding && src->nick == value)
- return MOD_RES_ALLOW;
- return MOD_RES_PASSTHRU;
- }
-};
-
-ModeChannelHalfOp::ModeChannelHalfOp(Module* parent) : ModeHandler(parent, "halfop", 'h', PARAM_ALWAYS, MODETYPE_CHANNEL)
-{
- list = true;
- prefix = '%';
- levelrequired = OP_VALUE;
- m_paramtype = TR_NICK;
-}
-
-unsigned int ModeChannelHalfOp::GetPrefixRank()
-{
- return HALFOP_VALUE;
-}
-
-void ModeChannelHalfOp::RemoveMode(Channel* channel, irc::modestacker* stack)
-{
- const UserMembList* clist = channel->GetUsers();
-
- for (UserMembCIter i = clist->begin(); i != clist->end(); i++)
- {
- if (stack)
- {
- stack->Push(this->GetModeChar(), i->first->nick);
- }
- else
- {
- std::vector<std::string> parameters;
- parameters.push_back(channel->name);
- parameters.push_back("-h");
- parameters.push_back(i->first->nick);
- ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
- }
- }
-
-}
-
-void ModeChannelHalfOp::RemoveMode(User*, irc::modestacker* stack)
-{
-}
-
-ModeAction ModeChannelHalfOp::OnModeChange(User* source, User*, Channel* channel, std::string &parameter, bool adding)
-{
- return MODEACTION_ALLOW;
-}
-
-class ModuleHalfop : public Module
-{
- ModeChannelHalfOp mh;
- public:
- ModuleHalfop() : mh(this)
- {
- }
-
- void init()
- {
- ServerInstance->Modules->AddService(mh);
- }
-
- Version GetVersion()
- {
- return Version("Channel half-operator mode provider", VF_VENDOR);
- }
-};
-
-MODULE_INIT(ModuleHalfop)
diff --git a/src/modules/m_helpop.cpp b/src/modules/m_helpop.cpp
index 4bbe8785e..2fe958a71 100644
--- a/src/modules/m_helpop.cpp
+++ b/src/modules/m_helpop.cpp
@@ -21,11 +21,10 @@
*/
-/* $ModDesc: Provides the /HELPOP command for useful information */
-
#include "inspircd.h"
-static std::map<irc::string, std::string> helpop_map;
+typedef std::map<std::string, std::string, irc::insensitive_swo> HelpopMap;
+static HelpopMap helpop_map;
/** Handles user mode +h
*/
@@ -42,41 +41,40 @@ class Helpop : public SimpleUserModeHandler
*/
class CommandHelpop : public Command
{
+ const std::string startkey;
public:
- CommandHelpop(Module* Creator) : Command(Creator, "HELPOP", 0)
+ CommandHelpop(Module* Creator)
+ : Command(Creator, "HELPOP", 0)
+ , startkey("start")
{
syntax = "<any-text>";
}
CmdResult Handle (const std::vector<std::string> &parameters, User *user)
{
- irc::string parameter("start");
- if (parameters.size() > 0)
- parameter = parameters[0].c_str();
+ const std::string& parameter = (!parameters.empty() ? parameters[0] : startkey);
if (parameter == "index")
{
/* iterate over all helpop items */
- user->WriteServ("290 %s :HELPOP topic index", user->nick.c_str());
- for (std::map<irc::string, std::string>::iterator iter = helpop_map.begin(); iter != helpop_map.end(); iter++)
- {
- user->WriteServ("292 %s : %s", user->nick.c_str(), iter->first.c_str());
- }
- user->WriteServ("292 %s :*** End of HELPOP topic index", user->nick.c_str());
+ user->WriteNumeric(290, ":HELPOP topic index");
+ for (HelpopMap::const_iterator iter = helpop_map.begin(); iter != helpop_map.end(); iter++)
+ user->WriteNumeric(292, ": %s", iter->first.c_str());
+ user->WriteNumeric(292, ":*** End of HELPOP topic index");
}
else
{
- user->WriteServ("290 %s :*** HELPOP for %s", user->nick.c_str(), parameter.c_str());
- user->WriteServ("292 %s : -", user->nick.c_str());
+ user->WriteNumeric(290, ":*** HELPOP for %s", parameter.c_str());
+ user->WriteNumeric(292, ": -");
- std::map<irc::string, std::string>::iterator iter = helpop_map.find(parameter);
+ HelpopMap::const_iterator iter = helpop_map.find(parameter);
if (iter == helpop_map.end())
{
iter = helpop_map.find("nohelp");
}
- std::string value = iter->second;
+ const std::string& value = iter->second;
irc::sepstream stream(value, '\n');
std::string token = "*";
@@ -84,13 +82,13 @@ class CommandHelpop : public Command
{
// Writing a blank line will not work with some clients
if (token.empty())
- user->WriteServ("292 %s : ", user->nick.c_str());
+ user->WriteNumeric(292, ": ");
else
- user->WriteServ("292 %s :%s", user->nick.c_str(), token.c_str());
+ user->WriteNumeric(292, ":%s", token.c_str());
}
- user->WriteServ("292 %s : -", user->nick.c_str());
- user->WriteServ("292 %s :*** End of HELPOP", user->nick.c_str());
+ user->WriteNumeric(292, ": -");
+ user->WriteNumeric(292, ":*** End of HELPOP");
}
return CMD_SUCCESS;
}
@@ -98,7 +96,6 @@ class CommandHelpop : public Command
class ModuleHelpop : public Module
{
- private:
CommandHelpop cmd;
Helpop ho;
@@ -108,24 +105,15 @@ class ModuleHelpop : public Module
{
}
- void init()
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
- ReadConfig();
- ServerInstance->Modules->AddService(ho);
- ServerInstance->Modules->AddService(cmd);
- Implementation eventlist[] = { I_OnRehash, I_OnWhois };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- void ReadConfig()
- {
- std::map<irc::string, std::string> help;
+ HelpopMap help;
ConfigTagList tags = ServerInstance->Config->ConfTags("helpop");
for(ConfigIter i = tags.first; i != tags.second; ++i)
{
ConfigTag* tag = i->second;
- irc::string key = assign(tag->getString("key"));
+ std::string key = tag->getString("key");
std::string value;
tag->readString("value", value, true); /* Linefeeds allowed */
@@ -151,20 +139,15 @@ class ModuleHelpop : public Module
helpop_map.swap(help);
}
- void OnRehash(User* user)
- {
- ReadConfig();
- }
-
- void OnWhois(User* src, User* dst)
+ void OnWhois(User* src, User* dst) CXX11_OVERRIDE
{
- if (dst->IsModeSet('h'))
+ if (dst->IsModeSet(ho))
{
- ServerInstance->SendWhoisLine(src, dst, 310, src->nick+" "+dst->nick+" :is available for help.");
+ ServerInstance->SendWhoisLine(src, dst, 310, dst->nick+" :is available for help.");
}
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides the /HELPOP command for useful information", VF_VENDOR);
}
diff --git a/src/modules/m_hidechans.cpp b/src/modules/m_hidechans.cpp
index 008c62208..cd3ac2c26 100644
--- a/src/modules/m_hidechans.cpp
+++ b/src/modules/m_hidechans.cpp
@@ -20,8 +20,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides support for hiding channels with user mode +I */
-
/** Handles user mode +I
*/
class HideChans : public SimpleUserModeHandler
@@ -39,29 +37,17 @@ class ModuleHideChans : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(hm);
- Implementation eventlist[] = { I_OnWhoisLine, I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- OnRehash(NULL);
- }
-
- virtual ~ModuleHideChans()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for hiding channels with user mode +I", VF_VENDOR);
}
- virtual void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
AffectsOpers = ServerInstance->Config->ConfValue("hidechans")->getBool("affectsopers");
}
- ModResult OnWhoisLine(User* user, User* dest, int &numeric, std::string &text)
+ ModResult OnWhoisLine(User* user, User* dest, int &numeric, std::string &text) CXX11_OVERRIDE
{
/* always show to self */
if (user == dest)
@@ -72,7 +58,7 @@ class ModuleHideChans : public Module
return MOD_RES_PASSTHRU;
/* don't touch if -I */
- if (!dest->IsModeSet('I'))
+ if (!dest->IsModeSet(hm))
return MOD_RES_PASSTHRU;
/* if it affects opers, we don't care if they are opered */
@@ -88,5 +74,4 @@ class ModuleHideChans : public Module
}
};
-
MODULE_INIT(ModuleHideChans)
diff --git a/src/modules/m_hideoper.cpp b/src/modules/m_hideoper.cpp
index b83c7de1a..5b226f3b8 100644
--- a/src/modules/m_hideoper.cpp
+++ b/src/modules/m_hideoper.cpp
@@ -21,8 +21,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides support for hiding oper status with user mode +H */
-
/** Handles user mode +H
*/
class HideOper : public SimpleUserModeHandler
@@ -43,24 +41,12 @@ class ModuleHideOper : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(hm);
- Implementation eventlist[] = { I_OnWhoisLine, I_OnSendWhoLine, I_OnStats };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
-
- virtual ~ModuleHideOper()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for hiding oper status with user mode +H", VF_VENDOR);
}
- ModResult OnWhoisLine(User* user, User* dest, int &numeric, std::string &text)
+ ModResult OnWhoisLine(User* user, User* dest, int &numeric, std::string &text) CXX11_OVERRIDE
{
/* Dont display numeric 313 (RPL_WHOISOPER) if they have +H set and the
* person doing the WHOIS is not an oper
@@ -68,7 +54,7 @@ class ModuleHideOper : public Module
if (numeric != 313)
return MOD_RES_PASSTHRU;
- if (!dest->IsModeSet('H'))
+ if (!dest->IsModeSet(hm))
return MOD_RES_PASSTHRU;
if (!user->HasPrivPermission("users/auspex"))
@@ -77,9 +63,9 @@ class ModuleHideOper : public Module
return MOD_RES_PASSTHRU;
}
- void OnSendWhoLine(User* source, const std::vector<std::string>& params, User* user, std::string& line)
+ void OnSendWhoLine(User* source, const std::vector<std::string>& params, User* user, Membership* memb, std::string& line) CXX11_OVERRIDE
{
- if (user->IsModeSet('H') && !source->HasPrivPermission("users/auspex"))
+ if (user->IsModeSet(hm) && !source->HasPrivPermission("users/auspex"))
{
// hide the "*" that marks the user as an oper from the /WHO line
std::string::size_type pos = line.find("*");
@@ -91,27 +77,28 @@ class ModuleHideOper : public Module
}
}
- ModResult OnStats(char symbol, User* user, string_list &results)
+ ModResult OnStats(char symbol, User* user, string_list& results) CXX11_OVERRIDE
{
if (symbol != 'P')
return MOD_RES_PASSTHRU;
unsigned int count = 0;
- for (std::list<User*>::const_iterator i = ServerInstance->Users->all_opers.begin(); i != ServerInstance->Users->all_opers.end(); ++i)
+ const UserManager::OperList& opers = ServerInstance->Users->all_opers;
+ for (UserManager::OperList::const_iterator i = opers.begin(); i != opers.end(); ++i)
{
User* oper = *i;
- if (!ServerInstance->ULine(oper->server) && (IS_OPER(user) || !oper->IsModeSet('H')))
+ if (!oper->server->IsULine() && (user->IsOper() || !oper->IsModeSet(hm)))
{
- results.push_back(ServerInstance->Config->ServerName+" 249 " + user->nick + " :" + oper->nick + " (" + oper->ident + "@" + oper->dhost + ") Idle: " +
- (IS_LOCAL(oper) ? ConvToStr(ServerInstance->Time() - oper->idle_lastmsg) + " secs" : "unavailable"));
+ LocalUser* lu = IS_LOCAL(oper);
+ results.push_back("249 " + user->nick + " :" + oper->nick + " (" + oper->ident + "@" + oper->dhost + ") Idle: " +
+ (lu ? ConvToStr(ServerInstance->Time() - lu->idle_lastmsg) + " secs" : "unavailable"));
count++;
}
}
- results.push_back(ServerInstance->Config->ServerName+" 249 "+user->nick+" :"+ConvToStr(count)+" OPER(s)");
+ results.push_back("249 "+user->nick+" :"+ConvToStr(count)+" OPER(s)");
return MOD_RES_DENY;
}
};
-
MODULE_INIT(ModuleHideOper)
diff --git a/src/modules/m_hostchange.cpp b/src/modules/m_hostchange.cpp
index 7433fccd3..6d5896ef5 100644
--- a/src/modules/m_hostchange.cpp
+++ b/src/modules/m_hostchange.cpp
@@ -21,8 +21,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides masking of user hostnames in a different way to m_cloaking */
-
/** Holds information on a host set by m_hostchange
*/
class Host
@@ -47,21 +45,13 @@ typedef std::vector<std::pair<std::string, Host> > hostchanges_t;
class ModuleHostChange : public Module
{
- private:
hostchanges_t hostchanges;
std::string MySuffix;
std::string MyPrefix;
std::string MySeparator;
public:
- void init()
- {
- OnRehash(NULL);
- Implementation eventlist[] = { I_OnRehash, I_OnUserConnect };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- virtual void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ConfigTag* host = ServerInstance->Config->ConfValue("host");
MySuffix = host->getString("suffix");
@@ -97,14 +87,14 @@ class ModuleHostChange : public Module
}
}
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
// returns the version number of the module to be
// listed in /MODULES
return Version("Provides masking of user hostnames in a different way to m_cloaking", VF_VENDOR);
}
- virtual void OnUserConnect(LocalUser* user)
+ void OnUserConnect(LocalUser* user) CXX11_OVERRIDE
{
for (hostchanges_t::iterator i = hostchanges.begin(); i != hostchanges.end(); i++)
{
@@ -160,9 +150,9 @@ class ModuleHostChange : public Module
}
if (!newhost.empty())
{
- user->WriteServ("NOTICE "+user->nick+" :Setting your virtual host: " + newhost);
- if (!user->ChangeDisplayedHost(newhost.c_str()))
- user->WriteServ("NOTICE "+user->nick+" :Could not set your virtual host: " + newhost);
+ user->WriteNotice("Setting your virtual host: " + newhost);
+ if (!user->ChangeDisplayedHost(newhost))
+ user->WriteNotice("Could not set your virtual host: " + newhost);
return;
}
}
diff --git a/src/modules/m_hostcycle.cpp b/src/modules/m_hostcycle.cpp
new file mode 100644
index 000000000..e8a0abbf1
--- /dev/null
+++ b/src/modules/m_hostcycle.cpp
@@ -0,0 +1,114 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2013 Attila Molnar <attilamolnar@hush.com>
+ * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+
+class ModuleHostCycle : public Module
+{
+ /** Send fake quit/join/mode messages for host or ident cycle.
+ */
+ static void DoHostCycle(User* user, const std::string& newident, const std::string& newhost, const char* quitmsg)
+ {
+ // GetFullHost() returns the original data at the time this function is called
+ const std::string quitline = ":" + user->GetFullHost() + " QUIT :" + quitmsg;
+
+ already_sent_t silent_id = ++LocalUser::already_sent_id;
+ already_sent_t seen_id = ++LocalUser::already_sent_id;
+
+ IncludeChanList include_chans(user->chans.begin(), user->chans.end());
+ std::map<User*,bool> exceptions;
+
+ FOREACH_MOD(OnBuildNeighborList, (user, include_chans, exceptions));
+
+ for (std::map<User*,bool>::iterator i = exceptions.begin(); i != exceptions.end(); ++i)
+ {
+ LocalUser* u = IS_LOCAL(i->first);
+ if (u && !u->quitting)
+ {
+ if (i->second)
+ {
+ u->already_sent = seen_id;
+ u->Write(quitline);
+ }
+ else
+ {
+ u->already_sent = silent_id;
+ }
+ }
+ }
+
+ std::string newfullhost = user->nick + "!" + newident + "@" + newhost;
+
+ for (IncludeChanList::const_iterator i = include_chans.begin(); i != include_chans.end(); ++i)
+ {
+ Membership* memb = *i;
+ Channel* c = memb->chan;
+ const std::string joinline = ":" + newfullhost + " JOIN " + c->name;
+ std::string modeline;
+
+ if (!memb->modes.empty())
+ {
+ modeline = ":" + (ServerInstance->Config->CycleHostsFromUser ? newfullhost : ServerInstance->Config->ServerName)
+ + " MODE " + c->name + " +" + memb->modes;
+
+ for (size_t j = 0; j < memb->modes.length(); j++)
+ modeline.append(" ").append(user->nick);
+ }
+
+ const Channel::MemberMap& ulist = c->GetUsers();
+ for (Channel::MemberMap::const_iterator j = ulist.begin(); j != ulist.end(); ++j)
+ {
+ LocalUser* u = IS_LOCAL(j->first);
+ if (u == NULL || u == user)
+ continue;
+ if (u->already_sent == silent_id)
+ continue;
+
+ if (u->already_sent != seen_id)
+ {
+ u->Write(quitline);
+ u->already_sent = seen_id;
+ }
+
+ u->Write(joinline);
+ if (!memb->modes.empty())
+ u->Write(modeline);
+ }
+ }
+ }
+
+ public:
+ void OnChangeIdent(User* user, const std::string& newident) CXX11_OVERRIDE
+ {
+ DoHostCycle(user, newident, user->dhost, "Changing ident");
+ }
+
+ void OnChangeHost(User* user, const std::string& newhost) CXX11_OVERRIDE
+ {
+ DoHostCycle(user, user->ident, newhost, "Changing host");
+ }
+
+ Version GetVersion() CXX11_OVERRIDE
+ {
+ return Version("Cycles users in all their channels when their host or ident changes", VF_VENDOR);
+ }
+};
+
+MODULE_INIT(ModuleHostCycle)
diff --git a/src/modules/m_httpd.cpp b/src/modules/m_httpd.cpp
index 2a430d967..bf372f34f 100644
--- a/src/modules/m_httpd.cpp
+++ b/src/modules/m_httpd.cpp
@@ -23,10 +23,8 @@
#include "inspircd.h"
-#include "httpd.h"
-
-/* $ModDesc: Provides HTTP serving facilities to modules */
-/* $ModDep: httpd.h */
+#include "iohook.h"
+#include "modules/httpd.h"
class ModuleHttpServer;
@@ -67,9 +65,8 @@ class HttpServerSocket : public BufferedSocket
{
InternalState = HTTP_SERVE_WAIT_REQUEST;
- FOREACH_MOD(I_OnHookIO, OnHookIO(this, via));
- if (GetIOHook())
- GetIOHook()->OnStreamSocketAccept(this, client, server);
+ if (via->iohookprov)
+ via->iohookprov->OnAccept(this, client, server);
}
~HttpServerSocket()
@@ -77,7 +74,7 @@ class HttpServerSocket : public BufferedSocket
sockets.erase(this);
}
- virtual void OnError(BufferedSocketError)
+ void OnError(BufferedSocketError) CXX11_OVERRIDE
{
ServerInstance->GlobalCulls.AddItem(this);
}
@@ -188,13 +185,8 @@ class HttpServerSocket : public BufferedSocket
WriteData(http_version + " "+ConvToStr(response)+" "+Response(response)+"\r\n");
- time_t local = ServerInstance->Time();
- struct tm *timeinfo = gmtime(&local);
- char *date = asctime(timeinfo);
- date[strlen(date) - 1] = '\0';
- rheaders.CreateHeader("Date", date);
-
- rheaders.CreateHeader("Server", BRANCH);
+ rheaders.CreateHeader("Date", InspIRCd::TimeString(ServerInstance->Time(), "%a, %d %b %Y %H:%M:%S GMT", true));
+ rheaders.CreateHeader("Server", INSPIRCD_BRANCH);
rheaders.SetHeader("Content-Length", ConvToStr(size));
if (size)
@@ -225,7 +217,7 @@ class HttpServerSocket : public BufferedSocket
if (reqbuffer.length() >= 8192)
{
- ServerInstance->Logs->Log("m_httpd",DEBUG, "m_httpd dropped connection due to an oversized request buffer");
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "m_httpd dropped connection due to an oversized request buffer");
reqbuffer.clear();
SetError("Buffer");
}
@@ -339,36 +331,45 @@ class HttpServerSocket : public BufferedSocket
}
};
+class HTTPdAPIImpl : public HTTPdAPIBase
+{
+ public:
+ HTTPdAPIImpl(Module* parent)
+ : HTTPdAPIBase(parent)
+ {
+ }
+
+ void SendResponse(HTTPDocumentResponse& resp) CXX11_OVERRIDE
+ {
+ claimed = true;
+ resp.src.sock->Page(resp.document, resp.responsecode, &resp.headers);
+ }
+};
+
class ModuleHttpServer : public Module
{
+ std::vector<HttpServerSocket *> httpsocks;
+ HTTPdAPIImpl APIImpl;
unsigned int timeoutsec;
public:
+ ModuleHttpServer()
+ : APIImpl(this)
+ {
+ }
- void init()
+ void init() CXX11_OVERRIDE
{
HttpModule = this;
- Implementation eventlist[] = { I_OnAcceptConnection, I_OnBackgroundTimer, I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- OnRehash(NULL);
}
- void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ConfigTag* tag = ServerInstance->Config->ConfValue("httpd");
timeoutsec = tag->getInt("timeout");
}
- void OnRequest(Request& request)
- {
- if (strcmp(request.id, "HTTP-DOC") != 0)
- return;
- HTTPDocumentResponse& resp = static_cast<HTTPDocumentResponse&>(request);
- claimed = true;
- resp.src.sock->Page(resp.document, resp.responsecode, &resp.headers);
- }
-
- ModResult OnAcceptConnection(int nfd, ListenSocket* from, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server)
+ ModResult OnAcceptConnection(int nfd, ListenSocket* from, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) CXX11_OVERRIDE
{
if (from->bind_tag->getString("type") != "httpd")
return MOD_RES_PASSTHRU;
@@ -379,7 +380,7 @@ class ModuleHttpServer : public Module
return MOD_RES_ALLOW;
}
- void OnBackgroundTimer(time_t curtime)
+ void OnBackgroundTimer(time_t curtime) CXX11_OVERRIDE
{
if (!timeoutsec)
return;
@@ -397,7 +398,7 @@ class ModuleHttpServer : public Module
}
}
- CullResult cull()
+ CullResult cull() CXX11_OVERRIDE
{
std::set<HttpServerSocket*> local;
local.swap(sockets);
@@ -410,7 +411,7 @@ class ModuleHttpServer : public Module
return Module::cull();
}
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides HTTP serving facilities to modules", VF_VENDOR);
}
diff --git a/src/modules/m_httpd_acl.cpp b/src/modules/m_httpd_acl.cpp
index c25cabc0a..58bbbde2a 100644
--- a/src/modules/m_httpd_acl.cpp
+++ b/src/modules/m_httpd_acl.cpp
@@ -19,10 +19,7 @@
#include "inspircd.h"
-#include "httpd.h"
-#include "protocol.h"
-
-/* $ModDesc: Provides access control lists (passwording of resources, ip restrictions etc) to m_httpd.so dependent modules */
+#include "modules/httpd.h"
class HTTPACL
{
@@ -37,19 +34,21 @@ class HTTPACL
const std::string &set_whitelist, const std::string &set_blacklist)
: path(set_path), username(set_username), password(set_password), whitelist(set_whitelist),
blacklist(set_blacklist) { }
-
- ~HTTPACL() { }
};
class ModuleHTTPAccessList : public Module
{
-
std::string stylesheet;
std::vector<HTTPACL> acl_list;
+ HTTPdAPI API;
public:
+ ModuleHTTPAccessList()
+ : API(this)
+ {
+ }
- void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
acl_list.clear();
ConfigTagList acls = ServerInstance->Config->ConfTags("httpdacl");
@@ -86,37 +85,30 @@ class ModuleHTTPAccessList : public Module
}
}
- ServerInstance->Logs->Log("m_httpd_acl", DEBUG, "Read ACL: path=%s pass=%s whitelist=%s blacklist=%s", path.c_str(),
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Read ACL: path=%s pass=%s whitelist=%s blacklist=%s", path.c_str(),
password.c_str(), whitelist.c_str(), blacklist.c_str());
acl_list.push_back(HTTPACL(path, username, password, whitelist, blacklist));
}
}
- void init()
- {
- OnRehash(NULL);
- Implementation eventlist[] = { I_OnEvent, I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
void BlockAccess(HTTPRequest* http, int returnval, const std::string &extraheaderkey = "", const std::string &extraheaderval="")
{
- ServerInstance->Logs->Log("m_httpd_acl", DEBUG, "BlockAccess (%d)", returnval);
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "BlockAccess (%d)", returnval);
std::stringstream data("Access to this resource is denied by an access control list. Please contact your IRC administrator.");
HTTPDocumentResponse response(this, *http, &data, returnval);
- response.headers.SetHeader("X-Powered-By", "m_httpd_acl.so");
+ response.headers.SetHeader("X-Powered-By", MODNAME);
if (!extraheaderkey.empty())
response.headers.SetHeader(extraheaderkey, extraheaderval);
- response.Send();
+ API->SendResponse(response);
}
- void OnEvent(Event& event)
+ void OnEvent(Event& event) CXX11_OVERRIDE
{
if (event.id == "httpd_acl")
{
- ServerInstance->Logs->Log("m_http_stats", DEBUG,"Handling httpd acl event");
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Handling httpd acl event");
HTTPRequest* http = (HTTPRequest*)&event;
for (std::vector<HTTPACL>::const_iterator this_acl = acl_list.begin(); this_acl != acl_list.end(); ++this_acl)
@@ -133,7 +125,7 @@ class ModuleHTTPAccessList : public Module
{
if (InspIRCd::Match(http->GetIP(), entry, ascii_case_insensitive_map))
{
- ServerInstance->Logs->Log("m_httpd_acl", DEBUG, "Denying access to blacklisted resource %s (matched by pattern %s) from ip %s (matched by entry %s)",
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Denying access to blacklisted resource %s (matched by pattern %s) from ip %s (matched by entry %s)",
http->GetURI().c_str(), this_acl->path.c_str(), http->GetIP().c_str(), entry.c_str());
BlockAccess(http, 403);
return;
@@ -155,7 +147,7 @@ class ModuleHTTPAccessList : public Module
if (!allow_access)
{
- ServerInstance->Logs->Log("m_httpd_acl", DEBUG, "Denying access to whitelisted resource %s (matched by pattern %s) from ip %s (Not in whitelist)",
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Denying access to whitelisted resource %s (matched by pattern %s) from ip %s (Not in whitelist)",
http->GetURI().c_str(), this_acl->path.c_str(), http->GetIP().c_str());
BlockAccess(http, 403);
return;
@@ -164,7 +156,7 @@ class ModuleHTTPAccessList : public Module
if (!this_acl->password.empty() && !this_acl->username.empty())
{
/* Password auth, first look to see if we have a basic authentication header */
- ServerInstance->Logs->Log("m_httpd_acl", DEBUG, "Checking HTTP auth password for resource %s (matched by pattern %s) from ip %s, against username %s",
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Checking HTTP auth password for resource %s (matched by pattern %s) from ip %s, against username %s",
http->GetURI().c_str(), this_acl->path.c_str(), http->GetIP().c_str(), this_acl->username.c_str());
if (http->headers->IsSet("Authorization"))
@@ -183,7 +175,7 @@ class ModuleHTTPAccessList : public Module
sep.GetToken(base64);
std::string userpass = Base64ToBin(base64);
- ServerInstance->Logs->Log("m_httpd_acl", DEBUG, "HTTP authorization: %s (%s)", userpass.c_str(), base64.c_str());
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "HTTP authorization: %s (%s)", userpass.c_str(), base64.c_str());
irc::sepstream userpasspair(userpass, ':');
if (userpasspair.GetToken(user))
@@ -193,7 +185,7 @@ class ModuleHTTPAccessList : public Module
/* Access granted if username and password are correct */
if (user == this_acl->username && pass == this_acl->password)
{
- ServerInstance->Logs->Log("m_httpd_acl", DEBUG, "HTTP authorization: password and username match");
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "HTTP authorization: password and username match");
return;
}
else
@@ -222,11 +214,7 @@ class ModuleHTTPAccessList : public Module
}
}
- virtual ~ModuleHTTPAccessList()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides access control lists (passwording of resources, ip restrictions etc) to m_httpd.so dependent modules", VF_VENDOR);
}
diff --git a/src/modules/m_httpd_config.cpp b/src/modules/m_httpd_config.cpp
index 62314cd7e..3c4680799 100644
--- a/src/modules/m_httpd_config.cpp
+++ b/src/modules/m_httpd_config.cpp
@@ -19,18 +19,16 @@
#include "inspircd.h"
-#include "httpd.h"
-#include "protocol.h"
-
-/* $ModDesc: Allows for the server configuration to be viewed over HTTP via m_httpd.so */
+#include "modules/httpd.h"
class ModuleHttpConfig : public Module
{
+ HTTPdAPI API;
+
public:
- void init()
+ ModuleHttpConfig()
+ : API(this)
{
- Implementation eventlist[] = { I_OnEvent };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
}
std::string Sanitize(const std::string &str)
@@ -67,13 +65,13 @@ class ModuleHttpConfig : public Module
return ret;
}
- void OnEvent(Event& event)
+ void OnEvent(Event& event) CXX11_OVERRIDE
{
std::stringstream data("");
if (event.id == "httpd_url")
{
- ServerInstance->Logs->Log("m_http_stats", DEBUG,"Handling httpd event");
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Handling httpd event");
HTTPRequest* http = (HTTPRequest*)&event;
if ((http->GetURI() == "/config") || (http->GetURI() == "/config/"))
@@ -95,18 +93,14 @@ class ModuleHttpConfig : public Module
data << "</body></html>";
/* Send the document back to m_httpd */
HTTPDocumentResponse response(this, *http, &data, 200);
- response.headers.SetHeader("X-Powered-By", "m_httpd_config.so");
+ response.headers.SetHeader("X-Powered-By", MODNAME);
response.headers.SetHeader("Content-Type", "text/html");
- response.Send();
+ API->SendResponse(response);
}
}
}
- virtual ~ModuleHttpConfig()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Allows for the server configuration to be viewed over HTTP via m_httpd.so", VF_VENDOR);
}
diff --git a/src/modules/m_httpd_stats.cpp b/src/modules/m_httpd_stats.cpp
index 2fc7ca7de..84cca7e01 100644
--- a/src/modules/m_httpd_stats.cpp
+++ b/src/modules/m_httpd_stats.cpp
@@ -22,22 +22,18 @@
#include "inspircd.h"
-#include "httpd.h"
+#include "modules/httpd.h"
#include "xline.h"
-#include "protocol.h"
-
-/* $ModDesc: Provides statistics over HTTP via m_httpd.so */
class ModuleHttpStats : public Module
{
static std::map<char, char const*> const &entities;
+ HTTPdAPI API;
public:
-
- void init()
+ ModuleHttpStats()
+ : API(this)
{
- Implementation eventlist[] = { I_OnEvent };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
}
std::string Sanitize(const std::string &str)
@@ -91,13 +87,13 @@ class ModuleHttpStats : public Module
data << "</metadata>";
}
- void OnEvent(Event& event)
+ void OnEvent(Event& event) CXX11_OVERRIDE
{
std::stringstream data("");
if (event.id == "httpd_url")
{
- ServerInstance->Logs->Log("m_http_stats", DEBUG,"Handling httpd event");
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Handling httpd event");
HTTPRequest* http = (HTTPRequest*)&event;
if ((http->GetURI() == "/stats") || (http->GetURI() == "/stats/"))
@@ -107,10 +103,10 @@ class ModuleHttpStats : public Module
<< Sanitize(ServerInstance->GetVersionString()) << "</version></server>";
data << "<general>";
- data << "<usercount>" << ServerInstance->Users->clientlist->size() << "</usercount>";
- data << "<channelcount>" << ServerInstance->chanlist->size() << "</channelcount>";
+ data << "<usercount>" << ServerInstance->Users->GetUsers().size() << "</usercount>";
+ data << "<channelcount>" << ServerInstance->GetChans().size() << "</channelcount>";
data << "<opercount>" << ServerInstance->Users->all_opers.size() << "</opercount>";
- data << "<socketcount>" << (ServerInstance->SE->GetUsedFds()) << "</socketcount><socketmax>" << ServerInstance->SE->GetMaxFds() << "</socketmax><socketengine>" << ServerInstance->SE->GetName() << "</socketengine>";
+ data << "<socketcount>" << (SocketEngine::GetUsedFds()) << "</socketcount><socketmax>" << SocketEngine::GetMaxFds() << "</socketmax><socketengine>" INSPIRCD_SOCKETENGINE_NAME "</socketengine>";
time_t current_time = 0;
current_time = ServerInstance->Time();
@@ -119,7 +115,13 @@ class ModuleHttpStats : public Module
stime = gmtime(&server_uptime);
data << "<uptime><days>" << stime->tm_yday << "</days><hours>" << stime->tm_hour << "</hours><mins>" << stime->tm_min << "</mins><secs>" << stime->tm_sec << "</secs><boot_time_t>" << ServerInstance->startup_time << "</boot_time_t></uptime>";
- data << "<isupport>" << Sanitize(ServerInstance->Config->data005) << "</isupport></general><xlines>";
+ data << "<isupport>";
+ const std::vector<std::string>& isupport = ServerInstance->ISupport.GetLines();
+ for (std::vector<std::string>::const_iterator it = isupport.begin(); it != isupport.end(); it++)
+ {
+ data << Sanitize(*it) << std::endl;
+ }
+ data << "</isupport></general><xlines>";
std::vector<std::string> xltypes = ServerInstance->XLines->GetAllTypes();
for (std::vector<std::string>::iterator it = xltypes.begin(); it != xltypes.end(); ++it)
{
@@ -138,35 +140,35 @@ class ModuleHttpStats : public Module
}
data << "</xlines><modulelist>";
- std::vector<std::string> module_names = ServerInstance->Modules->GetAllModuleNames(0);
+ const ModuleManager::ModuleMap& mods = ServerInstance->Modules->GetModules();
- for (std::vector<std::string>::iterator i = module_names.begin(); i != module_names.end(); ++i)
+ for (ModuleManager::ModuleMap::const_iterator i = mods.begin(); i != mods.end(); ++i)
{
- Module* m = ServerInstance->Modules->Find(i->c_str());
- Version v = m->GetVersion();
- data << "<module><name>" << *i << "</name><description>" << Sanitize(v.description) << "</description></module>";
+ Version v = i->second->GetVersion();
+ data << "<module><name>" << i->first << "</name><description>" << Sanitize(v.description) << "</description></module>";
}
data << "</modulelist><channellist>";
- for (chan_hash::const_iterator a = ServerInstance->chanlist->begin(); a != ServerInstance->chanlist->end(); ++a)
+ const chan_hash& chans = ServerInstance->GetChans();
+ for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); ++i)
{
- Channel* c = a->second;
+ Channel* c = i->second;
data << "<channel>";
- data << "<usercount>" << c->GetUsers()->size() << "</usercount><channelname>" << Sanitize(c->name) << "</channelname>";
+ data << "<usercount>" << c->GetUsers().size() << "</usercount><channelname>" << Sanitize(c->name) << "</channelname>";
data << "<channeltopic>";
data << "<topictext>" << Sanitize(c->topic) << "</topictext>";
data << "<setby>" << Sanitize(c->setby) << "</setby>";
data << "<settime>" << c->topicset << "</settime>";
data << "</channeltopic>";
data << "<channelmodes>" << Sanitize(c->ChanModes(true)) << "</channelmodes>";
- const UserMembList* ulist = c->GetUsers();
- for (UserMembCIter x = ulist->begin(); x != ulist->end(); ++x)
+ const Channel::MemberMap& ulist = c->GetUsers();
+ for (Channel::MemberMap::const_iterator x = ulist.begin(); x != ulist.end(); ++x)
{
Membership* memb = x->second;
data << "<channelmember><uid>" << memb->user->uuid << "</uid><privs>"
- << Sanitize(c->GetAllPrefixChars(x->first)) << "</privs><modes>"
+ << Sanitize(memb->GetAllPrefixChars()) << "</privs><modes>"
<< memb->modes << "</modes>";
DumpMeta(data, memb);
data << "</channelmember>";
@@ -179,23 +181,24 @@ class ModuleHttpStats : public Module
data << "</channellist><userlist>";
- for (user_hash::const_iterator a = ServerInstance->Users->clientlist->begin(); a != ServerInstance->Users->clientlist->end(); ++a)
+ const user_hash& users = ServerInstance->Users->GetUsers();
+ for (user_hash::const_iterator i = users.begin(); i != users.end(); ++i)
{
- User* u = a->second;
+ User* u = i->second;
data << "<user>";
data << "<nickname>" << u->nick << "</nickname><uuid>" << u->uuid << "</uuid><realhost>"
<< u->host << "</realhost><displayhost>" << u->dhost << "</displayhost><gecos>"
<< Sanitize(u->fullname) << "</gecos><server>" << u->server << "</server>";
- if (IS_AWAY(u))
+ if (u->IsAway())
data << "<away>" << Sanitize(u->awaymsg) << "</away><awaytime>" << u->awaytime << "</awaytime>";
- if (IS_OPER(u))
- data << "<opertype>" << Sanitize(u->oper->NameStr()) << "</opertype>";
+ if (u->IsOper())
+ data << "<opertype>" << Sanitize(u->oper->name) << "</opertype>";
data << "<modes>" << u->FormatModes() << "</modes><ident>" << Sanitize(u->ident) << "</ident>";
LocalUser* lu = IS_LOCAL(u);
if (lu)
data << "<port>" << lu->GetServerPort() << "</port><servaddr>"
- << irc::sockets::satouser(lu->server_sa) << "</servaddr>";
+ << lu->server_sa.str() << "</servaddr>";
data << "<ipaddress>" << u->GetIPString() << "</ipaddress>";
DumpMeta(data, u);
@@ -205,10 +208,10 @@ class ModuleHttpStats : public Module
data << "</userlist><serverlist>";
- ProtoServerList sl;
+ ProtocolInterface::ServerList sl;
ServerInstance->PI->GetServerList(sl);
- for (ProtoServerList::iterator b = sl.begin(); b != sl.end(); ++b)
+ for (ProtocolInterface::ServerList::const_iterator b = sl.begin(); b != sl.end(); ++b)
{
data << "<server>";
data << "<servername>" << b->servername << "</servername>";
@@ -225,18 +228,14 @@ class ModuleHttpStats : public Module
/* Send the document back to m_httpd */
HTTPDocumentResponse response(this, *http, &data, 200);
- response.headers.SetHeader("X-Powered-By", "m_httpd_stats.so");
+ response.headers.SetHeader("X-Powered-By", MODNAME);
response.headers.SetHeader("Content-Type", "text/xml");
- response.Send();
+ API->SendResponse(response);
}
}
}
- virtual ~ModuleHttpStats()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides statistics over HTTP via m_httpd.so", VF_VENDOR);
}
diff --git a/src/modules/m_ident.cpp b/src/modules/m_ident.cpp
index f0ced1db7..3e87b8c5a 100644
--- a/src/modules/m_ident.cpp
+++ b/src/modules/m_ident.cpp
@@ -24,8 +24,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides support for RFC1413 ident lookups */
-
/* --------------------------------------------------------------
* Note that this is the third incarnation of m_ident. The first
* two attempts were pretty crashy, mainly due to the fact we tried
@@ -119,33 +117,33 @@ class IdentRequestSocket : public EventHandler
}
/* Attempt to bind (ident requests must come from the ip the query is referring to */
- if (ServerInstance->SE->Bind(GetFd(), bindaddr) < 0)
+ if (SocketEngine::Bind(GetFd(), bindaddr) < 0)
{
this->Close();
throw ModuleException("failed to bind()");
}
- ServerInstance->SE->NonBlocking(GetFd());
+ SocketEngine::NonBlocking(GetFd());
/* Attempt connection (nonblocking) */
- if (ServerInstance->SE->Connect(this, &connaddr.sa, connaddr.sa_size()) == -1 && errno != EINPROGRESS)
+ if (SocketEngine::Connect(this, &connaddr.sa, connaddr.sa_size()) == -1 && errno != EINPROGRESS)
{
this->Close();
throw ModuleException("connect() failed");
}
/* Add fd to socket engine */
- if (!ServerInstance->SE->AddFd(this, FD_WANT_NO_READ | FD_WANT_POLL_WRITE))
+ if (!SocketEngine::AddFd(this, FD_WANT_NO_READ | FD_WANT_POLL_WRITE))
{
this->Close();
throw ModuleException("out of fds");
}
}
- virtual void OnConnected()
+ void OnConnected()
{
- ServerInstance->Logs->Log("m_ident",DEBUG,"OnConnected()");
- ServerInstance->SE->ChangeEventMask(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "OnConnected()");
+ SocketEngine::ChangeEventMask(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
char req[32];
@@ -161,11 +159,11 @@ class IdentRequestSocket : public EventHandler
/* Send failed if we didnt write the whole ident request --
* might as well give up if this happens!
*/
- if (ServerInstance->SE->Send(this, req, req_size, 0) < req_size)
+ if (SocketEngine::Send(this, req, req_size, 0) < req_size)
done = true;
}
- virtual void HandleEvent(EventType et, int errornum = 0)
+ void HandleEvent(EventType et, int errornum = 0)
{
switch (et)
{
@@ -179,7 +177,7 @@ class IdentRequestSocket : public EventHandler
break;
case EVENT_ERROR:
/* fd error event, ohshi- */
- ServerInstance->Logs->Log("m_ident",DEBUG,"EVENT_ERROR");
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "EVENT_ERROR");
/* We *must* Close() here immediately or we get a
* huge storm of EVENT_ERROR events!
*/
@@ -196,10 +194,8 @@ class IdentRequestSocket : public EventHandler
*/
if (GetFd() > -1)
{
- ServerInstance->Logs->Log("m_ident",DEBUG,"Close ident socket %d", GetFd());
- ServerInstance->SE->DelFd(this);
- ServerInstance->SE->Close(GetFd());
- this->SetFd(-1);
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Close ident socket %d", GetFd());
+ SocketEngine::Close(this);
}
}
@@ -213,8 +209,8 @@ class IdentRequestSocket : public EventHandler
/* We don't really need to buffer for incomplete replies here, since IDENT replies are
* extremely short - there is *no* sane reason it'd be in more than one packet
*/
- char ibuf[MAXBUF];
- int recvresult = ServerInstance->SE->Recv(this, ibuf, MAXBUF-1, 0);
+ char ibuf[256];
+ int recvresult = SocketEngine::Recv(this, ibuf, sizeof(ibuf)-1, 0);
/* Close (but don't delete from memory) our socket
* and flag as done since the ident lookup has finished
@@ -228,7 +224,7 @@ class IdentRequestSocket : public EventHandler
if (recvresult < 3)
return;
- ServerInstance->Logs->Log("m_ident",DEBUG,"ReadResponse()");
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "ReadResponse()");
/* Truncate at the first null character, but first make sure
* there is at least one null char (at the end of the buffer).
@@ -260,67 +256,59 @@ class IdentRequestSocket : public EventHandler
* we're done.
*/
result += *i;
- if (!ServerInstance->IsIdent(result.c_str()))
+ if (!ServerInstance->IsIdent(result))
{
result.erase(result.end()-1);
break;
}
}
}
+
+ CullResult cull() CXX11_OVERRIDE
+ {
+ Close();
+ return EventHandler::cull();
+ }
};
class ModuleIdent : public Module
{
int RequestTimeout;
- SimpleExtItem<IdentRequestSocket> ext;
+ bool NoLookupPrefix;
+ SimpleExtItem<IdentRequestSocket, stdalgo::culldeleter> ext;
public:
ModuleIdent() : ext("ident_socket", this)
{
}
- void init()
- {
- ServerInstance->Modules->AddService(ext);
- OnRehash(NULL);
- Implementation eventlist[] = {
- I_OnRehash, I_OnUserInit, I_OnCheckReady,
- I_OnUserDisconnect, I_OnSetConnectClass
- };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- ~ModuleIdent()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for RFC1413 ident lookups", VF_VENDOR);
}
- virtual void OnRehash(User *user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
- RequestTimeout = ServerInstance->Config->ConfValue("ident")->getInt("timeout", 5);
- if (!RequestTimeout)
- RequestTimeout = 5;
+ ConfigTag* tag = ServerInstance->Config->ConfValue("ident");
+ RequestTimeout = tag->getInt("timeout", 5, 1);
+ NoLookupPrefix = tag->getBool("nolookupprefix", false);
}
- void OnUserInit(LocalUser *user)
+ void OnUserInit(LocalUser *user) CXX11_OVERRIDE
{
ConfigTag* tag = user->MyClass->config;
if (!tag->getBool("useident", true))
return;
- user->WriteServ("NOTICE Auth :*** Looking up your ident...");
+ user->WriteNotice("*** Looking up your ident...");
try
{
- IdentRequestSocket *isock = new IdentRequestSocket(IS_LOCAL(user));
+ IdentRequestSocket *isock = new IdentRequestSocket(user);
ext.set(user, isock);
}
catch (ModuleException &e)
{
- ServerInstance->Logs->Log("m_ident",DEBUG,"Ident exception: %s", e.GetReason());
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Ident exception: " + e.GetReason());
}
}
@@ -328,18 +316,17 @@ class ModuleIdent : public Module
* creating a Timer object and especially better than creating a
* Timer per ident lookup!
*/
- virtual ModResult OnCheckReady(LocalUser *user)
+ ModResult OnCheckReady(LocalUser *user) CXX11_OVERRIDE
{
/* Does user have an ident socket attached at all? */
IdentRequestSocket *isock = ext.get(user);
if (!isock)
{
- ServerInstance->Logs->Log("m_ident",DEBUG, "No ident socket :(");
+ if ((NoLookupPrefix) && (user->ident[0] != '~'))
+ user->ident.insert(user->ident.begin(), 1, '~');
return MOD_RES_PASSTHRU;
}
- ServerInstance->Logs->Log("m_ident",DEBUG, "Has ident_socket");
-
time_t compare = isock->age;
compare += RequestTimeout;
@@ -347,28 +334,24 @@ class ModuleIdent : public Module
if (ServerInstance->Time() >= compare)
{
/* Ident timeout */
- user->WriteServ("NOTICE Auth :*** Ident request timed out.");
- ServerInstance->Logs->Log("m_ident",DEBUG, "Timeout");
+ user->WriteNotice("*** Ident request timed out.");
}
else if (!isock->HasResult())
{
// time still good, no result yet... hold the registration
- ServerInstance->Logs->Log("m_ident",DEBUG, "No result yet");
return MOD_RES_DENY;
}
- ServerInstance->Logs->Log("m_ident",DEBUG, "Yay, result!");
-
/* wooo, got a result (it will be good, or bad) */
if (isock->result.empty())
{
user->ident.insert(user->ident.begin(), 1, '~');
- user->WriteServ("NOTICE Auth :*** Could not find your ident, using %s instead.", user->ident.c_str());
+ user->WriteNotice("*** Could not find your ident, using " + user->ident + " instead.");
}
else
{
user->ident = isock->result;
- user->WriteServ("NOTICE Auth :*** Found your ident, '%s'", user->ident.c_str());
+ user->WriteNotice("*** Found your ident, '" + user->ident + "'");
}
user->InvalidateCache();
@@ -377,35 +360,12 @@ class ModuleIdent : public Module
return MOD_RES_PASSTHRU;
}
- ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass)
+ ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass) CXX11_OVERRIDE
{
if (myclass->config->getBool("requireident") && user->ident[0] == '~')
return MOD_RES_DENY;
return MOD_RES_PASSTHRU;
}
-
- virtual void OnCleanup(int target_type, void *item)
- {
- /* Module unloading, tidy up users */
- if (target_type == TYPE_USER)
- {
- LocalUser* user = IS_LOCAL((User*) item);
- if (user)
- OnUserDisconnect(user);
- }
- }
-
- virtual void OnUserDisconnect(LocalUser *user)
- {
- /* User disconnect (generic socket detatch event) */
- IdentRequestSocket *isock = ext.get(user);
- if (isock)
- {
- isock->Close();
- ext.unset(user);
- }
- }
};
MODULE_INIT(ModuleIdent)
-
diff --git a/src/modules/m_inviteexception.cpp b/src/modules/m_inviteexception.cpp
index 747a3b30a..6229e1fa2 100644
--- a/src/modules/m_inviteexception.cpp
+++ b/src/modules/m_inviteexception.cpp
@@ -22,10 +22,7 @@
#include "inspircd.h"
-#include "u_listmode.h"
-
-/* $ModDesc: Provides support for the +I channel mode */
-/* $ModDep: ../../include/u_listmode.h */
+#include "listmode.h"
/*
* Written by Om <om@inspircd.org>, April 2005.
@@ -54,27 +51,17 @@ public:
{
}
- void init()
- {
- ServerInstance->Modules->AddService(ie);
-
- OnRehash(NULL);
- ie.DoImplements(this);
- Implementation eventlist[] = { I_On005Numeric, I_OnCheckInvite, I_OnCheckKey, I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- void On005Numeric(std::string &output)
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
- output.append(" INVEX=I");
+ tokens["INVEX"] = "I";
}
- ModResult OnCheckInvite(User* user, Channel* chan)
+ ModResult OnCheckInvite(User* user, Channel* chan) CXX11_OVERRIDE
{
- modelist* list = ie.extItem.get(chan);
+ ListModeBase::ModeList* list = ie.GetList(chan);
if (list)
{
- for (modelist::iterator it = list->begin(); it != list->end(); it++)
+ for (ListModeBase::ModeList::iterator it = list->begin(); it != list->end(); it++)
{
if (chan->CheckBan(user, it->mask))
{
@@ -86,25 +73,20 @@ public:
return MOD_RES_PASSTHRU;
}
- ModResult OnCheckKey(User* user, Channel* chan, const std::string& key)
+ ModResult OnCheckKey(User* user, Channel* chan, const std::string& key) CXX11_OVERRIDE
{
if (invite_bypass_key)
return OnCheckInvite(user, chan);
return MOD_RES_PASSTHRU;
}
- void OnSyncChannel(Channel* chan, Module* proto, void* opaque)
- {
- ie.DoSyncChannel(chan, proto, opaque);
- }
-
- void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
invite_bypass_key = ServerInstance->Config->ConfValue("inviteexception")->getBool("bypasskey", true);
ie.DoRehash();
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for the +I channel mode", VF_VENDOR);
}
diff --git a/src/modules/m_ircv3.cpp b/src/modules/m_ircv3.cpp
index da42d823d..4eb54d2a6 100644
--- a/src/modules/m_ircv3.cpp
+++ b/src/modules/m_ircv3.cpp
@@ -16,11 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/* $ModDesc: Provides support for extended-join, away-notify and account-notify CAP capabilities */
-
#include "inspircd.h"
-#include "account.h"
-#include "m_cap.h"
+#include "modules/account.h"
+#include "modules/cap.h"
class ModuleIRCv3 : public Module
{
@@ -35,10 +33,10 @@ class ModuleIRCv3 : public Module
void WriteNeighboursWithExt(User* user, const std::string& line, const LocalIntExt& ext)
{
- UserChanList chans(user->chans);
+ IncludeChanList chans(user->chans.begin(), user->chans.end());
std::map<User*, bool> exceptions;
- FOREACH_MOD(I_OnBuildNeighborList, OnBuildNeighborList(user, chans, exceptions));
+ FOREACH_MOD(OnBuildNeighborList, (user, chans, exceptions));
// Send it to all local users who were explicitly marked as neighbours by modules and have the required ext
for (std::map<User*, bool>::const_iterator i = exceptions.begin(); i != exceptions.end(); ++i)
@@ -50,10 +48,10 @@ class ModuleIRCv3 : public Module
// Now consider sending it to all other users who has at least a common channel with the user
std::set<User*> already_sent;
- for (UCListIter i = chans.begin(); i != chans.end(); ++i)
+ for (IncludeChanList::const_iterator i = chans.begin(); i != chans.end(); ++i)
{
- const UserMembList* userlist = (*i)->GetUsers();
- for (UserMembList::const_iterator m = userlist->begin(); m != userlist->end(); ++m)
+ const Channel::MemberMap& userlist = (*i)->chan->GetUsers();
+ for (Channel::MemberMap::const_iterator m = userlist.begin(); m != userlist.end(); ++m)
{
/*
* Send the line if the channel member in question meets all of the following criteria:
@@ -78,22 +76,15 @@ class ModuleIRCv3 : public Module
{
}
- void init()
- {
- OnRehash(NULL);
- Implementation eventlist[] = { I_OnUserJoin, I_OnPostJoin, I_OnSetAway, I_OnEvent, I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ConfigTag* conf = ServerInstance->Config->ConfValue("ircv3");
- accountnotify = conf->getBool("accountnotify", conf->getBool("accoutnotify", true));
+ accountnotify = conf->getBool("accountnotify", true);
awaynotify = conf->getBool("awaynotify", true);
extendedjoin = conf->getBool("extendedjoin", true);
}
- void OnEvent(Event& ev)
+ void OnEvent(Event& ev) CXX11_OVERRIDE
{
if (awaynotify)
cap_awaynotify.HandleEvent(ev);
@@ -122,10 +113,10 @@ class ModuleIRCv3 : public Module
}
}
- void OnUserJoin(Membership* memb, bool sync, bool created, CUList& excepts)
+ void OnUserJoin(Membership* memb, bool sync, bool created, CUList& excepts) CXX11_OVERRIDE
{
// Remember who is not going to see the JOIN because of other modules
- if ((awaynotify) && (IS_AWAY(memb->user)))
+ if ((awaynotify) && (memb->user->IsAway()))
last_excepts = excepts;
if (!extendedjoin)
@@ -143,8 +134,8 @@ class ModuleIRCv3 : public Module
std::string line;
std::string mode;
- const UserMembList* userlist = memb->chan->GetUsers();
- for (UserMembCIter it = userlist->begin(); it != userlist->end(); ++it)
+ const Channel::MemberMap& userlist = memb->chan->GetUsers();
+ for (Channel::MemberMap::const_iterator it = userlist.begin(); it != userlist.end(); ++it)
{
// Send the extended join line if the current member is local, has the extended-join cap and isn't excepted
User* member = IS_LOCAL(it->first);
@@ -195,7 +186,7 @@ class ModuleIRCv3 : public Module
}
}
- ModResult OnSetAway(User* user, const std::string &awaymsg)
+ ModResult OnSetAway(User* user, const std::string &awaymsg) CXX11_OVERRIDE
{
if (awaynotify)
{
@@ -210,15 +201,15 @@ class ModuleIRCv3 : public Module
return MOD_RES_PASSTHRU;
}
- void OnPostJoin(Membership *memb)
+ void OnPostJoin(Membership *memb) CXX11_OVERRIDE
{
- if ((!awaynotify) || (!IS_AWAY(memb->user)))
+ if ((!awaynotify) || (!memb->user->IsAway()))
return;
std::string line = ":" + memb->user->GetFullHost() + " AWAY :" + memb->user->awaymsg;
- const UserMembList* userlist = memb->chan->GetUsers();
- for (UserMembCIter it = userlist->begin(); it != userlist->end(); ++it)
+ const Channel::MemberMap& userlist = memb->chan->GetUsers();
+ for (Channel::MemberMap::const_iterator it = userlist.begin(); it != userlist.end(); ++it)
{
// Send the away notify line if the current member is local, has the away-notify cap and isn't excepted
User* member = IS_LOCAL(it->first);
@@ -236,7 +227,7 @@ class ModuleIRCv3 : public Module
ServerInstance->Modules->SetPriority(this, I_OnUserJoin, PRIORITY_LAST);
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for extended-join, away-notify and account-notify CAP capabilities", VF_VENDOR);
}
diff --git a/src/modules/m_joinflood.cpp b/src/modules/m_joinflood.cpp
index 63bcc38a4..52802f168 100644
--- a/src/modules/m_joinflood.cpp
+++ b/src/modules/m_joinflood.cpp
@@ -23,35 +23,32 @@
#include "inspircd.h"
-/* $ModDesc: Provides channel mode +j (join flood protection) */
-
/** Holds settings and state associated with channel mode +j
*/
class joinfloodsettings
{
public:
- int secs;
- int joins;
+ unsigned int secs;
+ unsigned int joins;
time_t reset;
time_t unlocktime;
- int counter;
- bool locked;
+ unsigned int counter;
- joinfloodsettings(int b, int c) : secs(b), joins(c)
+ joinfloodsettings(unsigned int b, unsigned int c)
+ : secs(b), joins(c), unlocktime(0), counter(0)
{
reset = ServerInstance->Time() + secs;
- counter = 0;
- locked = false;
- };
+ }
void addjoin()
{
- counter++;
if (ServerInstance->Time() > reset)
{
- counter = 0;
+ counter = 1;
reset = ServerInstance->Time() + secs;
}
+ else
+ counter++;
}
bool shouldlock()
@@ -66,155 +63,87 @@ class joinfloodsettings
bool islocked()
{
- if (locked)
- {
- if (ServerInstance->Time() > unlocktime)
- {
- locked = false;
- return false;
- }
- else
- {
- return true;
- }
- }
- return false;
+ if (ServerInstance->Time() > unlocktime)
+ unlocktime = 0;
+
+ return (unlocktime != 0);
}
void lock()
{
- locked = true;
unlocktime = ServerInstance->Time() + 60;
}
+ bool operator==(const joinfloodsettings& other) const
+ {
+ return ((this->secs == other.secs) && (this->joins == other.joins));
+ }
};
/** Handles channel mode +j
*/
-class JoinFlood : public ModeHandler
+class JoinFlood : public ParamMode<JoinFlood, SimpleExtItem<joinfloodsettings> >
{
public:
- SimpleExtItem<joinfloodsettings> ext;
- JoinFlood(Module* Creator) : ModeHandler(Creator, "joinflood", 'j', PARAM_SETONLY, MODETYPE_CHANNEL),
- ext("joinflood", Creator) { }
+ JoinFlood(Module* Creator)
+ : ParamMode<JoinFlood, SimpleExtItem<joinfloodsettings> >(Creator, "joinflood", 'j')
+ {
+ }
- ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
+ ModeAction OnSet(User* source, Channel* channel, std::string& parameter)
{
- if (adding)
+ std::string::size_type colon = parameter.find(':');
+ if ((colon == std::string::npos) || (parameter.find('-') != std::string::npos))
{
- char ndata[MAXBUF];
- char* data = ndata;
- strlcpy(ndata,parameter.c_str(),MAXBUF);
- char* joins = data;
- char* secs = NULL;
- while (*data)
- {
- if (*data == ':')
- {
- *data = 0;
- data++;
- secs = data;
- break;
- }
- else data++;
- }
- if (secs)
-
- {
- /* Set up the flood parameters for this channel */
- int njoins = atoi(joins);
- int nsecs = atoi(secs);
- if ((njoins<1) || (nsecs<1))
- {
- source->WriteNumeric(608, "%s %s :Invalid flood parameter",source->nick.c_str(),channel->name.c_str());
- parameter.clear();
- return MODEACTION_DENY;
- }
- else
- {
- joinfloodsettings* f = ext.get(channel);
- if (!f)
- {
- parameter = ConvToStr(njoins) + ":" +ConvToStr(nsecs);
- f = new joinfloodsettings(nsecs, njoins);
- ext.set(channel, f);
- channel->SetModeParam('j', parameter);
- return MODEACTION_ALLOW;
- }
- else
- {
- std::string cur_param = channel->GetModeParameter('j');
- parameter = ConvToStr(njoins) + ":" +ConvToStr(nsecs);
- if (cur_param == parameter)
- {
- // mode params match
- return MODEACTION_DENY;
- }
- else
- {
- // new mode param, replace old with new
- f = new joinfloodsettings(nsecs, njoins);
- ext.set(channel, f);
- channel->SetModeParam('j', parameter);
- return MODEACTION_ALLOW;
- }
- }
- }
- }
- else
- {
- source->WriteNumeric(608, "%s %s :Invalid flood parameter",source->nick.c_str(),channel->name.c_str());
- return MODEACTION_DENY;
- }
+ source->WriteNumeric(608, "%s :Invalid flood parameter",channel->name.c_str());
+ return MODEACTION_DENY;
}
- else
+
+ /* Set up the flood parameters for this channel */
+ unsigned int njoins = ConvToInt(parameter.substr(0, colon));
+ unsigned int nsecs = ConvToInt(parameter.substr(colon+1));
+ if ((njoins<1) || (nsecs<1))
{
- if (channel->IsModeSet('j'))
- {
- ext.unset(channel);
- channel->SetModeParam('j', "");
- return MODEACTION_ALLOW;
- }
+ source->WriteNumeric(608, "%s :Invalid flood parameter",channel->name.c_str());
+ return MODEACTION_DENY;
}
- return MODEACTION_DENY;
+
+ ext.set(channel, new joinfloodsettings(nsecs, njoins));
+ return MODEACTION_ALLOW;
+ }
+
+ void SerializeParam(Channel* chan, const joinfloodsettings* jfs, std::string& out)
+ {
+ out.append(ConvToStr(jfs->joins)).push_back(':');
+ out.append(ConvToStr(jfs->secs));
}
};
class ModuleJoinFlood : public Module
{
-
JoinFlood jf;
public:
-
ModuleJoinFlood()
: jf(this)
{
}
- void init()
- {
- ServerInstance->Modules->AddService(jf);
- ServerInstance->Modules->AddService(jf.ext);
- Implementation eventlist[] = { I_OnUserPreJoin, I_OnUserJoin };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven)
+ ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE
{
if (chan)
{
joinfloodsettings *f = jf.ext.get(chan);
if (f && f->islocked())
{
- user->WriteNumeric(609, "%s %s :This channel is temporarily unavailable (+j). Please try again later.",user->nick.c_str(),chan->name.c_str());
+ user->WriteNumeric(609, "%s :This channel is temporarily unavailable (+j). Please try again later.",chan->name.c_str());
return MOD_RES_DENY;
}
}
return MOD_RES_PASSTHRU;
}
- void OnUserJoin(Membership* memb, bool sync, bool created, CUList& excepts)
+ void OnUserJoin(Membership* memb, bool sync, bool created, CUList& excepts) CXX11_OVERRIDE
{
/* We arent interested in JOIN events caused by a network burst */
if (sync)
@@ -235,11 +164,7 @@ class ModuleJoinFlood : public Module
}
}
- ~ModuleJoinFlood()
- {
- }
-
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides channel mode +j (join flood protection)", VF_VENDOR);
}
diff --git a/src/modules/m_jumpserver.cpp b/src/modules/m_jumpserver.cpp
index dce8f0bd5..599144448 100644
--- a/src/modules/m_jumpserver.cpp
+++ b/src/modules/m_jumpserver.cpp
@@ -20,8 +20,7 @@
#include "inspircd.h"
-
-/* $ModDesc: Provides support for the RPL_REDIR numeric and the /JUMPSERVER command. */
+#include "modules/ssl.h"
/** Handle /JUMPSERVER
*/
@@ -32,11 +31,14 @@ class CommandJumpserver : public Command
std::string redirect_to;
std::string reason;
int port;
+ int sslport;
CommandJumpserver(Module* Creator) : Command(Creator, "JUMPSERVER", 0, 4)
{
- flags_needed = 'o'; syntax = "[<server> <port> <+/-an> <reason>]";
+ flags_needed = 'o';
+ syntax = "[<server> <port>[:<sslport>] <+/-an> <reason>]";
port = 0;
+ sslport = 0;
redirect_new_users = false;
}
@@ -53,11 +55,12 @@ class CommandJumpserver : public Command
if (!parameters.size())
{
if (port)
- user->WriteServ("NOTICE %s :*** Disabled jumpserver (previously set to '%s:%d')", user->nick.c_str(), redirect_to.c_str(), port);
+ user->WriteNotice("*** Disabled jumpserver (previously set to '" + redirect_to + ":" + ConvToStr(port) + "')");
else
- user->WriteServ("NOTICE %s :*** Jumpserver was not enabled.", user->nick.c_str());
+ user->WriteNotice("*** Jumpserver was not enabled.");
port = 0;
+ sslport = 0;
redirect_to.clear();
return CMD_SUCCESS;
}
@@ -84,27 +87,34 @@ class CommandJumpserver : public Command
redirect_new_users = direction;
break;
default:
- user->WriteServ("NOTICE %s :*** Invalid JUMPSERVER flag: %c", user->nick.c_str(), *n);
+ user->WriteNotice("*** Invalid JUMPSERVER flag: " + ConvToStr(*n));
return CMD_FAILURE;
break;
}
}
- if (!atoi(parameters[1].c_str()))
+ size_t delimpos = parameters[1].find(':');
+ port = ConvToInt(parameters[1].substr(0, delimpos ? delimpos : std::string::npos));
+ sslport = (delimpos == std::string::npos ? 0 : ConvToInt(parameters[1].substr(delimpos + 1)));
+
+ if (parameters[1].find_first_not_of("0123456789:") != std::string::npos
+ || parameters[1].rfind(':') != delimpos
+ || port > 65535 || sslport > 65535)
{
- user->WriteServ("NOTICE %s :*** Invalid port number", user->nick.c_str());
+ user->WriteNotice("*** Invalid port number");
return CMD_FAILURE;
}
if (redirect_all_immediately)
{
/* Redirect everyone but the oper sending the command */
- for (LocalUserList::const_iterator i = ServerInstance->Users->local_users.begin(); i != ServerInstance->Users->local_users.end(); ++i)
+ const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers();
+ for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i)
{
- User* t = *i;
- if (!IS_OPER(t))
+ LocalUser* t = *i;
+ if (!t->IsOper())
{
- t->WriteNumeric(10, "%s %s %s :Please use this Server/Port instead", t->nick.c_str(), parameters[0].c_str(), parameters[1].c_str());
+ t->WriteNumeric(RPL_REDIR, "%s %d :Please use this Server/Port instead", parameters[0].c_str(), GetPort(t));
ServerInstance->Users->QuitUser(t, reason);
n_done++;
}
@@ -116,24 +126,24 @@ class CommandJumpserver : public Command
}
if (redirect_new_users)
- {
redirect_to = parameters[0];
- port = atoi(parameters[1].c_str());
- }
- user->WriteServ("NOTICE %s :*** Set jumpserver to server '%s' port '%s', flags '+%s%s'%s%s%s: %s", user->nick.c_str(), parameters[0].c_str(), parameters[1].c_str(),
- redirect_all_immediately ? "a" : "",
- redirect_new_users ? "n" : "",
- n_done ? " (" : "",
- n_done ? n_done_s.c_str() : "",
- n_done ? " user(s) redirected)" : "",
- reason.c_str());
+ user->WriteNotice("*** Set jumpserver to server '" + parameters[0] + "' port '" + (port ? ConvToStr(port) : "Auto") + ", SSL " + (sslport ? ConvToStr(sslport) : "Auto") + "', flags '+" +
+ (redirect_all_immediately ? "a" : "") + (redirect_new_users ? "n'" : "'") +
+ (n_done ? " (" + n_done_s + "user(s) redirected): " : ": ") + reason);
}
return CMD_SUCCESS;
}
-};
+ int GetPort(LocalUser* user)
+ {
+ int p = (SSLClientCert::GetCertificate(&user->eh) ? sslport : port);
+ if (p == 0)
+ p = user->GetServerPort();
+ return p;
+ }
+};
class ModuleJumpServer : public Module
{
@@ -143,40 +153,30 @@ class ModuleJumpServer : public Module
{
}
- void init()
+ ModResult OnUserRegister(LocalUser* user) CXX11_OVERRIDE
{
- ServerInstance->Modules->AddService(js);
- Implementation eventlist[] = { I_OnUserRegister, I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- virtual ~ModuleJumpServer()
- {
- }
-
- virtual ModResult OnUserRegister(LocalUser* user)
- {
- if (js.port && js.redirect_new_users)
+ if (js.redirect_new_users)
{
- user->WriteNumeric(10, "%s %s %d :Please use this Server/Port instead",
- user->nick.c_str(), js.redirect_to.c_str(), js.port);
+ int port = js.GetPort(user);
+ user->WriteNumeric(RPL_REDIR, "%s %d :Please use this Server/Port instead",
+ js.redirect_to.c_str(), port);
ServerInstance->Users->QuitUser(user, js.reason);
return MOD_RES_PASSTHRU;
}
return MOD_RES_PASSTHRU;
}
- virtual void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
// Emergency way to unlock
- if (!user) js.redirect_new_users = false;
+ if (!status.srcuser)
+ js.redirect_new_users = false;
}
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for the RPL_REDIR numeric and the /JUMPSERVER command.", VF_VENDOR);
}
-
};
MODULE_INIT(ModuleJumpServer)
diff --git a/src/modules/m_kicknorejoin.cpp b/src/modules/m_kicknorejoin.cpp
index a914f3869..fdb7b8f24 100644
--- a/src/modules/m_kicknorejoin.cpp
+++ b/src/modules/m_kicknorejoin.cpp
@@ -25,49 +25,44 @@
#include "inspircd.h"
-/* $ModDesc: Provides channel mode +J (delay rejoin after kick) */
-
typedef std::map<std::string, time_t> delaylist;
+struct KickRejoinData
+{
+ delaylist kicked;
+ unsigned int delay;
+
+ KickRejoinData(unsigned int Delay) : delay(Delay) { }
+};
+
/** Handles channel mode +J
*/
-class KickRejoin : public ModeHandler
+class KickRejoin : public ParamMode<KickRejoin, SimpleExtItem<KickRejoinData> >
{
+ static const unsigned int max = 60;
public:
- unsigned int max;
- SimpleExtItem<delaylist> ext;
KickRejoin(Module* Creator)
- : ModeHandler(Creator, "kicknorejoin", 'J', PARAM_SETONLY, MODETYPE_CHANNEL)
- , ext("norejoinusers", Creator)
+ : ParamMode<KickRejoin, SimpleExtItem<KickRejoinData> >(Creator, "kicknorejoin", 'J')
{
}
- ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string& parameter, bool adding)
+ ModeAction OnSet(User* source, Channel* channel, std::string& parameter)
{
- if (adding)
- {
- int v = ConvToInt(parameter);
- if (v <= 0)
- return MODEACTION_DENY;
- if (parameter == channel->GetModeParameter(this))
- return MODEACTION_DENY;
-
- if ((IS_LOCAL(source) && ((unsigned int)v > max)))
- v = max;
+ int v = ConvToInt(parameter);
+ if (v <= 0)
+ return MODEACTION_DENY;
- parameter = ConvToStr(v);
- channel->SetModeParam(this, parameter);
- }
- else
- {
- if (!channel->IsModeSet(this))
- return MODEACTION_DENY;
+ if ((IS_LOCAL(source) && ((unsigned int)v > max)))
+ v = max;
- ext.unset(channel);
- channel->SetModeParam(this, "");
- }
+ ext.set(channel, new KickRejoinData(v));
return MODEACTION_ALLOW;
}
+
+ void SerializeParam(Channel* chan, const KickRejoinData* krd, std::string& out)
+ {
+ out.append(ConvToStr(krd->delay));
+ }
};
class ModuleKickNoRejoin : public Module
@@ -75,44 +70,27 @@ class ModuleKickNoRejoin : public Module
KickRejoin kr;
public:
-
ModuleKickNoRejoin()
: kr(this)
{
}
- void init()
- {
- ServerInstance->Modules->AddService(kr);
- ServerInstance->Modules->AddService(kr.ext);
- Implementation eventlist[] = { I_OnUserPreJoin, I_OnUserKick, I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- OnRehash(NULL);
- }
-
- void OnRehash(User* user)
- {
- kr.max = ServerInstance->Duration(ServerInstance->Config->ConfValue("kicknorejoin")->getString("maxtime"));
- if (!kr.max)
- kr.max = 30*60;
- }
-
- ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven)
+ ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE
{
if (chan)
{
- delaylist* dl = kr.ext.get(chan);
- if (dl)
+ KickRejoinData* data = kr.ext.get(chan);
+ if (data)
{
- for (delaylist::iterator iter = dl->begin(); iter != dl->end(); )
+ delaylist& kicked = data->kicked;
+ for (delaylist::iterator iter = kicked.begin(); iter != kicked.end(); )
{
if (iter->second > ServerInstance->Time())
{
if (iter->first == user->uuid)
{
- std::string modeparam = chan->GetModeParameter(&kr);
- user->WriteNumeric(ERR_DELAYREJOIN, "%s %s :You must wait %s seconds after being kicked to rejoin (+J)",
- user->nick.c_str(), chan->name.c_str(), modeparam.c_str());
+ user->WriteNumeric(ERR_DELAYREJOIN, "%s :You must wait %u seconds after being kicked to rejoin (+J)",
+ chan->name.c_str(), data->delay);
return MOD_RES_DENY;
}
++iter;
@@ -120,40 +98,30 @@ public:
else
{
// Expired record, remove.
- dl->erase(iter++);
+ kicked.erase(iter++);
}
}
-
- if (dl->empty())
- kr.ext.unset(chan);
}
}
return MOD_RES_PASSTHRU;
}
- void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& excepts)
+ void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& excepts) CXX11_OVERRIDE
{
- if (memb->chan->IsModeSet(&kr) && (IS_LOCAL(memb->user)) && (source != memb->user))
+ if ((!IS_LOCAL(memb->user)) || (source == memb->user))
+ return;
+
+ KickRejoinData* data = kr.ext.get(memb->chan);
+ if (data)
{
- delaylist* dl = kr.ext.get(memb->chan);
- if (!dl)
- {
- dl = new delaylist;
- kr.ext.set(memb->chan, dl);
- }
- (*dl)[memb->user->uuid] = ServerInstance->Time() + ConvToInt(memb->chan->GetModeParameter(&kr));
+ data->kicked[memb->user->uuid] = ServerInstance->Time() + data->delay;
}
}
- ~ModuleKickNoRejoin()
- {
- }
-
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Channel mode to delay rejoin after kick", VF_VENDOR);
}
};
-
MODULE_INIT(ModuleKickNoRejoin)
diff --git a/src/modules/m_knock.cpp b/src/modules/m_knock.cpp
index 8d2aa4543..26397bc9c 100644
--- a/src/modules/m_knock.cpp
+++ b/src/modules/m_knock.cpp
@@ -21,20 +21,23 @@
#include "inspircd.h"
-/* $ModDesc: Provides support for /KNOCK and channel mode +K */
-
/** Handles the /KNOCK command
*/
class CommandKnock : public Command
{
+ SimpleChannelModeHandler& noknockmode;
+ ChanModeReference inviteonlymode;
+
public:
bool sendnotice;
bool sendnumeric;
- CommandKnock(Module* Creator) : Command(Creator,"KNOCK", 2, 2)
+ CommandKnock(Module* Creator, SimpleChannelModeHandler& Noknockmode)
+ : Command(Creator,"KNOCK", 2, 2)
+ , noknockmode(Noknockmode)
+ , inviteonlymode(Creator, "inviteonly")
{
syntax = "<channel> <reason>";
Penalty = 5;
- TRANSLATE3(TR_TEXT, TR_TEXT, TR_END);
}
CmdResult Handle (const std::vector<std::string> &parameters, User *user)
@@ -42,25 +45,25 @@ class CommandKnock : public Command
Channel* c = ServerInstance->FindChan(parameters[0]);
if (!c)
{
- user->WriteNumeric(401, "%s %s :No such channel",user->nick.c_str(), parameters[0].c_str());
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such channel", parameters[0].c_str());
return CMD_FAILURE;
}
if (c->HasUser(user))
{
- user->WriteNumeric(480, "%s :Can't KNOCK on %s, you are already on that channel.", user->nick.c_str(), c->name.c_str());
+ user->WriteNumeric(ERR_KNOCKONCHAN, "%s :Can't KNOCK on %s, you are already on that channel.", c->name.c_str(), c->name.c_str());
return CMD_FAILURE;
}
- if (c->IsModeSet('K'))
+ if (c->IsModeSet(noknockmode))
{
- user->WriteNumeric(480, "%s :Can't KNOCK on %s, +K is set.",user->nick.c_str(), c->name.c_str());
+ user->WriteNumeric(480, ":Can't KNOCK on %s, +K is set.", c->name.c_str());
return CMD_FAILURE;
}
- if (!c->IsModeSet('i'))
+ if (!c->IsModeSet(inviteonlymode))
{
- user->WriteNumeric(480, "%s :Can't KNOCK on %s, channel is not invite only so knocking is pointless!",user->nick.c_str(), c->name.c_str());
+ user->WriteNumeric(ERR_CHANOPEN, "%s :Can't KNOCK on %s, channel is not invite only so knocking is pointless!", c->name.c_str(), c->name.c_str());
return CMD_FAILURE;
}
@@ -70,7 +73,7 @@ class CommandKnock : public Command
if (sendnumeric)
c->WriteChannelWithServ(ServerInstance->Config->ServerName, "710 %s %s %s :is KNOCKing: %s", c->name.c_str(), c->name.c_str(), user->GetFullHost().c_str(), parameters[1].c_str());
- user->WriteServ("NOTICE %s :KNOCKing on %s", user->nick.c_str(), c->name.c_str());
+ user->WriteNotice("KNOCKing on " + c->name);
return CMD_SUCCESS;
}
@@ -80,33 +83,19 @@ class CommandKnock : public Command
}
};
-/** Handles channel mode +K
- */
-class Knock : public SimpleChannelModeHandler
-{
- public:
- Knock(Module* Creator) : SimpleChannelModeHandler(Creator, "noknock", 'K') { }
-};
-
class ModuleKnock : public Module
{
+ SimpleChannelModeHandler kn;
CommandKnock cmd;
- Knock kn;
- public:
- ModuleKnock() : cmd(this), kn(this)
- {
- }
- void init()
+ public:
+ ModuleKnock()
+ : kn(this, "noknock", 'K')
+ , cmd(this, kn)
{
- ServerInstance->Modules->AddService(kn);
- ServerInstance->Modules->AddService(cmd);
-
- ServerInstance->Modules->Attach(I_OnRehash, this);
- OnRehash(NULL);
}
- void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
std::string knocknotify = ServerInstance->Config->ConfValue("knock")->getString("notify");
irc::string notify(knocknotify.c_str());
@@ -128,7 +117,7 @@ class ModuleKnock : public Module
}
}
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for /KNOCK and channel mode +K", VF_OPTCOMMON | VF_VENDOR);
}
diff --git a/src/modules/m_ldapauth.cpp b/src/modules/m_ldapauth.cpp
new file mode 100644
index 000000000..e89ce4949
--- /dev/null
+++ b/src/modules/m_ldapauth.cpp
@@ -0,0 +1,434 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2013 Adam <Adam@anope.org>
+ * Copyright (C) 2011 Pierre Carrier <pierre@spotify.com>
+ * Copyright (C) 2009-2010 Robin Burchell <robin+git@viroteck.net>
+ * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com>
+ * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc>
+ * Copyright (C) 2008 Dennis Friis <peavey@inspircd.org>
+ * Copyright (C) 2007 Carsten Valdemar Munk <carsten.munk+inspircd@gmail.com>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "modules/ldap.h"
+
+namespace
+{
+ Module* me;
+ std::string killreason;
+ LocalIntExt* authed;
+ bool verbose;
+ std::string vhost;
+ LocalStringExt* vhosts;
+ std::vector<std::pair<std::string, std::string> > requiredattributes;
+}
+
+class BindInterface : public LDAPInterface
+{
+ const std::string provider;
+ const std::string uid;
+ std::string DN;
+ bool checkingAttributes;
+ bool passed;
+ int attrCount;
+
+ static std::string SafeReplace(const std::string& text, std::map<std::string, std::string>& replacements)
+ {
+ std::string result;
+ result.reserve(text.length());
+
+ for (unsigned int i = 0; i < text.length(); ++i)
+ {
+ char c = text[i];
+ if (c == '$')
+ {
+ // find the first nonalpha
+ i++;
+ unsigned int start = i;
+
+ while (i < text.length() - 1 && isalpha(text[i + 1]))
+ ++i;
+
+ std::string key = text.substr(start, (i - start) + 1);
+ result.append(replacements[key]);
+ }
+ else
+ result.push_back(c);
+ }
+
+ return result;
+ }
+
+ static void SetVHost(User* user, const std::string& DN)
+ {
+ if (!vhost.empty())
+ {
+ irc::commasepstream stream(DN);
+
+ // mashed map of key:value parts of the DN
+ std::map<std::string, std::string> dnParts;
+
+ std::string dnPart;
+ while (stream.GetToken(dnPart))
+ {
+ std::string::size_type pos = dnPart.find('=');
+ if (pos == std::string::npos) // malformed
+ continue;
+
+ std::string key = dnPart.substr(0, pos);
+ std::string value = dnPart.substr(pos + 1, dnPart.length() - pos + 1); // +1s to skip the = itself
+ dnParts[key] = value;
+ }
+
+ // change host according to config key
+ vhosts->set(user, SafeReplace(vhost, dnParts));
+ }
+ }
+
+ public:
+ BindInterface(Module* c, const std::string& p, const std::string& u, const std::string& dn)
+ : LDAPInterface(c)
+ , provider(p), uid(u), DN(dn), checkingAttributes(false), passed(false), attrCount(0)
+ {
+ }
+
+ void OnResult(const LDAPResult& r) CXX11_OVERRIDE
+ {
+ User* user = ServerInstance->FindUUID(uid);
+ dynamic_reference<LDAPProvider> LDAP(me, provider);
+
+ if (!user || !LDAP)
+ {
+ if (!checkingAttributes || !--attrCount)
+ delete this;
+ return;
+ }
+
+ if (!checkingAttributes && requiredattributes.empty())
+ {
+ // We're done, there are no attributes to check
+ SetVHost(user, DN);
+ authed->set(user, 1);
+
+ delete this;
+ return;
+ }
+
+ // Already checked attributes?
+ if (checkingAttributes)
+ {
+ if (!passed)
+ {
+ // Only one has to pass
+ passed = true;
+
+ SetVHost(user, DN);
+ authed->set(user, 1);
+ }
+
+ // Delete this if this is the last ref
+ if (!--attrCount)
+ delete this;
+
+ return;
+ }
+
+ // check required attributes
+ checkingAttributes = true;
+
+ for (std::vector<std::pair<std::string, std::string> >::const_iterator it = requiredattributes.begin(); it != requiredattributes.end(); ++it)
+ {
+ // Note that only one of these has to match for it to be success
+ const std::string& attr = it->first;
+ const std::string& val = it->second;
+
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "LDAP compare: %s=%s", attr.c_str(), val.c_str());
+ try
+ {
+ LDAP->Compare(this, DN, attr, val);
+ ++attrCount;
+ }
+ catch (LDAPException &ex)
+ {
+ if (verbose)
+ ServerInstance->SNO->WriteToSnoMask('c', "Unable to compare attributes %s=%s: %s", attr.c_str(), val.c_str(), ex.GetReason().c_str());
+ }
+ }
+
+ // Nothing done
+ if (!attrCount)
+ {
+ if (verbose)
+ ServerInstance->SNO->WriteToSnoMask('c', "Forbidden connection from %s (unable to validate attributes)", user->GetFullRealHost().c_str());
+ ServerInstance->Users->QuitUser(user, killreason);
+ delete this;
+ }
+ }
+
+ void OnError(const LDAPResult& err) CXX11_OVERRIDE
+ {
+ if (checkingAttributes && --attrCount)
+ return;
+
+ if (passed)
+ {
+ delete this;
+ return;
+ }
+
+ User* user = ServerInstance->FindUUID(uid);
+ if (user)
+ {
+ if (verbose)
+ ServerInstance->SNO->WriteToSnoMask('c', "Forbidden connection from %s (%s)", user->GetFullRealHost().c_str(), err.getError().c_str());
+ ServerInstance->Users->QuitUser(user, killreason);
+ }
+
+ delete this;
+ }
+};
+
+class SearchInterface : public LDAPInterface
+{
+ const std::string provider;
+ const std::string uid;
+
+ public:
+ SearchInterface(Module* c, const std::string& p, const std::string& u)
+ : LDAPInterface(c), provider(p), uid(u)
+ {
+ }
+
+ void OnResult(const LDAPResult& r) CXX11_OVERRIDE
+ {
+ LocalUser* user = static_cast<LocalUser*>(ServerInstance->FindUUID(uid));
+ dynamic_reference<LDAPProvider> LDAP(me, provider);
+ if (!LDAP || r.empty() || !user)
+ {
+ if (user)
+ ServerInstance->Users->QuitUser(user, killreason);
+ delete this;
+ return;
+ }
+
+ try
+ {
+ const LDAPAttributes& a = r.get(0);
+ std::string bindDn = a.get("dn");
+ if (bindDn.empty())
+ {
+ ServerInstance->Users->QuitUser(user, killreason);
+ delete this;
+ return;
+ }
+
+ LDAP->Bind(new BindInterface(this->creator, provider, uid, bindDn), bindDn, user->password);
+ }
+ catch (LDAPException& ex)
+ {
+ ServerInstance->SNO->WriteToSnoMask('a', "Error searching LDAP server: " + ex.GetReason());
+ }
+ delete this;
+ }
+
+ void OnError(const LDAPResult& err) CXX11_OVERRIDE
+ {
+ ServerInstance->SNO->WriteToSnoMask('a', "Error searching LDAP server: %s", err.getError().c_str());
+ User* user = ServerInstance->FindUUID(uid);
+ if (user)
+ ServerInstance->Users->QuitUser(user, killreason);
+ delete this;
+ }
+};
+
+class AdminBindInterface : public LDAPInterface
+{
+ const std::string provider;
+ const std::string uuid;
+ const std::string base;
+ const std::string what;
+
+ public:
+ AdminBindInterface(Module* c, const std::string& p, const std::string& u, const std::string& b, const std::string& w)
+ : LDAPInterface(c), provider(p), uuid(u), base(b), what(w)
+ {
+ }
+
+ void OnResult(const LDAPResult& r) CXX11_OVERRIDE
+ {
+ dynamic_reference<LDAPProvider> LDAP(me, provider);
+ if (LDAP)
+ {
+ try
+ {
+ LDAP->Search(new SearchInterface(this->creator, provider, uuid), base, what);
+ }
+ catch (LDAPException& ex)
+ {
+ ServerInstance->SNO->WriteToSnoMask('a', "Error searching LDAP server: " + ex.GetReason());
+ }
+ }
+ delete this;
+ }
+
+ void OnError(const LDAPResult& err) CXX11_OVERRIDE
+ {
+ ServerInstance->SNO->WriteToSnoMask('a', "Error binding as manager to LDAP server: " + err.getError());
+ delete this;
+ }
+};
+
+class ModuleLDAPAuth : public Module
+{
+ dynamic_reference<LDAPProvider> LDAP;
+ LocalIntExt ldapAuthed;
+ LocalStringExt ldapVhost;
+ std::string base;
+ std::string attribute;
+ std::vector<std::string> allowpatterns;
+ std::vector<std::string> whitelistedcidrs;
+ bool useusername;
+
+public:
+ ModuleLDAPAuth()
+ : LDAP(this, "LDAP")
+ , ldapAuthed("ldapauth", this)
+ , ldapVhost("ldapauth_vhost", this)
+ {
+ me = this;
+ authed = &ldapAuthed;
+ vhosts = &ldapVhost;
+ }
+
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
+ {
+ ConfigTag* tag = ServerInstance->Config->ConfValue("ldapauth");
+ whitelistedcidrs.clear();
+ requiredattributes.clear();
+
+ base = tag->getString("baserdn");
+ attribute = tag->getString("attribute");
+ killreason = tag->getString("killreason");
+ vhost = tag->getString("host");
+ // Set to true if failed connects should be reported to operators
+ verbose = tag->getBool("verbose");
+ useusername = tag->getBool("userfield");
+
+ LDAP.SetProvider("LDAP/" + tag->getString("dbid"));
+
+ ConfigTagList whitelisttags = ServerInstance->Config->ConfTags("ldapwhitelist");
+
+ for (ConfigIter i = whitelisttags.first; i != whitelisttags.second; ++i)
+ {
+ std::string cidr = i->second->getString("cidr");
+ if (!cidr.empty()) {
+ whitelistedcidrs.push_back(cidr);
+ }
+ }
+
+ ConfigTagList attributetags = ServerInstance->Config->ConfTags("ldaprequire");
+
+ for (ConfigIter i = attributetags.first; i != attributetags.second; ++i)
+ {
+ const std::string attr = i->second->getString("attribute");
+ const std::string val = i->second->getString("value");
+
+ if (!attr.empty() && !val.empty())
+ requiredattributes.push_back(make_pair(attr, val));
+ }
+
+ std::string allowpattern = tag->getString("allowpattern");
+ irc::spacesepstream ss(allowpattern);
+ for (std::string more; ss.GetToken(more); )
+ {
+ allowpatterns.push_back(more);
+ }
+ }
+
+ void OnUserConnect(LocalUser *user) CXX11_OVERRIDE
+ {
+ std::string* cc = ldapVhost.get(user);
+ if (cc)
+ {
+ user->ChangeDisplayedHost(*cc);
+ ldapVhost.unset(user);
+ }
+ }
+
+ ModResult OnUserRegister(LocalUser* user) CXX11_OVERRIDE
+ {
+ for (std::vector<std::string>::const_iterator i = allowpatterns.begin(); i != allowpatterns.end(); ++i)
+ {
+ if (InspIRCd::Match(user->nick, *i))
+ {
+ ldapAuthed.set(user,1);
+ return MOD_RES_PASSTHRU;
+ }
+ }
+
+ for (std::vector<std::string>::iterator i = whitelistedcidrs.begin(); i != whitelistedcidrs.end(); i++)
+ {
+ if (InspIRCd::MatchCIDR(user->GetIPString(), *i, ascii_case_insensitive_map))
+ {
+ ldapAuthed.set(user,1);
+ return MOD_RES_PASSTHRU;
+ }
+ }
+
+ if (user->password.empty())
+ {
+ if (verbose)
+ ServerInstance->SNO->WriteToSnoMask('c', "Forbidden connection from %s (No password provided)", user->GetFullRealHost().c_str());
+ ServerInstance->Users->QuitUser(user, killreason);
+ return MOD_RES_DENY;
+ }
+
+ if (!LDAP)
+ {
+ if (verbose)
+ ServerInstance->SNO->WriteToSnoMask('c', "Forbidden connection from %s (Unable to find LDAP provider)", user->GetFullRealHost().c_str());
+ ServerInstance->Users->QuitUser(user, killreason);
+ return MOD_RES_DENY;
+ }
+
+ try
+ {
+ std::string what = attribute + "=" + (useusername ? user->ident : user->nick);
+ LDAP->BindAsManager(new AdminBindInterface(this, LDAP.GetProvider(), user->uuid, base, what));
+ }
+ catch (LDAPException &ex)
+ {
+ ServerInstance->SNO->WriteToSnoMask('a', "LDAP exception: " + ex.GetReason());
+ ServerInstance->Users->QuitUser(user, killreason);
+ }
+
+ return MOD_RES_DENY;
+ }
+
+ ModResult OnCheckReady(LocalUser* user) CXX11_OVERRIDE
+ {
+ return ldapAuthed.get(user) ? MOD_RES_PASSTHRU : MOD_RES_DENY;
+ }
+
+ Version GetVersion() CXX11_OVERRIDE
+ {
+ return Version("Allow/Deny connections based upon answer from LDAP server", VF_VENDOR);
+ }
+};
+
+MODULE_INIT(ModuleLDAPAuth)
diff --git a/src/modules/m_ldapoper.cpp b/src/modules/m_ldapoper.cpp
new file mode 100644
index 000000000..9deb9a203
--- /dev/null
+++ b/src/modules/m_ldapoper.cpp
@@ -0,0 +1,248 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2013 Adam <Adam@anope.org>
+ * Copyright (C) 2009 Robin Burchell <robin+git@viroteck.net>
+ * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com>
+ * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc>
+ * Copyright (C) 2007 Carsten Valdemar Munk <carsten.munk+inspircd@gmail.com>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "modules/ldap.h"
+
+namespace
+{
+ Module* me;
+}
+
+class LDAPOperBase : public LDAPInterface
+{
+ protected:
+ const std::string uid;
+ const std::string opername;
+ const std::string password;
+
+ void Fallback(User* user)
+ {
+ if (!user)
+ return;
+
+ Command* oper_command = ServerInstance->Parser.GetHandler("OPER");
+ if (!oper_command)
+ return;
+
+ std::vector<std::string> params;
+ params.push_back(opername);
+ params.push_back(password);
+ oper_command->Handle(params, user);
+ }
+
+ void Fallback()
+ {
+ User* user = ServerInstance->FindUUID(uid);
+ Fallback(user);
+ }
+
+ public:
+ LDAPOperBase(Module* mod, const std::string& uuid, const std::string& oper, const std::string& pass)
+ : LDAPInterface(mod)
+ , uid(uuid), opername(oper), password(pass)
+ {
+ }
+
+ void OnError(const LDAPResult& err) CXX11_OVERRIDE
+ {
+ ServerInstance->SNO->WriteToSnoMask('a', "Error searching LDAP server: %s", err.getError().c_str());
+ Fallback();
+ delete this;
+ }
+};
+
+class BindInterface : public LDAPOperBase
+{
+ public:
+ BindInterface(Module* mod, const std::string& uuid, const std::string& oper, const std::string& pass)
+ : LDAPOperBase(mod, uuid, oper, pass)
+ {
+ }
+
+ void OnResult(const LDAPResult& r) CXX11_OVERRIDE
+ {
+ User* user = ServerInstance->FindUUID(uid);
+ ServerConfig::OperIndex::const_iterator iter = ServerInstance->Config->oper_blocks.find(opername);
+
+ if (!user || iter == ServerInstance->Config->oper_blocks.end())
+ {
+ Fallback();
+ delete this;
+ return;
+ }
+
+ OperInfo* ifo = iter->second;
+ user->Oper(ifo);
+ delete this;
+ }
+};
+
+class SearchInterface : public LDAPOperBase
+{
+ const std::string provider;
+
+ bool HandleResult(const LDAPResult& result)
+ {
+ dynamic_reference<LDAPProvider> LDAP(me, provider);
+ if (!LDAP || result.empty())
+ return false;
+
+ try
+ {
+ const LDAPAttributes& attr = result.get(0);
+ std::string bindDn = attr.get("dn");
+ if (bindDn.empty())
+ return false;
+
+ LDAP->Bind(new BindInterface(this->creator, uid, opername, password), bindDn, password);
+ }
+ catch (LDAPException& ex)
+ {
+ ServerInstance->SNO->WriteToSnoMask('a', "Error searching LDAP server: " + ex.GetReason());
+ }
+
+ return true;
+ }
+
+ public:
+ SearchInterface(Module* mod, const std::string& prov, const std::string &uuid, const std::string& oper, const std::string& pass)
+ : LDAPOperBase(mod, uuid, oper, pass)
+ , provider(prov)
+ {
+ }
+
+ void OnResult(const LDAPResult& result) CXX11_OVERRIDE
+ {
+ if (!HandleResult(result))
+ Fallback();
+ delete this;
+ }
+};
+
+class AdminBindInterface : public LDAPInterface
+{
+ const std::string provider;
+ const std::string user;
+ const std::string opername;
+ const std::string password;
+ const std::string base;
+ const std::string what;
+
+ public:
+ AdminBindInterface(Module* c, const std::string& p, const std::string& u, const std::string& o, const std::string& pa, const std::string& b, const std::string& w)
+ : LDAPInterface(c), provider(p), user(u), opername(p), password(pa), base(b), what(w)
+ {
+ }
+
+ void OnResult(const LDAPResult& r) CXX11_OVERRIDE
+ {
+ dynamic_reference<LDAPProvider> LDAP(me, provider);
+ if (LDAP)
+ {
+ try
+ {
+ LDAP->Search(new SearchInterface(this->creator, provider, user, opername, password), base, what);
+ }
+ catch (LDAPException& ex)
+ {
+ ServerInstance->SNO->WriteToSnoMask('a', "Error searching LDAP server: " + ex.GetReason());
+ }
+ }
+ delete this;
+ }
+
+ void OnError(const LDAPResult& err) CXX11_OVERRIDE
+ {
+ ServerInstance->SNO->WriteToSnoMask('a', "Error binding as manager to LDAP server: " + err.getError());
+ delete this;
+ }
+};
+
+class ModuleLDAPAuth : public Module
+{
+ dynamic_reference<LDAPProvider> LDAP;
+ std::string base;
+ std::string attribute;
+
+ public:
+ ModuleLDAPAuth()
+ : LDAP(this, "LDAP")
+ {
+ me = this;
+ }
+
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
+ {
+ ConfigTag* tag = ServerInstance->Config->ConfValue("ldapoper");
+
+ LDAP.SetProvider("LDAP/" + tag->getString("dbid"));
+ base = tag->getString("baserdn");
+ attribute = tag->getString("attribute");
+ }
+
+ ModResult OnPreCommand(std::string& command, std::vector<std::string>& parameters, LocalUser* user, bool validated, const std::string& original_line) CXX11_OVERRIDE
+ {
+ if (validated && command == "OPER" && parameters.size() >= 2)
+ {
+ const std::string& opername = parameters[0];
+ const std::string& password = parameters[1];
+
+ ServerConfig::OperIndex::const_iterator it = ServerInstance->Config->oper_blocks.find(opername);
+ if (it == ServerInstance->Config->oper_blocks.end())
+ return MOD_RES_PASSTHRU;
+
+ ConfigTag* tag = it->second->oper_block;
+ if (!tag)
+ return MOD_RES_PASSTHRU;
+
+ std::string acceptedhosts = tag->getString("host");
+ std::string hostname = user->ident + "@" + user->host;
+ if (!InspIRCd::MatchMask(acceptedhosts, hostname, user->GetIPString()))
+ return MOD_RES_PASSTHRU;
+
+ if (!LDAP)
+ return MOD_RES_PASSTHRU;
+
+ try
+ {
+ std::string what = attribute + "=" + opername;
+ LDAP->BindAsManager(new AdminBindInterface(this, LDAP.GetProvider(), user->uuid, opername, password, base, what));
+ return MOD_RES_DENY;
+ }
+ catch (LDAPException& ex)
+ {
+ ServerInstance->SNO->WriteToSnoMask('a', "LDAP exception: " + ex.GetReason());
+ }
+ }
+
+ return MOD_RES_PASSTHRU;
+ }
+
+ Version GetVersion() CXX11_OVERRIDE
+ {
+ return Version("Adds the ability to authenticate opers via LDAP", VF_VENDOR);
+ }
+};
+
+MODULE_INIT(ModuleLDAPAuth)
diff --git a/src/modules/m_lockserv.cpp b/src/modules/m_lockserv.cpp
index 4983ae16a..65b9aa036 100644
--- a/src/modules/m_lockserv.cpp
+++ b/src/modules/m_lockserv.cpp
@@ -20,18 +20,16 @@
#include "inspircd.h"
-/* $ModDesc: Allows locking of the server to stop all incoming connections till unlocked again */
-
/** Adds numerics
* 988 <nick> <servername> :Closed for new connections
* 989 <nick> <servername> :Open for new connections
-*/
-
+ */
class CommandLockserv : public Command
{
bool& locked;
-public:
+
+ public:
CommandLockserv(Module* Creator, bool& lock) : Command(Creator, "LOCKSERV", 0), locked(lock)
{
flags_needed = 'o';
@@ -41,12 +39,12 @@ public:
{
if (locked)
{
- user->WriteServ("NOTICE %s :The server is already locked.", user->nick.c_str());
+ user->WriteNotice("The server is already locked.");
return CMD_FAILURE;
}
locked = true;
- user->WriteNumeric(988, "%s %s :Closed for new connections", user->nick.c_str(), user->server.c_str());
+ user->WriteNumeric(988, "%s :Closed for new connections", user->server->GetName().c_str());
ServerInstance->SNO->WriteGlobalSno('a', "Oper %s used LOCKSERV to temporarily disallow new connections", user->nick.c_str());
return CMD_SUCCESS;
}
@@ -54,10 +52,9 @@ public:
class CommandUnlockserv : public Command
{
-private:
bool& locked;
-public:
+ public:
CommandUnlockserv(Module* Creator, bool &lock) : Command(Creator, "UNLOCKSERV", 0), locked(lock)
{
flags_needed = 'o';
@@ -67,12 +64,12 @@ public:
{
if (!locked)
{
- user->WriteServ("NOTICE %s :The server isn't locked.", user->nick.c_str());
+ user->WriteNotice("The server isn't locked.");
return CMD_FAILURE;
}
locked = false;
- user->WriteNumeric(989, "%s %s :Open for new connections", user->nick.c_str(), user->server.c_str());
+ user->WriteNumeric(989, "%s :Open for new connections", user->server->GetName().c_str());
ServerInstance->SNO->WriteGlobalSno('a', "Oper %s used UNLOCKSERV to allow new connections", user->nick.c_str());
return CMD_SUCCESS;
}
@@ -80,37 +77,28 @@ public:
class ModuleLockserv : public Module
{
-private:
bool locked;
CommandLockserv lockcommand;
CommandUnlockserv unlockcommand;
-public:
+ public:
ModuleLockserv() : lockcommand(this, locked), unlockcommand(this, locked)
{
}
- void init()
+ void init() CXX11_OVERRIDE
{
locked = false;
- ServerInstance->Modules->AddService(lockcommand);
- ServerInstance->Modules->AddService(unlockcommand);
- Implementation eventlist[] = { I_OnUserRegister, I_OnRehash, I_OnCheckReady };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
}
- virtual ~ModuleLockserv()
- {
- }
-
-
- virtual void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
// Emergency way to unlock
- if (!user) locked = false;
+ if (!status.srcuser)
+ locked = false;
}
- virtual ModResult OnUserRegister(LocalUser* user)
+ ModResult OnUserRegister(LocalUser* user) CXX11_OVERRIDE
{
if (locked)
{
@@ -120,12 +108,12 @@ public:
return MOD_RES_PASSTHRU;
}
- virtual ModResult OnCheckReady(LocalUser* user)
+ ModResult OnCheckReady(LocalUser* user) CXX11_OVERRIDE
{
return locked ? MOD_RES_DENY : MOD_RES_PASSTHRU;
}
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Allows locking of the server to stop all incoming connections until unlocked again", VF_VENDOR);
}
diff --git a/src/modules/m_maphide.cpp b/src/modules/m_maphide.cpp
index 546e342ae..41de2997d 100644
--- a/src/modules/m_maphide.cpp
+++ b/src/modules/m_maphide.cpp
@@ -19,44 +19,30 @@
#include "inspircd.h"
-/* $ModDesc: Hide /MAP and /LINKS in the same form as ircu (mostly useless) */
-
class ModuleMapHide : public Module
{
std::string url;
public:
- void init()
- {
- Implementation eventlist[] = { I_OnPreCommand, I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- OnRehash(NULL);
- }
-
- void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
url = ServerInstance->Config->ConfValue("security")->getString("maphide");
}
- ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line)
+ ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line) CXX11_OVERRIDE
{
- if (validated && !IS_OPER(user) && !url.empty() && (command == "MAP" || command == "LINKS"))
+ if (validated && !user->IsOper() && !url.empty() && (command == "MAP" || command == "LINKS"))
{
- user->WriteServ("NOTICE %s :/%s has been disabled; visit %s", user->nick.c_str(), command.c_str(), url.c_str());
+ user->WriteNotice("/" + command + " has been disabled; visit " + url);
return MOD_RES_DENY;
}
else
return MOD_RES_PASSTHRU;
}
- virtual ~ModuleMapHide()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Hide /MAP and /LINKS in the same form as ircu (mostly useless)", VF_VENDOR);
}
};
MODULE_INIT(ModuleMapHide)
-
diff --git a/src/modules/m_md5.cpp b/src/modules/m_md5.cpp
index 14ccf16a8..ecf76d07c 100644
--- a/src/modules/m_md5.cpp
+++ b/src/modules/m_md5.cpp
@@ -21,13 +21,8 @@
*/
-/* $ModDesc: Allows for MD5 encrypted oper passwords */
-
#include "inspircd.h"
-#ifdef HAS_STDINT
-#include <stdint.h>
-#endif
-#include "hash.h"
+#include "modules/hash.h"
/* The four core functions - F1 is optimized somewhat */
#define F1(x, y, z) (z ^ (x & (y ^ z)))
@@ -39,10 +34,6 @@
#define MD5STEP(f,w,x,y,z,in,s) \
(w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
-#ifndef HAS_STDINT
-typedef unsigned int uint32_t;
-#endif
-
typedef uint32_t word32; /* NOT unsigned long. We don't support 16 bit platforms, anyway. */
typedef unsigned char byte;
@@ -275,13 +266,6 @@ class MD5Provider : public HashProvider
return std::string(res, 16);
}
- std::string sumIV(unsigned int* IV, const char* HexMap, const std::string &sdata)
- {
- char res[33];
- GenHash(sdata.data(), res, HexMap, IV, sdata.length());
- return res;
- }
-
MD5Provider(Module* parent) : HashProvider(parent, "hash/md5", 16, 64) {}
};
@@ -291,10 +275,9 @@ class ModuleMD5 : public Module
public:
ModuleMD5() : md5(this)
{
- ServerInstance->Modules->AddService(md5);
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Implements MD5 hashing",VF_VENDOR);
}
diff --git a/src/modules/m_messageflood.cpp b/src/modules/m_messageflood.cpp
index 9ff17924d..92d67b9ab 100644
--- a/src/modules/m_messageflood.cpp
+++ b/src/modules/m_messageflood.cpp
@@ -25,8 +25,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides channel mode +f (message flood protection) */
-
/** Holds flood settings and state for mode +f
*/
class floodsettings
@@ -66,54 +64,44 @@ class floodsettings
/** Handles channel mode +f
*/
-class MsgFlood : public ModeHandler
+class MsgFlood : public ParamMode<MsgFlood, SimpleExtItem<floodsettings> >
{
public:
- SimpleExtItem<floodsettings> ext;
- MsgFlood(Module* Creator) : ModeHandler(Creator, "flood", 'f', PARAM_SETONLY, MODETYPE_CHANNEL),
- ext("messageflood", Creator) { }
+ MsgFlood(Module* Creator)
+ : ParamMode<MsgFlood, SimpleExtItem<floodsettings> >(Creator, "flood", 'f')
+ {
+ }
- ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
+ ModeAction OnSet(User* source, Channel* channel, std::string& parameter)
{
- if (adding)
+ std::string::size_type colon = parameter.find(':');
+ if ((colon == std::string::npos) || (parameter.find('-') != std::string::npos))
{
- std::string::size_type colon = parameter.find(':');
- if ((colon == std::string::npos) || (parameter.find('-') != std::string::npos))
- {
- source->WriteNumeric(608, "%s %s :Invalid flood parameter",source->nick.c_str(),channel->name.c_str());
- return MODEACTION_DENY;
- }
-
- /* Set up the flood parameters for this channel */
- bool ban = (parameter[0] == '*');
- unsigned int nlines = ConvToInt(parameter.substr(ban ? 1 : 0, ban ? colon-1 : colon));
- unsigned int nsecs = ConvToInt(parameter.substr(colon+1));
-
- if ((nlines<2) || (nsecs<1))
- {
- source->WriteNumeric(608, "%s %s :Invalid flood parameter",source->nick.c_str(),channel->name.c_str());
- return MODEACTION_DENY;
- }
+ source->WriteNumeric(608, "%s :Invalid flood parameter", channel->name.c_str());
+ return MODEACTION_DENY;
+ }
- floodsettings* f = ext.get(channel);
- if ((f) && (nlines == f->lines) && (nsecs == f->secs) && (ban == f->ban))
- // mode params match
- return MODEACTION_DENY;
+ /* Set up the flood parameters for this channel */
+ bool ban = (parameter[0] == '*');
+ unsigned int nlines = ConvToInt(parameter.substr(ban ? 1 : 0, ban ? colon-1 : colon));
+ unsigned int nsecs = ConvToInt(parameter.substr(colon+1));
- ext.set(channel, new floodsettings(ban, nsecs, nlines));
- parameter = std::string(ban ? "*" : "") + ConvToStr(nlines) + ":" + ConvToStr(nsecs);
- channel->SetModeParam('f', parameter);
- return MODEACTION_ALLOW;
- }
- else
+ if ((nlines<2) || (nsecs<1))
{
- if (!channel->IsModeSet('f'))
- return MODEACTION_DENY;
-
- ext.unset(channel);
- channel->SetModeParam('f', "");
- return MODEACTION_ALLOW;
+ source->WriteNumeric(608, "%s :Invalid flood parameter", channel->name.c_str());
+ return MODEACTION_DENY;
}
+
+ ext.set(channel, new floodsettings(ban, nsecs, nlines));
+ return MODEACTION_ALLOW;
+ }
+
+ void SerializeParam(Channel* chan, const floodsettings* fs, std::string& out)
+ {
+ if (fs->ban)
+ out.push_back('*');
+ out.append(ConvToStr(fs->lines)).push_back(':');
+ out.append(ConvToStr(fs->secs));
}
};
@@ -128,17 +116,13 @@ class ModuleMsgFlood : public Module
{
}
- void init()
+ ModResult OnUserPreMessage(User* user, void* voiddest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE
{
- ServerInstance->Modules->AddService(mf);
- ServerInstance->Modules->AddService(mf.ext);
- Implementation eventlist[] = { I_OnUserPreNotice, I_OnUserPreMessage };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
+ if (target_type != TYPE_CHANNEL)
+ return MOD_RES_PASSTHRU;
- ModResult ProcessMessages(User* user,Channel* dest, const std::string &text)
- {
- if ((!IS_LOCAL(user)) || !dest->IsModeSet('f'))
+ Channel* dest = static_cast<Channel*>(voiddest);
+ if ((!IS_LOCAL(user)) || !dest->IsModeSet(mf))
return MOD_RES_PASSTHRU;
if (ServerInstance->OnCheckExemption(user,dest,"flood") == MOD_RES_ALLOW)
@@ -156,14 +140,14 @@ class ModuleMsgFlood : public Module
std::vector<std::string> parameters;
parameters.push_back(dest->name);
parameters.push_back("+b");
- parameters.push_back(user->MakeWildHost());
- ServerInstance->SendGlobalMode(parameters, ServerInstance->FakeClient);
+ parameters.push_back("*!*@" + user->dhost);
+ ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient);
}
- char kickmessage[MAXBUF];
- snprintf(kickmessage, MAXBUF, "Channel flood triggered (limit is %u lines in %u secs)", f->lines, f->secs);
+ const std::string kickMessage = "Channel flood triggered (limit is " + ConvToStr(f->lines) +
+ " in " + ConvToStr(f->secs) + " secs)";
- dest->KickUser(ServerInstance->FakeClient, user, kickmessage);
+ dest->KickUser(ServerInstance->FakeClient, user, kickMessage);
return MOD_RES_DENY;
}
@@ -172,30 +156,13 @@ class ModuleMsgFlood : public Module
return MOD_RES_PASSTHRU;
}
- ModResult OnUserPreMessage(User *user, void *dest, int target_type, std::string &text, char status, CUList &exempt_list)
- {
- if (target_type == TYPE_CHANNEL)
- return ProcessMessages(user,(Channel*)dest,text);
-
- return MOD_RES_PASSTHRU;
- }
-
- ModResult OnUserPreNotice(User *user, void *dest, int target_type, std::string &text, char status, CUList &exempt_list)
- {
- if (target_type == TYPE_CHANNEL)
- return ProcessMessages(user,(Channel*)dest,text);
-
- return MOD_RES_PASSTHRU;
- }
-
void Prioritize()
{
// we want to be after all modules that might deny the message (e.g. m_muteban, m_noctcp, m_blockcolor, etc.)
ServerInstance->Modules->SetPriority(this, I_OnUserPreMessage, PRIORITY_LAST);
- ServerInstance->Modules->SetPriority(this, I_OnUserPreNotice, PRIORITY_LAST);
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides channel mode +f (message flood protection)", VF_VENDOR);
}
diff --git a/src/modules/m_mlock.cpp b/src/modules/m_mlock.cpp
index d1df81354..d9c43ec10 100644
--- a/src/modules/m_mlock.cpp
+++ b/src/modules/m_mlock.cpp
@@ -17,30 +17,24 @@
*/
-/* $ModDesc: Implements the ability to have server-side MLOCK enforcement. */
-
#include "inspircd.h"
class ModuleMLock : public Module
{
-private:
StringExtItem mlock;
-public:
- ModuleMLock() : mlock("mlock", this) {};
-
- void init()
+ public:
+ ModuleMLock()
+ : mlock("mlock", this)
{
- ServerInstance->Modules->Attach(I_OnRawMode, this);
- ServerInstance->Modules->AddService(this->mlock);
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Implements the ability to have server-side MLOCK enforcement.", VF_VENDOR);
}
- ModResult OnRawMode(User* source, Channel* channel, const char mode, const std::string& parameter, bool adding, int pcnt)
+ ModResult OnRawMode(User* source, Channel* channel, ModeHandler* mh, const std::string& parameter, bool adding)
{
if (!channel)
return MOD_RES_PASSTHRU;
@@ -52,6 +46,7 @@ public:
if (!mlock_str)
return MOD_RES_PASSTHRU;
+ const char mode = mh->GetModeChar();
std::string::size_type p = mlock_str->find(mode);
if (p != std::string::npos)
{
@@ -62,7 +57,6 @@ public:
return MOD_RES_PASSTHRU;
}
-
};
MODULE_INIT(ModuleMLock)
diff --git a/src/commands/cmd_modenotice.cpp b/src/modules/m_modenotice.cpp
index 852b72f6a..056eb4a62 100644
--- a/src/commands/cmd_modenotice.cpp
+++ b/src/modules/m_modenotice.cpp
@@ -30,8 +30,10 @@ class CommandModeNotice : public Command
CmdResult Handle(const std::vector<std::string>& parameters, User *src)
{
+ std::string msg = "*** From " + src->nick + ": " + parameters[1];
int mlen = parameters[0].length();
- for (LocalUserList::const_iterator i = ServerInstance->Users->local_users.begin(); i != ServerInstance->Users->local_users.end(); i++)
+ const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers();
+ for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i)
{
User* user = *i;
for (int n = 0; n < mlen; n++)
@@ -39,8 +41,7 @@ class CommandModeNotice : public Command
if (!user->IsModeSet(parameters[0][n]))
goto next_user;
}
- user->Write(":%s NOTICE %s :*** From %s: %s", ServerInstance->Config->ServerName.c_str(),
- user->nick.c_str(), src->nick.c_str(), parameters[1].c_str());
+ user->WriteNotice(msg);
next_user: ;
}
return CMD_SUCCESS;
@@ -48,8 +49,24 @@ next_user: ;
RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
{
- return ROUTE_BROADCAST;
+ return ROUTE_OPT_BCAST;
}
};
-COMMAND_INIT(CommandModeNotice)
+class ModuleModeNotice : public Module
+{
+ CommandModeNotice cmd;
+
+ public:
+ ModuleModeNotice()
+ : cmd(this)
+ {
+ }
+
+ Version GetVersion() CXX11_OVERRIDE
+ {
+ return Version("Provides the /MODENOTICE command", VF_VENDOR);
+ }
+};
+
+MODULE_INIT(ModuleModeNotice)
diff --git a/src/modules/m_muteban.cpp b/src/modules/m_muteban.cpp
index 767af2901..72c4acd47 100644
--- a/src/modules/m_muteban.cpp
+++ b/src/modules/m_muteban.cpp
@@ -20,28 +20,15 @@
#include "inspircd.h"
-/* $ModDesc: Implements extban +b m: - mute bans */
-
class ModuleQuietBan : public Module
{
- private:
public:
- void init()
- {
- Implementation eventlist[] = { I_OnUserPreMessage, I_OnUserPreNotice, I_On005Numeric };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- virtual ~ModuleQuietBan()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Implements extban +b m: - mute bans",VF_OPTCOMMON|VF_VENDOR);
}
- virtual ModResult OnUserPreMessage(User *user, void *dest, int target_type, std::string &text, char status, CUList &exempt_list)
+ ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE
{
if (!IS_LOCAL(user) || target_type != TYPE_CHANNEL)
return MOD_RES_PASSTHRU;
@@ -49,24 +36,17 @@ class ModuleQuietBan : public Module
Channel* chan = static_cast<Channel*>(dest);
if (chan->GetExtBanStatus(user, 'm') == MOD_RES_DENY && chan->GetPrefixValue(user) < VOICE_VALUE)
{
- user->WriteNumeric(404, "%s %s :Cannot send to channel (you're muted)", user->nick.c_str(), chan->name.c_str());
+ user->WriteNumeric(ERR_CANNOTSENDTOCHAN, "%s :Cannot send to channel (you're muted)", chan->name.c_str());
return MOD_RES_DENY;
}
return MOD_RES_PASSTHRU;
}
- virtual ModResult OnUserPreNotice(User *user, void *dest, int target_type, std::string &text, char status, CUList &exempt_list)
- {
- return OnUserPreMessage(user, dest, target_type, text, status, exempt_list);
- }
-
- virtual void On005Numeric(std::string &output)
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
- ServerInstance->AddExtBanChar('m');
+ tokens["EXTBAN"].push_back('m');
}
};
-
MODULE_INIT(ModuleQuietBan)
-
diff --git a/src/modules/m_namedmodes.cpp b/src/modules/m_namedmodes.cpp
index 4db1f70b9..5c0ffeea5 100644
--- a/src/modules/m_namedmodes.cpp
+++ b/src/modules/m_namedmodes.cpp
@@ -17,28 +17,24 @@
*/
-/* $ModDesc: Provides the ability to manipulate modes via long names. */
-
#include "inspircd.h"
static void DisplayList(User* user, Channel* channel)
{
std::stringstream items;
- for(char letter = 'A'; letter <= 'z'; letter++)
+ const ModeParser::ModeHandlerMap& mhs = ServerInstance->Modes->GetModes(MODETYPE_CHANNEL);
+ for (ModeParser::ModeHandlerMap::const_iterator i = mhs.begin(); i != mhs.end(); ++i)
{
- ModeHandler* mh = ServerInstance->Modes->FindMode(letter, MODETYPE_CHANNEL);
- if (!mh || mh->IsListMode())
- continue;
- if (!channel->IsModeSet(letter))
+ ModeHandler* mh = i->second;
+ if (!channel->IsModeSet(mh))
continue;
items << " +" << mh->name;
if (mh->GetNumParams(true))
- items << " " << channel->GetModeParameter(letter);
+ items << " " << channel->GetModeParameter(mh);
}
- char pfx[MAXBUF];
- snprintf(pfx, MAXBUF, ":%s 961 %s %s", ServerInstance->Config->ServerName.c_str(), user->nick.c_str(), channel->name.c_str());
- user->SendText(std::string(pfx), items);
- user->WriteNumeric(960, "%s %s :End of mode list", user->nick.c_str(), channel->name.c_str());
+ const std::string line = ":" + ServerInstance->Config->ServerName + " 961 " + user->nick + " " + channel->name;
+ user->SendText(line, items);
+ user->WriteNumeric(960, "%s :End of mode list", channel->name.c_str());
}
class CommandProp : public Command
@@ -69,21 +65,19 @@ class CommandProp : public Command
if (prop[0] == '+' || prop[0] == '-')
prop.erase(prop.begin());
- for(char letter = 'A'; letter <= 'z'; letter++)
+ ModeHandler* mh = ServerInstance->Modes->FindMode(prop, MODETYPE_CHANNEL);
+ if (mh)
{
- ModeHandler* mh = ServerInstance->Modes->FindMode(letter, MODETYPE_CHANNEL);
- if (mh && mh->name == prop)
+ modes[1].push_back(plus ? '+' : '-');
+ modes[1].push_back(mh->GetModeChar());
+ if (mh->GetNumParams(plus))
{
- modes[1].append((plus ? "+" : "-") + std::string(1, letter));
- if (mh->GetNumParams(plus))
- {
- if (i != parameters.size())
- modes.push_back(parameters[i++]);
- }
+ if (i != parameters.size())
+ modes.push_back(parameters[i++]);
}
}
}
- ServerInstance->SendGlobalMode(modes, src);
+ ServerInstance->Modes->Process(modes, src);
return CMD_SUCCESS;
}
};
@@ -106,16 +100,7 @@ class ModuleNamedModes : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cmd);
- ServerInstance->Modules->AddService(dummyZ);
-
- Implementation eventlist[] = { I_OnPreMode };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides the ability to manipulate modes via long names.",VF_VENDOR);
}
@@ -125,7 +110,7 @@ class ModuleNamedModes : public Module
ServerInstance->Modules->SetPriority(this, I_OnPreMode, PRIORITY_FIRST);
}
- ModResult OnPreMode(User* source, User* dest, Channel* channel, const std::vector<std::string>& parameters)
+ ModResult OnPreMode(User* source, User* dest, Channel* channel, const std::vector<std::string>& parameters) CXX11_OVERRIDE
{
if (!channel)
return MOD_RES_PASSTHRU;
@@ -155,7 +140,6 @@ class ModuleNamedModes : public Module
ModeHandler *mh = ServerInstance->Modes->FindMode(modechar, MODETYPE_CHANNEL);
if (modechar == 'Z')
{
- modechar = 0;
std::string name, value;
if (param_at < parameters.size())
name = parameters[param_at++];
@@ -165,31 +149,28 @@ class ModuleNamedModes : public Module
value = name.substr(eq + 1);
name = name.substr(0, eq);
}
- for(char letter = 'A'; modechar == 0 && letter <= 'z'; letter++)
+
+ mh = ServerInstance->Modes->FindMode(name, MODETYPE_CHANNEL);
+ if (!mh)
+ {
+ // Mode handler not found
+ modelist.erase(i--, 1);
+ continue;
+ }
+
+ if (mh->GetNumParams(adding))
{
- mh = ServerInstance->Modes->FindMode(letter, MODETYPE_CHANNEL);
- if (mh && mh->name == name)
+ if (value.empty())
{
- if (mh->GetNumParams(adding))
- {
- if (!value.empty())
- {
- newparms.push_back(value);
- modechar = letter;
- break;
- }
- }
- else
- {
- modechar = letter;
- break;
- }
+ // Mode needs a parameter but there wasn't one
+ modelist.erase(i--, 1);
+ continue;
}
+
+ newparms.push_back(value);
}
- if (modechar)
- modelist[i] = modechar;
- else
- modelist.erase(i--, 1);
+
+ modelist[i] = mh->GetModeChar();
}
else if (mh && mh->GetNumParams(adding) && param_at < parameters.size())
{
@@ -197,7 +178,7 @@ class ModuleNamedModes : public Module
}
}
newparms[1] = modelist;
- ServerInstance->Modes->Process(newparms, source, false);
+ ServerInstance->Modes->Process(newparms, source);
return MOD_RES_DENY;
}
};
diff --git a/src/modules/m_namesx.cpp b/src/modules/m_namesx.cpp
index 82d311773..f211b01d8 100644
--- a/src/modules/m_namesx.cpp
+++ b/src/modules/m_namesx.cpp
@@ -21,40 +21,27 @@
#include "inspircd.h"
-#include "m_cap.h"
-
-/* $ModDesc: Provides the NAMESX (CAP multi-prefix) capability. */
+#include "modules/cap.h"
class ModuleNamesX : public Module
{
- public:
GenericCap cap;
+ public:
ModuleNamesX() : cap(this, "multi-prefix")
{
}
- void init()
- {
- Implementation eventlist[] = { I_OnPreCommand, I_OnNamesListItem, I_On005Numeric, I_OnEvent, I_OnSendWhoLine };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
-
- ~ModuleNamesX()
- {
- }
-
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides the NAMESX (CAP multi-prefix) capability.",VF_VENDOR);
}
- void On005Numeric(std::string &output)
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
- output.append(" NAMESX");
+ tokens["NAMESX"];
}
- ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line)
+ ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line) CXX11_OVERRIDE
{
/* We don't actually create a proper command handler class for PROTOCTL,
* because other modules might want to have PROTOCTL hooks too.
@@ -72,21 +59,17 @@ class ModuleNamesX : public Module
return MOD_RES_PASSTHRU;
}
- void OnNamesListItem(User* issuer, Membership* memb, std::string &prefixes, std::string &nick)
+ ModResult OnNamesListItem(User* issuer, Membership* memb, std::string& prefixes, std::string& nick) CXX11_OVERRIDE
{
- if (!cap.ext.get(issuer))
- return;
-
- /* Some module hid this from being displayed, dont bother */
- if (nick.empty())
- return;
+ if (cap.ext.get(issuer))
+ prefixes = memb->GetAllPrefixChars();
- prefixes = memb->chan->GetAllPrefixChars(memb->user);
+ return MOD_RES_PASSTHRU;
}
- void OnSendWhoLine(User* source, const std::vector<std::string>& params, User* user, std::string& line)
+ void OnSendWhoLine(User* source, const std::vector<std::string>& params, User* user, Membership* memb, std::string& line) CXX11_OVERRIDE
{
- if (!cap.ext.get(source))
+ if ((!memb) || (!cap.ext.get(source)))
return;
// Channel names can contain ":", and ":" as a 'start-of-token' delimiter is
@@ -101,20 +84,10 @@ class ModuleNamesX : public Module
return;
// 352 21DAAAAAB #chan ident localhost insp21.test 21DAAAAAB H@ :0 a
- // a b pos
- std::string::size_type a = 4 + source->nick.length() + 1;
- std::string::size_type b = line.find(' ', a);
- if (b == std::string::npos)
- return;
-
- // Try to find this channel
- std::string channame = line.substr(a, b-a);
- Channel* chan = ServerInstance->FindChan(channame);
- if (!chan)
- return;
+ // pos
// Don't do anything if the user has only one prefix
- std::string prefixes = chan->GetAllPrefixChars(user);
+ std::string prefixes = memb->GetAllPrefixChars();
if (prefixes.length() <= 1)
return;
@@ -122,7 +95,7 @@ class ModuleNamesX : public Module
line.insert(pos, prefixes);
}
- void OnEvent(Event& ev)
+ void OnEvent(Event& ev) CXX11_OVERRIDE
{
cap.HandleEvent(ev);
}
diff --git a/src/modules/m_nationalchars.cpp b/src/modules/m_nationalchars.cpp
index b43b6e2b6..0650cb3d0 100644
--- a/src/modules/m_nationalchars.cpp
+++ b/src/modules/m_nationalchars.cpp
@@ -26,17 +26,12 @@
by Chernov-Phoenix Alexey (Phoenix@RusNet) mailto:phoenix /email address separator/ pravmail.ru */
#include "inspircd.h"
-#include "caller.h"
#include <fstream>
-/* $ModDesc: Provides an ability to have non-RFC1459 nicks & support for national CASEMAPPING */
-
-class lwbNickHandler : public HandlerBase2<bool, const char*, size_t>
+class lwbNickHandler : public HandlerBase1<bool, const std::string&>
{
public:
- lwbNickHandler() { }
- virtual ~lwbNickHandler() { }
- virtual bool Call(const char*, size_t);
+ bool Call(const std::string&);
};
/*,m_reverse_additionalUp[256];*/
@@ -71,11 +66,12 @@ char utf8size(unsigned char * mb)
/* Conditions added */
-bool lwbNickHandler::Call(const char* n, size_t max)
+bool lwbNickHandler::Call(const std::string& nick)
{
- if (!n || !*n)
+ if (nick.empty())
return false;
+ const char* n = nick.c_str();
unsigned int p = 0;
for (const char* i = n; *i; i++, p++)
{
@@ -215,17 +211,16 @@ bool lwbNickHandler::Call(const char* n, size_t max)
}
/* too long? or not -- pointer arithmetic rocks */
- return (p < max);
+ return (p < ServerInstance->Config->Limits.NickMax);
}
class ModuleNationalChars : public Module
{
- private:
lwbNickHandler myhandler;
std::string charset, casemapping;
unsigned char m_additional[256], m_additionalUp[256], m_lower[256], m_upper[256];
- caller2<bool, const char*, size_t> rememberer;
+ caller1<bool, const std::string&> rememberer;
bool forcequit;
const unsigned char * lowermap_rememberer;
@@ -235,26 +230,20 @@ class ModuleNationalChars : public Module
{
}
- void init()
+ void init() CXX11_OVERRIDE
{
memcpy(m_lower, rfc_case_insensitive_map, 256);
national_case_insensitive_map = m_lower;
ServerInstance->IsNick = &myhandler;
-
- Implementation eventlist[] = { I_OnRehash, I_On005Numeric };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- OnRehash(NULL);
}
- virtual void On005Numeric(std::string &output)
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
- std::string tmp(casemapping);
- tmp.insert(0, "CASEMAPPING=");
- SearchAndReplace(output, std::string("CASEMAPPING=rfc1459"), tmp);
+ tokens["CASEMAPPING"] = casemapping;
}
- virtual void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ConfigTag* tag = ServerInstance->Config->ConfValue("nationalchars");
charset = tag->getString("file");
@@ -272,23 +261,24 @@ class ModuleNationalChars : public Module
if (!forcequit)
return;
- for (LocalUserList::const_iterator iter = ServerInstance->Users->local_users.begin(); iter != ServerInstance->Users->local_users.end(); ++iter)
+ const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers();
+ for (UserManager::LocalList::const_iterator iter = list.begin(); iter != list.end(); ++iter)
{
/* Fix by Brain: Dont quit UID users */
User* n = *iter;
- if (!isdigit(n->nick[0]) && !ServerInstance->IsNick(n->nick.c_str(), ServerInstance->Config->Limits.NickMax))
+ if (!isdigit(n->nick[0]) && !ServerInstance->IsNick(n->nick))
ServerInstance->Users->QuitUser(n, message);
}
}
- virtual ~ModuleNationalChars()
+ ~ModuleNationalChars()
{
ServerInstance->IsNick = rememberer;
national_case_insensitive_map = lowermap_rememberer;
CheckForceQuit("National characters module unloaded");
}
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides an ability to have non-RFC1459 nicks & support for national CASEMAPPING", VF_VENDOR | VF_COMMON, charset);
}
@@ -304,10 +294,10 @@ class ModuleNationalChars : public Module
/*so Bynets Unreal distribution stuff*/
void loadtables(std::string filename, unsigned char ** tables, unsigned char cnt, char faillimit)
{
- std::ifstream ifs(filename.c_str());
+ std::ifstream ifs(ServerInstance->Config->Paths.PrependConfig(filename).c_str());
if (ifs.fail())
{
- ServerInstance->Logs->Log("m_nationalchars",DEFAULT,"loadtables() called for missing file: %s", filename.c_str());
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "loadtables() called for missing file: %s", filename.c_str());
return;
}
@@ -322,7 +312,7 @@ class ModuleNationalChars : public Module
{
if (loadtable(ifs, tables[n], 255) && (n < faillimit))
{
- ServerInstance->Logs->Log("m_nationalchars",DEFAULT,"loadtables() called for illegal file: %s (line %d)", filename.c_str(), n+1);
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "loadtables() called for illegal file: %s (line %d)", filename.c_str(), n+1);
return;
}
}
diff --git a/src/modules/m_nickflood.cpp b/src/modules/m_nickflood.cpp
index 04d7c8b5e..cade0b1db 100644
--- a/src/modules/m_nickflood.cpp
+++ b/src/modules/m_nickflood.cpp
@@ -20,8 +20,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides channel mode +F (nick flood protection) */
-
/** Holds settings and state associated with channel mode +F
*/
class nickfloodsettings
@@ -80,53 +78,41 @@ class nickfloodsettings
/** Handles channel mode +F
*/
-class NickFlood : public ModeHandler
+class NickFlood : public ParamMode<NickFlood, SimpleExtItem<nickfloodsettings> >
{
public:
- SimpleExtItem<nickfloodsettings> ext;
- NickFlood(Module* Creator) : ModeHandler(Creator, "nickflood", 'F', PARAM_SETONLY, MODETYPE_CHANNEL),
- ext("nickflood", Creator) { }
+ NickFlood(Module* Creator)
+ : ParamMode<NickFlood, SimpleExtItem<nickfloodsettings> >(Creator, "nickflood", 'F')
+ {
+ }
- ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
+ ModeAction OnSet(User* source, Channel* channel, std::string& parameter)
{
- if (adding)
+ std::string::size_type colon = parameter.find(':');
+ if ((colon == std::string::npos) || (parameter.find('-') != std::string::npos))
{
- std::string::size_type colon = parameter.find(':');
- if ((colon == std::string::npos) || (parameter.find('-') != std::string::npos))
- {
- source->WriteNumeric(608, "%s %s :Invalid flood parameter",source->nick.c_str(),channel->name.c_str());
- return MODEACTION_DENY;
- }
-
- /* Set up the flood parameters for this channel */
- unsigned int nnicks = ConvToInt(parameter.substr(0, colon));
- unsigned int nsecs = ConvToInt(parameter.substr(colon+1));
-
- if ((nnicks<1) || (nsecs<1))
- {
- source->WriteNumeric(608, "%s %s :Invalid flood parameter",source->nick.c_str(),channel->name.c_str());
- return MODEACTION_DENY;
- }
+ source->WriteNumeric(608, "%s :Invalid flood parameter",channel->name.c_str());
+ return MODEACTION_DENY;
+ }
- nickfloodsettings* f = ext.get(channel);
- if ((f) && (nnicks == f->nicks) && (nsecs == f->secs))
- // mode params match
- return MODEACTION_DENY;
+ /* Set up the flood parameters for this channel */
+ unsigned int nnicks = ConvToInt(parameter.substr(0, colon));
+ unsigned int nsecs = ConvToInt(parameter.substr(colon+1));
- ext.set(channel, new nickfloodsettings(nsecs, nnicks));
- parameter = ConvToStr(nnicks) + ":" + ConvToStr(nsecs);
- channel->SetModeParam('F', parameter);
- return MODEACTION_ALLOW;
- }
- else
+ if ((nnicks<1) || (nsecs<1))
{
- if (!channel->IsModeSet('F'))
- return MODEACTION_DENY;
-
- ext.unset(channel);
- channel->SetModeParam('F', "");
- return MODEACTION_ALLOW;
+ source->WriteNumeric(608, "%s :Invalid flood parameter",channel->name.c_str());
+ return MODEACTION_DENY;
}
+
+ ext.set(channel, new nickfloodsettings(nsecs, nnicks));
+ return MODEACTION_ALLOW;
+ }
+
+ void SerializeParam(Channel* chan, const nickfloodsettings* nfs, std::string& out)
+ {
+ out.append(ConvToStr(nfs->nicks)).push_back(':');
+ out.append(ConvToStr(nfs->secs));
}
};
@@ -135,28 +121,16 @@ class ModuleNickFlood : public Module
NickFlood nf;
public:
-
ModuleNickFlood()
: nf(this)
{
}
- void init()
- {
- ServerInstance->Modules->AddService(nf);
- ServerInstance->Modules->AddService(nf.ext);
- Implementation eventlist[] = { I_OnUserPreNick, I_OnUserPostNick };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- ModResult OnUserPreNick(User* user, const std::string &newnick)
+ ModResult OnUserPreNick(LocalUser* user, const std::string& newnick) CXX11_OVERRIDE
{
- if (ServerInstance->NICKForced.get(user)) /* Allow forced nick changes */
- return MOD_RES_PASSTHRU;
-
- for (UCListIter i = user->chans.begin(); i != user->chans.end(); i++)
+ for (User::ChanList::iterator i = user->chans.begin(); i != user->chans.end(); i++)
{
- Channel *channel = *i;
+ Channel* channel = (*i)->chan;
ModResult res;
nickfloodsettings *f = nf.ext.get(channel);
@@ -168,7 +142,7 @@ class ModuleNickFlood : public Module
if (f->islocked())
{
- user->WriteNumeric(447, "%s :%s has been locked for nickchanges for 60 seconds because there have been more than %u nick changes in %u seconds", user->nick.c_str(), channel->name.c_str(), f->nicks, f->secs);
+ user->WriteNumeric(ERR_CANTCHANGENICK, ":%s has been locked for nickchanges for 60 seconds because there have been more than %u nick changes in %u seconds", channel->name.c_str(), f->nicks, f->secs);
return MOD_RES_DENY;
}
@@ -188,14 +162,14 @@ class ModuleNickFlood : public Module
/*
* XXX: HACK: We do the increment on the *POST* event here (instead of all together) because we have no way of knowing whether other modules would block a nickchange.
*/
- void OnUserPostNick(User* user, const std::string &oldnick)
+ void OnUserPostNick(User* user, const std::string &oldnick) CXX11_OVERRIDE
{
if (isdigit(user->nick[0])) /* allow switches to UID */
return;
- for (UCListIter i = user->chans.begin(); i != user->chans.end(); ++i)
+ for (User::ChanList::iterator i = user->chans.begin(); i != user->chans.end(); ++i)
{
- Channel *channel = *i;
+ Channel* channel = (*i)->chan;
ModResult res;
nickfloodsettings *f = nf.ext.get(channel);
@@ -214,11 +188,7 @@ class ModuleNickFlood : public Module
}
}
- ~ModuleNickFlood()
- {
- }
-
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Channel mode F - nick flood protection", VF_VENDOR);
}
diff --git a/src/modules/m_nicklock.cpp b/src/modules/m_nicklock.cpp
index 4f5e5941c..9bf16498a 100644
--- a/src/modules/m_nicklock.cpp
+++ b/src/modules/m_nicklock.cpp
@@ -22,8 +22,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides the NICKLOCK command, allows an oper to change a users nick and lock them to it until they quit */
-
/** Handle /NICKLOCK
*/
class CommandNicklock : public Command
@@ -35,7 +33,7 @@ class CommandNicklock : public Command
{
flags_needed = 'o';
syntax = "<oldnick> <newnick>";
- TRANSLATE3(TR_NICK, TR_TEXT, TR_END);
+ TRANSLATE2(TR_NICK, TR_TEXT);
}
CmdResult Handle(const std::vector<std::string>& parameters, User *user)
@@ -44,20 +42,20 @@ class CommandNicklock : public Command
if ((!target) || (target->registered != REG_ALL))
{
- user->WriteServ("NOTICE %s :*** No such nickname: '%s'", user->nick.c_str(), parameters[0].c_str());
+ user->WriteNotice("*** No such nickname: '" + parameters[0] + "'");
return CMD_FAILURE;
}
/* Do local sanity checks and bails */
if (IS_LOCAL(user))
{
- if (!ServerInstance->IsNick(parameters[1].c_str(), ServerInstance->Config->Limits.NickMax))
+ if (!ServerInstance->IsNick(parameters[1]))
{
- user->WriteServ("NOTICE %s :*** Invalid nickname '%s'", user->nick.c_str(), parameters[1].c_str());
+ user->WriteNotice("*** Invalid nickname '" + parameters[1] + "'");
return CMD_FAILURE;
}
- user->WriteServ("947 %s %s :Nickname now locked.", user->nick.c_str(), parameters[1].c_str());
+ user->WriteNumeric(947, "%s :Nickname now locked.", parameters[1].c_str());
}
/* If we made it this far, extend the user */
@@ -66,7 +64,7 @@ class CommandNicklock : public Command
locked.set(target, 1);
std::string oldnick = target->nick;
- if (target->ForceNickChange(parameters[1].c_str()))
+ if (target->ChangeNick(parameters[1]))
ServerInstance->SNO->WriteGlobalSno('a', user->nick+" used NICKLOCK to change and hold "+oldnick+" to "+parameters[1]);
else
{
@@ -98,7 +96,7 @@ class CommandNickunlock : public Command
{
flags_needed = 'o';
syntax = "<locked-nick>";
- TRANSLATE2(TR_NICK, TR_END);
+ TRANSLATE1(TR_NICK);
}
CmdResult Handle (const std::vector<std::string>& parameters, User *user)
@@ -107,7 +105,7 @@ class CommandNickunlock : public Command
if (!target)
{
- user->WriteServ("NOTICE %s :*** No such nickname: '%s'", user->nick.c_str(), parameters[0].c_str());
+ user->WriteNotice("*** No such nickname: '" + parameters[0] + "'");
return CMD_FAILURE;
}
@@ -139,7 +137,6 @@ class CommandNickunlock : public Command
}
};
-
class ModuleNickLock : public Module
{
LocalIntExt locked;
@@ -151,34 +148,16 @@ class ModuleNickLock : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cmd1);
- ServerInstance->Modules->AddService(cmd2);
- ServerInstance->Modules->AddService(locked);
- ServerInstance->Modules->Attach(I_OnUserPreNick, this);
- }
-
- ~ModuleNickLock()
- {
- }
-
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides the NICKLOCK command, allows an oper to change a users nick and lock them to it until they quit", VF_OPTCOMMON | VF_VENDOR);
}
- ModResult OnUserPreNick(User* user, const std::string &newnick)
+ ModResult OnUserPreNick(LocalUser* user, const std::string& newnick) CXX11_OVERRIDE
{
- if (!IS_LOCAL(user))
- return MOD_RES_PASSTHRU;
-
- if (ServerInstance->NICKForced.get(user)) /* Allow forced nick changes */
- return MOD_RES_PASSTHRU;
-
if (locked.get(user))
{
- user->WriteNumeric(447, "%s :You cannot change your nickname (your nick is locked)",user->nick.c_str());
+ user->WriteNumeric(ERR_CANTCHANGENICK, ":You cannot change your nickname (your nick is locked)");
return MOD_RES_DENY;
}
return MOD_RES_PASSTHRU;
diff --git a/src/modules/m_noctcp.cpp b/src/modules/m_noctcp.cpp
index 1dd6fe34a..953557d90 100644
--- a/src/modules/m_noctcp.cpp
+++ b/src/modules/m_noctcp.cpp
@@ -21,8 +21,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides channel mode +C to block CTCPs */
-
class NoCTCP : public SimpleChannelModeHandler
{
public:
@@ -31,38 +29,20 @@ class NoCTCP : public SimpleChannelModeHandler
class ModuleNoCTCP : public Module
{
-
NoCTCP nc;
public:
-
ModuleNoCTCP()
: nc(this)
{
}
- void init()
- {
- ServerInstance->Modules->AddService(nc);
- Implementation eventlist[] = { I_OnUserPreMessage, I_OnUserPreNotice, I_On005Numeric };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- virtual ~ModuleNoCTCP()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides channel mode +C to block CTCPs", VF_VENDOR);
}
- virtual ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
- {
- return OnUserPreNotice(user,dest,target_type,text,status,exempt_list);
- }
-
- virtual ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+ ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE
{
if ((target_type == TYPE_CHANNEL) && (IS_LOCAL(user)))
{
@@ -74,18 +54,18 @@ class ModuleNoCTCP : public Module
if (res == MOD_RES_ALLOW)
return MOD_RES_PASSTHRU;
- if (!c->GetExtBanStatus(user, 'C').check(!c->IsModeSet('C')))
+ if (!c->GetExtBanStatus(user, 'C').check(!c->IsModeSet(nc)))
{
- user->WriteNumeric(ERR_NOCTCPALLOWED, "%s %s :Can't send CTCP to channel (+C set)",user->nick.c_str(), c->name.c_str());
+ user->WriteNumeric(ERR_NOCTCPALLOWED, "%s :Can't send CTCP to channel (+C set)", c->name.c_str());
return MOD_RES_DENY;
}
}
return MOD_RES_PASSTHRU;
}
- virtual void On005Numeric(std::string &output)
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
- ServerInstance->AddExtBanChar('C');
+ tokens["EXTBAN"].push_back('C');
}
};
diff --git a/src/modules/m_nokicks.cpp b/src/modules/m_nokicks.cpp
index 1f58a2e08..0acf84118 100644
--- a/src/modules/m_nokicks.cpp
+++ b/src/modules/m_nokicks.cpp
@@ -22,8 +22,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides channel mode +Q to prevent kicks on the channel. */
-
class NoKicks : public SimpleChannelModeHandler
{
public:
@@ -40,38 +38,26 @@ class ModuleNoKicks : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(nk);
- Implementation eventlist[] = { I_OnUserPreKick, I_On005Numeric };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- void On005Numeric(std::string &output)
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
- ServerInstance->AddExtBanChar('Q');
+ tokens["EXTBAN"].push_back('Q');
}
- ModResult OnUserPreKick(User* source, Membership* memb, const std::string &reason)
+ ModResult OnUserPreKick(User* source, Membership* memb, const std::string &reason) CXX11_OVERRIDE
{
- if (!memb->chan->GetExtBanStatus(source, 'Q').check(!memb->chan->IsModeSet('Q')))
+ if (!memb->chan->GetExtBanStatus(source, 'Q').check(!memb->chan->IsModeSet(nk)))
{
// Can't kick with Q in place, not even opers with override, and founders
- source->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Can't kick user %s from channel (+Q set)",source->nick.c_str(), memb->chan->name.c_str(), memb->user->nick.c_str());
+ source->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s :Can't kick user %s from channel (+Q set)", memb->chan->name.c_str(), memb->user->nick.c_str());
return MOD_RES_DENY;
}
return MOD_RES_PASSTHRU;
}
- ~ModuleNoKicks()
- {
- }
-
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides channel mode +Q to prevent kicks on the channel.", VF_VENDOR);
}
};
-
MODULE_INIT(ModuleNoKicks)
diff --git a/src/modules/m_nonicks.cpp b/src/modules/m_nonicks.cpp
index 672a48f8d..63815f2bf 100644
--- a/src/modules/m_nonicks.cpp
+++ b/src/modules/m_nonicks.cpp
@@ -21,8 +21,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides support for channel mode +N & extban +b N: which prevents nick changes on channel */
-
class NoNicks : public SimpleChannelModeHandler
{
public:
@@ -38,54 +36,34 @@ class ModuleNoNickChange : public Module
{
}
- void init()
- {
- OnRehash(NULL);
- ServerInstance->Modules->AddService(nn);
- Implementation eventlist[] = { I_OnUserPreNick, I_On005Numeric, I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- virtual ~ModuleNoNickChange()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for channel mode +N & extban +b N: which prevents nick changes on channel", VF_VENDOR);
}
-
- virtual void On005Numeric(std::string &output)
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
- ServerInstance->AddExtBanChar('N');
+ tokens["EXTBAN"].push_back('N');
}
- virtual ModResult OnUserPreNick(User* user, const std::string &newnick)
+ ModResult OnUserPreNick(LocalUser* user, const std::string& newnick) CXX11_OVERRIDE
{
- if (!IS_LOCAL(user))
- return MOD_RES_PASSTHRU;
-
- // Allow forced nick changes.
- if (ServerInstance->NICKForced.get(user))
- return MOD_RES_PASSTHRU;
-
- for (UCListIter i = user->chans.begin(); i != user->chans.end(); i++)
+ for (User::ChanList::iterator i = user->chans.begin(); i != user->chans.end(); i++)
{
- Channel* curr = *i;
+ Channel* curr = (*i)->chan;
ModResult res = ServerInstance->OnCheckExemption(user,curr,"nonick");
if (res == MOD_RES_ALLOW)
continue;
- if (override && IS_OPER(user))
+ if (override && user->IsOper())
continue;
- if (!curr->GetExtBanStatus(user, 'N').check(!curr->IsModeSet('N')))
+ if (!curr->GetExtBanStatus(user, 'N').check(!curr->IsModeSet(nn)))
{
- user->WriteNumeric(ERR_CANTCHANGENICK, "%s :Can't change nickname while on %s (+N is set)",
- user->nick.c_str(), curr->name.c_str());
+ user->WriteNumeric(ERR_CANTCHANGENICK, ":Can't change nickname while on %s (+N is set)",
+ curr->name.c_str());
return MOD_RES_DENY;
}
}
@@ -93,7 +71,7 @@ class ModuleNoNickChange : public Module
return MOD_RES_PASSTHRU;
}
- virtual void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
override = ServerInstance->Config->ConfValue("nonicks")->getBool("operoverride", false);
}
diff --git a/src/modules/m_nonotice.cpp b/src/modules/m_nonotice.cpp
index c5b9f3a1c..cab367ad9 100644
--- a/src/modules/m_nonotice.cpp
+++ b/src/modules/m_nonotice.cpp
@@ -21,8 +21,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides channel mode +T to block notices to the channel */
-
class NoNotice : public SimpleChannelModeHandler
{
public:
@@ -39,32 +37,25 @@ class ModuleNoNotice : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(nt);
- Implementation eventlist[] = { I_OnUserPreNotice, I_On005Numeric };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- virtual void On005Numeric(std::string &output)
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
- ServerInstance->AddExtBanChar('T');
+ tokens["EXTBAN"].push_back('T');
}
- virtual ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+ ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE
{
ModResult res;
- if ((target_type == TYPE_CHANNEL) && (IS_LOCAL(user)))
+ if ((msgtype == MSG_NOTICE) && (target_type == TYPE_CHANNEL) && (IS_LOCAL(user)))
{
Channel* c = (Channel*)dest;
- if (!c->GetExtBanStatus(user, 'T').check(!c->IsModeSet('T')))
+ if (!c->GetExtBanStatus(user, 'T').check(!c->IsModeSet(nt)))
{
res = ServerInstance->OnCheckExemption(user,c,"nonotice");
if (res == MOD_RES_ALLOW)
return MOD_RES_PASSTHRU;
else
{
- user->WriteNumeric(ERR_CANNOTSENDTOCHAN, "%s %s :Can't send NOTICE to channel (+T set)",user->nick.c_str(), c->name.c_str());
+ user->WriteNumeric(ERR_CANNOTSENDTOCHAN, "%s :Can't send NOTICE to channel (+T set)", c->name.c_str());
return MOD_RES_DENY;
}
}
@@ -72,11 +63,7 @@ class ModuleNoNotice : public Module
return MOD_RES_PASSTHRU;
}
- virtual ~ModuleNoNotice()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides channel mode +T to block notices to the channel", VF_VENDOR);
}
diff --git a/src/modules/m_nopartmsg.cpp b/src/modules/m_nopartmsg.cpp
index ad3413101..7aeb66920 100644
--- a/src/modules/m_nopartmsg.cpp
+++ b/src/modules/m_nopartmsg.cpp
@@ -19,45 +19,27 @@
#include "inspircd.h"
-/* $ModDesc: Implements extban +b p: - part message bans */
-
class ModulePartMsgBan : public Module
{
- private:
public:
- void init()
- {
- Implementation eventlist[] = { I_OnUserPart, I_On005Numeric };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- virtual ~ModulePartMsgBan()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Implements extban +b p: - part message bans", VF_OPTCOMMON|VF_VENDOR);
}
-
- virtual void OnUserPart(Membership* memb, std::string &partmessage, CUList& excepts)
+ void OnUserPart(Membership* memb, std::string &partmessage, CUList& excepts) CXX11_OVERRIDE
{
if (!IS_LOCAL(memb->user))
return;
if (memb->chan->GetExtBanStatus(memb->user, 'p') == MOD_RES_DENY)
partmessage.clear();
-
- return;
}
- virtual void On005Numeric(std::string &output)
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
- ServerInstance->AddExtBanChar('p');
+ tokens["EXTBAN"].push_back('p');
}
};
-
MODULE_INIT(ModulePartMsgBan)
-
diff --git a/src/modules/m_ojoin.cpp b/src/modules/m_ojoin.cpp
index 026d98f86..120715429 100644
--- a/src/modules/m_ojoin.cpp
+++ b/src/modules/m_ojoin.cpp
@@ -1,6 +1,7 @@
/*
* InspIRCd -- Internet Relay Chat Daemon
*
+ * Copyright (C) 2009 Taros <taros34@hotmail.com>
* Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
*
* This file is part of InspIRCd. InspIRCd is free software: you can
@@ -16,57 +17,38 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
-/*
- * Written for InspIRCd-1.2 by Taros on the Tel'Laerad M&D Team
- * <http://tellaerad.net>
- */
-
#include "inspircd.h"
-/* $ModConfig: <ojoin prefix="!" notice="yes" op="yes">
- * Specify the prefix that +Y will grant here, it should be unused.
- * Leave prefix empty if you do not wish +Y to grant a prefix
- * If notice is set to on, upon ojoin, the server will notice
- * the channel saying that the oper is joining on network business
- * If op is set to on, it will give them +o along with +Y */
-/* $ModDesc: Provides the /ojoin command, which joins a user to a channel on network business, and gives them +Y, which makes them immune to kick / deop and so on. */
-/* $ModAuthor: Taros */
-/* $ModAuthorMail: taros34@hotmail.com */
-
-/* A note: This will not protect against kicks from services,
- * ulines, or operoverride. */
-
#define NETWORK_VALUE 9000000
-char NPrefix;
-bool notice;
-bool op;
-
/** Handle /OJOIN
*/
-class CommandOjoin : public Command
+class CommandOjoin : public SplitCommand
{
public:
bool active;
- CommandOjoin(Module* parent) : Command(parent,"OJOIN", 1)
+ bool notice;
+ bool op;
+ ModeHandler* npmh;
+ CommandOjoin(Module* parent) :
+ SplitCommand(parent, "OJOIN", 1)
{
flags_needed = 'o'; Penalty = 0; syntax = "<channel>";
active = false;
- TRANSLATE3(TR_NICK, TR_TEXT, TR_END);
}
- CmdResult Handle (const std::vector<std::string>& parameters, User *user)
+ CmdResult HandleLocal(const std::vector<std::string>& parameters, LocalUser* user)
{
// Make sure the channel name is allowable.
- if (!ServerInstance->IsChannel(parameters[0].c_str(), ServerInstance->Config->Limits.ChanMax))
+ if (!ServerInstance->IsChannel(parameters[0]))
{
- user->WriteServ("NOTICE "+user->nick+" :*** Invalid characters in channel name or name too long");
+ user->WriteNotice("*** Invalid characters in channel name or name too long");
return CMD_FAILURE;
}
active = true;
- Channel* channel = Channel::JoinUser(user, parameters[0].c_str(), false, "", false);
+ // override is false because we want OnUserPreJoin to run
+ Channel* channel = Channel::JoinUser(user, parameters[0], false);
active = false;
if (channel)
@@ -86,11 +68,14 @@ class CommandOjoin : public Command
// they're already in the channel
std::vector<std::string> modes;
modes.push_back(parameters[0]);
- modes.push_back(op ? "+Yo" : "+Y");
- modes.push_back(user->nick);
+ modes.push_back(std::string("+") + npmh->GetModeChar());
if (op)
+ {
+ modes[1].push_back('o');
modes.push_back(user->nick);
- ServerInstance->SendGlobalMode(modes, ServerInstance->FakeClient);
+ }
+ modes.push_back(user->nick);
+ ServerInstance->Modes->Process(modes, ServerInstance->FakeClient);
}
return CMD_SUCCESS;
}
@@ -98,54 +83,15 @@ class CommandOjoin : public Command
/** channel mode +Y
*/
-class NetworkPrefix : public ModeHandler
+class NetworkPrefix : public PrefixMode
{
public:
- NetworkPrefix(Module* parent) : ModeHandler(parent, "official-join", 'Y', PARAM_ALWAYS, MODETYPE_CHANNEL)
+ NetworkPrefix(Module* parent, char NPrefix)
+ : PrefixMode(parent, "official-join", 'Y')
{
- list = true;
prefix = NPrefix;
levelrequired = INT_MAX;
- m_paramtype = TR_NICK;
- }
-
- void RemoveMode(Channel* channel, irc::modestacker* stack)
- {
- const UserMembList* cl = channel->GetUsers();
- std::vector<std::string> mode_junk;
- mode_junk.push_back(channel->name);
- irc::modestacker modestack(false);
- std::deque<std::string> stackresult;
-
- for (UserMembCIter i = cl->begin(); i != cl->end(); i++)
- {
- if (i->second->hasMode('Y'))
- {
- if (stack)
- stack->Push(this->GetModeChar(), i->first->nick);
- else
- modestack.Push(this->GetModeChar(), i->first->nick);
- }
- }
-
- if (stack)
- return;
-
- while (modestack.GetStackedLine(stackresult))
- {
- mode_junk.insert(mode_junk.end(), stackresult.begin(), stackresult.end());
- ServerInstance->SendMode(mode_junk, ServerInstance->FakeClient);
- mode_junk.erase(mode_junk.begin() + 1, mode_junk.end());
- }
- }
-
- unsigned int GetPrefixRank()
- {
- return NETWORK_VALUE;
- }
-
- void RemoveMode(User* user, irc::modestacker* stack)
- {
+ prefixrank = NETWORK_VALUE;
}
ModResult AccessCheck(User* source, Channel* channel, std::string &parameter, bool adding)
@@ -157,12 +103,6 @@ class NetworkPrefix : public ModeHandler
return MOD_RES_PASSTHRU;
}
-
- ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
- {
- return MODEACTION_ALLOW;
- }
-
};
class ModuleOjoin : public Module
@@ -177,27 +117,26 @@ class ModuleOjoin : public Module
{
}
- void init()
+ void init() CXX11_OVERRIDE
{
- /* Load config stuff */
- OnRehash(NULL);
+ std::string npre = ServerInstance->Config->ConfValue("ojoin")->getString("prefix");
+ char NPrefix = npre.empty() ? 0 : npre[0];
+ if (NPrefix && ServerInstance->Modes->FindPrefix(NPrefix))
+ throw ModuleException("Looks like the prefix you picked for m_ojoin is already in use. Pick another.");
/* Initialise module variables */
- np = new NetworkPrefix(this);
+ np = new NetworkPrefix(this, NPrefix);
+ mycommand.npmh = np;
ServerInstance->Modules->AddService(*np);
- ServerInstance->Modules->AddService(mycommand);
-
- Implementation eventlist[] = { I_OnUserPreJoin, I_OnUserPreKick, I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
}
- ModResult OnUserPreJoin(User *user, Channel *chan, const char *cname, std::string &privs, const std::string &keygiven)
+ ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE
{
if (mycommand.active)
{
- privs += 'Y';
- if (op)
+ privs += np->GetModeChar();
+ if (mycommand.op)
privs += 'o';
return MOD_RES_ALLOW;
}
@@ -205,35 +144,24 @@ class ModuleOjoin : public Module
return MOD_RES_PASSTHRU;
}
- void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ConfigTag* Conf = ServerInstance->Config->ConfValue("ojoin");
-
- if (!np)
- {
- // This is done on module load only
- std::string npre = Conf->getString("prefix");
- NPrefix = npre.empty() ? 0 : npre[0];
-
- if (NPrefix && ServerInstance->Modes->FindPrefix(NPrefix))
- throw ModuleException("Looks like the +Y prefix you picked for m_ojoin is already in use. Pick another.");
- }
-
- notice = Conf->getBool("notice", true);
- op = Conf->getBool("op", true);
+ mycommand.notice = Conf->getBool("notice", true);
+ mycommand.op = Conf->getBool("op", true);
}
- ModResult OnUserPreKick(User* source, Membership* memb, const std::string &reason)
+ ModResult OnUserPreKick(User* source, Membership* memb, const std::string &reason) CXX11_OVERRIDE
{
// Don't do anything if they're not +Y
- if (!memb->hasMode('Y'))
+ if (!memb->hasMode(np->GetModeChar()))
return MOD_RES_PASSTHRU;
// Let them do whatever they want to themselves.
if (source == memb->user)
return MOD_RES_PASSTHRU;
- source->WriteNumeric(484, source->nick+" "+memb->chan->name+" :Can't kick "+memb->user->nick+" as they're on official network business.");
+ source->WriteNumeric(ERR_RESTRICTED, memb->chan->name+" :Can't kick "+memb->user->nick+" as they're on official network business.");
return MOD_RES_DENY;
}
@@ -247,11 +175,10 @@ class ModuleOjoin : public Module
ServerInstance->Modules->SetPriority(this, I_OnUserPreJoin, PRIORITY_FIRST);
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Network Business Join", VF_VENDOR);
}
};
MODULE_INIT(ModuleOjoin)
-
diff --git a/src/modules/m_operchans.cpp b/src/modules/m_operchans.cpp
index ca948d95b..3c6b4cd59 100644
--- a/src/modules/m_operchans.cpp
+++ b/src/modules/m_operchans.cpp
@@ -22,8 +22,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides support for oper-only chans via the +O channel mode */
-
class OperChans : public SimpleChannelModeHandler
{
public:
@@ -42,44 +40,33 @@ class ModuleOperChans : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(oc);
- Implementation eventlist[] = { I_OnCheckBan, I_On005Numeric, I_OnUserPreJoin };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven)
+ ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE
{
- if (chan && chan->IsModeSet('O') && !IS_OPER(user))
+ if (chan && chan->IsModeSet(oc) && !user->IsOper())
{
- user->WriteNumeric(ERR_CANTJOINOPERSONLY, "%s %s :Only IRC operators may join %s (+O is set)",
- user->nick.c_str(), chan->name.c_str(), chan->name.c_str());
+ user->WriteNumeric(ERR_CANTJOINOPERSONLY, "%s :Only IRC operators may join %s (+O is set)",
+ chan->name.c_str(), chan->name.c_str());
return MOD_RES_DENY;
}
return MOD_RES_PASSTHRU;
}
- ModResult OnCheckBan(User *user, Channel *c, const std::string& mask)
+ ModResult OnCheckBan(User *user, Channel *c, const std::string& mask) CXX11_OVERRIDE
{
if ((mask.length() > 2) && (mask[0] == 'O') && (mask[1] == ':'))
{
- if (IS_OPER(user) && InspIRCd::Match(user->oper->name, mask.substr(2)))
+ if (user->IsOper() && InspIRCd::Match(user->oper->name, mask.substr(2)))
return MOD_RES_DENY;
}
return MOD_RES_PASSTHRU;
}
- void On005Numeric(std::string &output)
- {
- ServerInstance->AddExtBanChar('O');
- }
-
- ~ModuleOperChans()
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
+ tokens["EXTBAN"].push_back('O');
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for oper-only chans via the +O channel mode and 'O' extban", VF_VENDOR);
}
diff --git a/src/modules/m_operjoin.cpp b/src/modules/m_operjoin.cpp
index bd77384a6..dd80d99ba 100644
--- a/src/modules/m_operjoin.cpp
+++ b/src/modules/m_operjoin.cpp
@@ -24,84 +24,44 @@
#include "inspircd.h"
-/* $ModDesc: Forces opers to join the specified channel(s) on oper-up */
-
class ModuleOperjoin : public Module
{
- private:
- std::string operChan;
std::vector<std::string> operChans;
bool override;
- int tokenize(const std::string &str, std::vector<std::string> &tokens)
- {
- // skip delimiters at beginning.
- std::string::size_type lastPos = str.find_first_not_of(",", 0);
- // find first "non-delimiter".
- std::string::size_type pos = str.find_first_of(",", lastPos);
-
- while (std::string::npos != pos || std::string::npos != lastPos)
- {
- // found a token, add it to the vector.
- tokens.push_back(str.substr(lastPos, pos - lastPos));
- // skip delimiters. Note the "not_of"
- lastPos = str.find_first_not_of(",", pos);
- // find next "non-delimiter"
- pos = str.find_first_of(",", lastPos);
- }
- return tokens.size();
- }
-
public:
- void init()
- {
- OnRehash(NULL);
- Implementation eventlist[] = { I_OnPostOper, I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
-
- virtual void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ConfigTag* tag = ServerInstance->Config->ConfValue("operjoin");
- operChan = tag->getString("channel");
override = tag->getBool("override", false);
+ irc::commasepstream ss(tag->getString("channel"));
operChans.clear();
- if (!operChan.empty())
- tokenize(operChan,operChans);
- }
- virtual ~ModuleOperjoin()
- {
+ for (std::string channame; ss.GetToken(channame); )
+ operChans.push_back(channame);
}
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Forces opers to join the specified channel(s) on oper-up", VF_VENDOR);
}
- virtual void OnPostOper(User* user, const std::string &opertype, const std::string &opername)
+ void OnPostOper(User* user, const std::string &opertype, const std::string &opername) CXX11_OVERRIDE
{
- if (!IS_LOCAL(user))
+ LocalUser* localuser = IS_LOCAL(user);
+ if (!localuser)
return;
- for(std::vector<std::string>::iterator it = operChans.begin(); it != operChans.end(); it++)
- if (ServerInstance->IsChannel(it->c_str(), ServerInstance->Config->Limits.ChanMax))
- Channel::JoinUser(user, it->c_str(), override, "", false, ServerInstance->Time());
+ for (std::vector<std::string>::const_iterator i = operChans.begin(); i != operChans.end(); ++i)
+ if (ServerInstance->IsChannel(*i))
+ Channel::JoinUser(localuser, *i, override);
- std::string chanList = IS_OPER(user)->getConfig("autojoin");
- if (!chanList.empty())
+ irc::commasepstream ss(localuser->oper->getConfig("autojoin"));
+ for (std::string channame; ss.GetToken(channame); )
{
- std::vector<std::string> typechans;
- tokenize(chanList, typechans);
- for (std::vector<std::string>::const_iterator it = typechans.begin(); it != typechans.end(); ++it)
- {
- if (ServerInstance->IsChannel(it->c_str(), ServerInstance->Config->Limits.ChanMax))
- {
- Channel::JoinUser(user, it->c_str(), override, "", false, ServerInstance->Time());
- }
- }
+ if (ServerInstance->IsChannel(channame))
+ Channel::JoinUser(localuser, channame, override);
}
}
};
diff --git a/src/modules/m_operlevels.cpp b/src/modules/m_operlevels.cpp
index 569defd49..ac7178a93 100644
--- a/src/modules/m_operlevels.cpp
+++ b/src/modules/m_operlevels.cpp
@@ -20,27 +20,20 @@
*/
-/* $ModDesc: Gives each oper type a 'level', cannot kill opers 'above' your level. */
-
#include "inspircd.h"
class ModuleOperLevels : public Module
{
public:
- void init()
- {
- ServerInstance->Modules->Attach(I_OnKill, this);
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Gives each oper type a 'level', cannot kill opers 'above' your level.", VF_VENDOR);
}
- virtual ModResult OnKill(User* source, User* dest, const std::string &reason)
+ ModResult OnKill(User* source, User* dest, const std::string &reason) CXX11_OVERRIDE
{
// oper killing an oper?
- if (IS_OPER(dest) && IS_OPER(source))
+ if (dest->IsOper() && source->IsOper())
{
std::string level = dest->oper->getConfig("level");
long dest_level = atol(level.c_str());
@@ -50,8 +43,8 @@ class ModuleOperLevels : public Module
if (dest_level > source_level)
{
if (IS_LOCAL(source)) ServerInstance->SNO->WriteGlobalSno('a', "Oper %s (level %ld) attempted to /kill a higher oper: %s (level %ld): Reason: %s",source->nick.c_str(),source_level,dest->nick.c_str(),dest_level,reason.c_str());
- dest->WriteServ("NOTICE %s :*** Oper %s attempted to /kill you!",dest->nick.c_str(),source->nick.c_str());
- source->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper %s is a higher level than you",source->nick.c_str(),dest->nick.c_str());
+ dest->WriteNotice("*** Oper " + source->nick + " attempted to /kill you!");
+ source->WriteNumeric(ERR_NOPRIVILEGES, ":Permission Denied - Oper %s is a higher level than you", dest->nick.c_str());
return MOD_RES_DENY;
}
}
@@ -60,4 +53,3 @@ class ModuleOperLevels : public Module
};
MODULE_INIT(ModuleOperLevels)
-
diff --git a/src/modules/m_operlog.cpp b/src/modules/m_operlog.cpp
index edb9109e8..68f50bf6d 100644
--- a/src/modules/m_operlog.cpp
+++ b/src/modules/m_operlog.cpp
@@ -21,51 +21,39 @@
#include "inspircd.h"
-/* $ModDesc: A module which logs all oper commands to the ircd log at default loglevel. */
-
class ModuleOperLog : public Module
{
bool tosnomask;
public:
- void init()
+ void init() CXX11_OVERRIDE
{
- Implementation eventlist[] = { I_OnPreCommand, I_On005Numeric, I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
ServerInstance->SNO->EnableSnomask('r', "OPERLOG");
- OnRehash(NULL);
}
- virtual ~ModuleOperLog()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("A module which logs all oper commands to the ircd log at default loglevel.", VF_VENDOR);
}
- void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
tosnomask = ServerInstance->Config->ConfValue("operlog")->getBool("tosnomask", false);
}
- virtual ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line)
+ ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line) CXX11_OVERRIDE
{
/* If the command doesnt appear to be valid, we dont want to mess with it. */
if (!validated)
return MOD_RES_PASSTHRU;
- if ((IS_OPER(user)) && (IS_LOCAL(user)) && (user->HasPermission(command)))
+ if ((user->IsOper()) && (user->HasPermission(command)))
{
- Command* thiscommand = ServerInstance->Parser->GetHandler(command);
+ Command* thiscommand = ServerInstance->Parser.GetHandler(command);
if ((thiscommand) && (thiscommand->flags_needed == 'o'))
{
- std::string line;
- if (!parameters.empty())
- line = irc::stringjoiner(" ", parameters, 0, parameters.size() - 1).GetJoined();
- std::string msg = "[" + user->GetFullRealHost() + "] " + command + " " + line;
- ServerInstance->Logs->Log("m_operlog", DEFAULT, "OPERLOG: " + msg);
+ std::string msg = "[" + user->GetFullRealHost() + "] " + command + " " + irc::stringjoiner(parameters);
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "OPERLOG: " + msg);
if (tosnomask)
ServerInstance->SNO->WriteGlobalSno('r', msg);
}
@@ -74,12 +62,11 @@ class ModuleOperLog : public Module
return MOD_RES_PASSTHRU;
}
- virtual void On005Numeric(std::string &output)
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
- output.append(" OPERLOG");
+ tokens["OPERLOG"];
}
};
-
MODULE_INIT(ModuleOperLog)
diff --git a/src/modules/m_opermodes.cpp b/src/modules/m_opermodes.cpp
index 8b49f685e..7ab54cedf 100644
--- a/src/modules/m_opermodes.cpp
+++ b/src/modules/m_opermodes.cpp
@@ -22,26 +22,15 @@
#include "inspircd.h"
-/* $ModDesc: Sets (and unsets) modes on opers when they oper up */
-
class ModuleModesOnOper : public Module
{
public:
- void init()
- {
- ServerInstance->Modules->Attach(I_OnPostOper, this);
- }
-
- virtual ~ModuleModesOnOper()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Sets (and unsets) modes on opers when they oper up", VF_VENDOR);
}
- virtual void OnPostOper(User* user, const std::string &opertype, const std::string &opername)
+ void OnPostOper(User* user, const std::string &opertype, const std::string &opername) CXX11_OVERRIDE
{
if (!IS_LOCAL(user))
return;
@@ -71,7 +60,7 @@ class ModuleModesOnOper : public Module
while (ss >> buf)
modes.push_back(buf);
- ServerInstance->SendMode(modes, u);
+ ServerInstance->Modes->Process(modes, u);
}
};
diff --git a/src/modules/m_opermotd.cpp b/src/modules/m_opermotd.cpp
index 989f97689..bd1853d43 100644
--- a/src/modules/m_opermotd.cpp
+++ b/src/modules/m_opermotd.cpp
@@ -22,8 +22,6 @@
#include "inspircd.h"
-/* $ModDesc: Shows a message to opers after oper-up, adds /opermotd */
-
/** Handle /OPERMOTD
*/
class CommandOpermotd : public Command
@@ -82,34 +80,32 @@ class ModuleOpermotd : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cmd);
- OnRehash(NULL);
- Implementation eventlist[] = { I_OnRehash, I_OnOper };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Shows a message to opers after oper-up, adds /opermotd", VF_VENDOR | VF_OPTCOMMON);
}
- virtual void OnOper(User* user, const std::string &opertype)
+ void OnOper(User* user, const std::string &opertype) CXX11_OVERRIDE
{
if (onoper && IS_LOCAL(user))
cmd.ShowOperMOTD(user);
}
- virtual void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
cmd.opermotd.clear();
ConfigTag* conf = ServerInstance->Config->ConfValue("opermotd");
onoper = conf->getBool("onoper", true);
- FileReader f(conf->getString("file", "opermotd"));
- for (int i=0, filesize = f.FileSize(); i < filesize; i++)
- cmd.opermotd.push_back(f.GetLine(i));
+ try
+ {
+ FileReader reader(conf->getString("file", "opermotd"));
+ cmd.opermotd = reader.GetVector();
+ }
+ catch (CoreException&)
+ {
+ // Nothing happens here as we do the error handling in ShowOperMOTD.
+ }
if (conf->getBool("processcolors"))
InspIRCd::ProcessColors(cmd.opermotd);
diff --git a/src/modules/m_operprefix.cpp b/src/modules/m_operprefix.cpp
index 62ddb6c67..3f05dd086 100644
--- a/src/modules/m_operprefix.cpp
+++ b/src/modules/m_operprefix.cpp
@@ -22,90 +22,52 @@
* Originally by Chernov-Phoenix Alexey (Phoenix@RusNet) mailto:phoenix /email address separator/ pravmail.ru
*/
-/* $ModDesc: Gives opers cmode +y which provides a staff prefix. */
-
#include "inspircd.h"
#define OPERPREFIX_VALUE 1000000
-class OperPrefixMode : public ModeHandler
+class OperPrefixMode : public PrefixMode
{
public:
- OperPrefixMode(Module* Creator) : ModeHandler(Creator, "operprefix", 'y', PARAM_ALWAYS, MODETYPE_CHANNEL)
+ OperPrefixMode(Module* Creator) : PrefixMode(Creator, "operprefix", 'y')
{
std::string pfx = ServerInstance->Config->ConfValue("operprefix")->getString("prefix", "!");
- list = true;
prefix = pfx.empty() ? '!' : pfx[0];
- levelrequired = OPERPREFIX_VALUE;
- m_paramtype = TR_NICK;
- }
-
- unsigned int GetPrefixRank()
- {
- return OPERPREFIX_VALUE;
+ levelrequired = INT_MAX;
+ prefixrank = OPERPREFIX_VALUE;
}
-
- ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
- {
- if (IS_SERVER(source) || ServerInstance->ULine(source->server))
- return MODEACTION_ALLOW;
- else
- {
- if (channel)
- source->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only servers are permitted to change channel mode '%c'", source->nick.c_str(), channel->name.c_str(), 'y');
- return MODEACTION_DENY;
- }
- }
-
- bool NeedsOper() { return true; }
};
class ModuleOperPrefixMode;
class HideOperWatcher : public ModeWatcher
{
ModuleOperPrefixMode* parentmod;
+
public:
- HideOperWatcher(ModuleOperPrefixMode* parent) : ModeWatcher((Module*) parent, 'H', MODETYPE_USER), parentmod(parent) {}
- void AfterMode(User* source, User* dest, Channel* channel, const std::string &parameter, bool adding, ModeType type);
+ HideOperWatcher(ModuleOperPrefixMode* parent);
+ void AfterMode(User* source, User* dest, Channel* channel, const std::string &parameter, bool adding);
};
class ModuleOperPrefixMode : public Module
{
- private:
OperPrefixMode opm;
- bool mw_added;
HideOperWatcher hideoperwatcher;
+ UserModeReference hideopermode;
+
public:
ModuleOperPrefixMode()
- : opm(this), mw_added(false), hideoperwatcher(this)
+ : opm(this), hideoperwatcher(this)
+ , hideopermode(this, "hideoper")
{
- }
-
- void init()
- {
- ServerInstance->Modules->AddService(opm);
-
- Implementation eventlist[] = { I_OnUserPreJoin, I_OnPostOper, I_OnLoadModule, I_OnUnloadModule };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
-
/* To give clients a chance to learn about the new prefix we don't give +y to opers
* right now. That means if the module was loaded after opers have joined channels
* they need to rejoin them in order to get the oper prefix.
*/
-
- if (ServerInstance->Modules->Find("m_hideoper.so"))
- mw_added = ServerInstance->Modes->AddModeWatcher(&hideoperwatcher);
}
- ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string& privs, const std::string& keygiven)
+ ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE
{
- /* The user may have the +H umode on himself, but +H does not necessarily correspond
- * to the +H of m_hideoper.
- * However we only add the modewatcher when m_hideoper is loaded, so these
- * conditions (mw_added and the user being +H) together mean the user is a hidden oper.
- */
-
- if (IS_OPER(user) && (!mw_added || !user->IsModeSet('H')))
+ if ((user->IsOper()) && (!user->IsModeSet(hideopermode)))
privs.push_back('y');
return MOD_RES_PASSTHRU;
}
@@ -114,40 +76,23 @@ class ModuleOperPrefixMode : public Module
{
std::vector<std::string> modechange;
modechange.push_back("");
- modechange.push_back(add ? "+y" : "-y");
+ modechange.push_back(add ? "+" : "-");
+ modechange[1].push_back(opm.GetModeChar());
modechange.push_back(user->nick);
- for (UCListIter v = user->chans.begin(); v != user->chans.end(); v++)
+ for (User::ChanList::iterator v = user->chans.begin(); v != user->chans.end(); v++)
{
- modechange[0] = (*v)->name;
- ServerInstance->SendGlobalMode(modechange, ServerInstance->FakeClient);
+ modechange[0] = (*v)->chan->name;
+ ServerInstance->Modes->Process(modechange, ServerInstance->FakeClient);
}
}
- void OnPostOper(User* user, const std::string& opername, const std::string& opertype)
+ void OnPostOper(User* user, const std::string& opername, const std::string& opertype) CXX11_OVERRIDE
{
- if (IS_LOCAL(user) && (!mw_added || !user->IsModeSet('H')))
+ if (IS_LOCAL(user) && (!user->IsModeSet(hideopermode)))
SetOperPrefix(user, true);
}
- void OnLoadModule(Module* mod)
- {
- if ((!mw_added) && (mod->ModuleSourceFile == "m_hideoper.so"))
- mw_added = ServerInstance->Modes->AddModeWatcher(&hideoperwatcher);
- }
-
- void OnUnloadModule(Module* mod)
- {
- if ((mw_added) && (mod->ModuleSourceFile == "m_hideoper.so") && (ServerInstance->Modes->DelModeWatcher(&hideoperwatcher)))
- mw_added = false;
- }
-
- ~ModuleOperPrefixMode()
- {
- if (mw_added)
- ServerInstance->Modes->DelModeWatcher(&hideoperwatcher);
- }
-
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Gives opers cmode +y which provides a staff prefix.", VF_VENDOR);
}
@@ -160,10 +105,16 @@ class ModuleOperPrefixMode : public Module
}
};
-void HideOperWatcher::AfterMode(User* source, User* dest, Channel* channel, const std::string& parameter, bool adding, ModeType type)
+HideOperWatcher::HideOperWatcher(ModuleOperPrefixMode* parent)
+ : ModeWatcher(parent, "hideoper", MODETYPE_USER)
+ , parentmod(parent)
+{
+}
+
+void HideOperWatcher::AfterMode(User* source, User* dest, Channel* channel, const std::string& parameter, bool adding)
{
// If hideoper is being unset because the user is deopering, don't set +y
- if (IS_LOCAL(dest) && IS_OPER(dest))
+ if (IS_LOCAL(dest) && dest->IsOper())
parentmod->SetOperPrefix(dest, !adding);
}
diff --git a/src/modules/m_override.cpp b/src/modules/m_override.cpp
index 3e42c4f79..756ef8edc 100644
--- a/src/modules/m_override.cpp
+++ b/src/modules/m_override.cpp
@@ -26,12 +26,14 @@
#include "inspircd.h"
-/* $ModDesc: Provides support for allowing opers to override certain things. */
-
class ModuleOverride : public Module
{
bool RequireKey;
bool NoisyOverride;
+ ChanModeReference topiclock;
+ ChanModeReference inviteonly;
+ ChanModeReference key;
+ ChanModeReference limit;
static bool IsOverride(unsigned int userlevel, const std::string& modeline)
{
@@ -47,28 +49,46 @@ class ModuleOverride : public Module
return false;
}
+ ModResult HandleJoinOverride(LocalUser* user, Channel* chan, const std::string& keygiven, const char* bypasswhat, const char* mode)
+ {
+ if (RequireKey && keygiven != "override")
+ {
+ // Can't join normally -- must use a special key to bypass restrictions
+ user->WriteNotice("*** You may not join normally. You must join with a key of 'override' to oper override.");
+ return MOD_RES_PASSTHRU;
+ }
+
+ if (NoisyOverride)
+ chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper override to bypass %s", chan->name.c_str(), user->nick.c_str(), bypasswhat);
+ ServerInstance->SNO->WriteGlobalSno('v', user->nick+" used oper override to bypass " + mode + " on " + chan->name);
+ return MOD_RES_ALLOW;
+ }
+
public:
+ ModuleOverride()
+ : topiclock(this, "topiclock")
+ , inviteonly(this, "inviteonly")
+ , key(this, "key")
+ , limit(this, "limit")
+ {
+ }
- void init()
+ void init() CXX11_OVERRIDE
{
- // read our config options (main config file)
- OnRehash(NULL);
ServerInstance->SNO->EnableSnomask('v', "OVERRIDE");
- Implementation eventlist[] = { I_OnRehash, I_OnPreMode, I_On005Numeric, I_OnUserPreJoin, I_OnUserPreKick, I_OnPreTopicChange };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
}
- void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
- // re-read our config options on a rehash
+ // re-read our config options
ConfigTag* tag = ServerInstance->Config->ConfValue("override");
NoisyOverride = tag->getBool("noisy");
RequireKey = tag->getBool("requirekey");
}
- void On005Numeric(std::string &output)
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
- output.append(" OVERRIDE");
+ tokens["OVERRIDE"];
}
bool CanOverride(User* source, const char* token)
@@ -80,11 +100,11 @@ class ModuleOverride : public Module
}
- ModResult OnPreTopicChange(User *source, Channel *channel, const std::string &topic)
+ ModResult OnPreTopicChange(User *source, Channel *channel, const std::string &topic) CXX11_OVERRIDE
{
- if (IS_LOCAL(source) && IS_OPER(source) && CanOverride(source, "TOPIC"))
+ if (IS_LOCAL(source) && source->IsOper() && CanOverride(source, "TOPIC"))
{
- if (!channel->HasUser(source) || (channel->IsModeSet('t') && channel->GetPrefixValue(source) < HALFOP_VALUE))
+ if (!channel->HasUser(source) || (channel->IsModeSet(topiclock) && channel->GetPrefixValue(source) < HALFOP_VALUE))
{
ServerInstance->SNO->WriteGlobalSno('v',source->nick+" used oper override to change a topic on "+channel->name);
}
@@ -96,9 +116,9 @@ class ModuleOverride : public Module
return MOD_RES_PASSTHRU;
}
- ModResult OnUserPreKick(User* source, Membership* memb, const std::string &reason)
+ ModResult OnUserPreKick(User* source, Membership* memb, const std::string &reason) CXX11_OVERRIDE
{
- if (IS_OPER(source) && CanOverride(source,"KICK"))
+ if (source->IsOper() && CanOverride(source,"KICK"))
{
// If the kicker's status is less than the target's, or the kicker's status is less than or equal to voice
if ((memb->chan->GetPrefixValue(source) < memb->getRank()) || (memb->chan->GetPrefixValue(source) <= VOICE_VALUE))
@@ -110,11 +130,11 @@ class ModuleOverride : public Module
return MOD_RES_PASSTHRU;
}
- ModResult OnPreMode(User* source,User* dest,Channel* channel, const std::vector<std::string>& parameters)
+ ModResult OnPreMode(User* source,User* dest,Channel* channel, const std::vector<std::string>& parameters) CXX11_OVERRIDE
{
- if (!source || !channel)
+ if (!channel)
return MOD_RES_PASSTHRU;
- if (!IS_OPER(source) || !IS_LOCAL(source))
+ if (!source->IsOper() || !IS_LOCAL(source))
return MOD_RES_PASSTHRU;
unsigned int mode = channel->GetPrefixValue(source);
@@ -133,81 +153,33 @@ class ModuleOverride : public Module
return MOD_RES_PASSTHRU;
}
- ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven)
+ ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE
{
- if (IS_LOCAL(user) && IS_OPER(user))
+ if (user->IsOper())
{
if (chan)
{
- if (chan->IsModeSet('i') && (CanOverride(user,"INVITE")))
+ if (chan->IsModeSet(inviteonly) && (CanOverride(user,"INVITE")))
{
- irc::string x(chan->name.c_str());
- if (!IS_LOCAL(user)->IsInvited(x))
- {
- if (RequireKey && keygiven != "override")
- {
- // Can't join normally -- must use a special key to bypass restrictions
- user->WriteServ("NOTICE %s :*** You may not join normally. You must join with a key of 'override' to oper override.", user->nick.c_str());
- return MOD_RES_PASSTHRU;
- }
-
- if (NoisyOverride)
- chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper override to bypass invite-only", cname, user->nick.c_str());
- ServerInstance->SNO->WriteGlobalSno('v', user->nick+" used oper override to bypass +i on "+std::string(cname));
- }
+ if (!user->IsInvited(chan))
+ return HandleJoinOverride(user, chan, keygiven, "invite-only", "+i");
return MOD_RES_ALLOW;
}
- if (chan->IsModeSet('k') && (CanOverride(user,"KEY")) && keygiven != chan->GetModeParameter('k'))
- {
- if (RequireKey && keygiven != "override")
- {
- // Can't join normally -- must use a special key to bypass restrictions
- user->WriteServ("NOTICE %s :*** You may not join normally. You must join with a key of 'override' to oper override.", user->nick.c_str());
- return MOD_RES_PASSTHRU;
- }
-
- if (NoisyOverride)
- chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper override to bypass the channel key", cname, user->nick.c_str());
- ServerInstance->SNO->WriteGlobalSno('v', user->nick+" used oper override to bypass +k on "+std::string(cname));
- return MOD_RES_ALLOW;
- }
+ if (chan->IsModeSet(key) && (CanOverride(user,"KEY")) && keygiven != chan->GetModeParameter(key))
+ return HandleJoinOverride(user, chan, keygiven, "the channel key", "+k");
- if (chan->IsModeSet('l') && (chan->GetUserCounter() >= ConvToInt(chan->GetModeParameter('l'))) && (CanOverride(user,"LIMIT")))
- {
- if (RequireKey && keygiven != "override")
- {
- // Can't join normally -- must use a special key to bypass restrictions
- user->WriteServ("NOTICE %s :*** You may not join normally. You must join with a key of 'override' to oper override.", user->nick.c_str());
- return MOD_RES_PASSTHRU;
- }
-
- if (NoisyOverride)
- chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper override to bypass the channel limit", cname, user->nick.c_str());
- ServerInstance->SNO->WriteGlobalSno('v', user->nick+" used oper override to bypass +l on "+std::string(cname));
- return MOD_RES_ALLOW;
- }
+ if (chan->IsModeSet(limit) && (chan->GetUserCounter() >= ConvToInt(chan->GetModeParameter(limit))) && (CanOverride(user,"LIMIT")))
+ return HandleJoinOverride(user, chan, keygiven, "the channel limit", "+l");
if (chan->IsBanned(user) && CanOverride(user,"BANWALK"))
- {
- if (RequireKey && keygiven != "override")
- {
- // Can't join normally -- must use a special key to bypass restrictions
- user->WriteServ("NOTICE %s :*** You may not join normally. You must join with a key of 'override' to oper override.", user->nick.c_str());
- return MOD_RES_PASSTHRU;
- }
-
- if (NoisyOverride)
- chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper override to bypass channel ban", cname, user->nick.c_str());
- ServerInstance->SNO->WriteGlobalSno('v',"%s used oper override to bypass channel ban on %s", user->nick.c_str(), cname);
- return MOD_RES_ALLOW;
- }
+ return HandleJoinOverride(user, chan, keygiven, "channel ban", "channel ban");
}
}
return MOD_RES_PASSTHRU;
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for allowing opers to override certain things",VF_VENDOR);
}
diff --git a/src/modules/m_passforward.cpp b/src/modules/m_passforward.cpp
index c04b306b1..3050dba0b 100644
--- a/src/modules/m_passforward.cpp
+++ b/src/modules/m_passforward.cpp
@@ -17,29 +17,19 @@
*/
-/* $ModDesc: Forwards a password users can send on connect (for example for NickServ identification). */
-
#include "inspircd.h"
class ModulePassForward : public Module
{
- private:
std::string nickrequired, forwardmsg, forwardcmd;
public:
- void init()
- {
- OnRehash(NULL);
- Implementation eventlist[] = { I_OnPostConnect, I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Sends server password to NickServ", VF_VENDOR);
}
- void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ConfigTag* tag = ServerInstance->Config->ConfValue("passforward");
nickrequired = tag->getString("nick", "NickServ");
@@ -54,22 +44,22 @@ class ModulePassForward : public Module
char c = format[i];
if (c == '$')
{
- if (format.substr(i, 13) == "$nickrequired")
+ if (!format.compare(i, 13, "$nickrequired", 13))
{
result.append(nickrequired);
i += 12;
}
- else if (format.substr(i, 5) == "$nick")
+ else if (!format.compare(i, 5, "$nick", 5))
{
result.append(user->nick);
i += 4;
}
- else if (format.substr(i, 5) == "$user")
+ else if (!format.compare(i, 5, "$user", 5))
{
result.append(user->ident);
i += 4;
}
- else if (format.substr(i,5) == "$pass")
+ else if (!format.compare(i, 5, "$pass", 5))
{
result.append(user->password);
i += 4;
@@ -82,17 +72,21 @@ class ModulePassForward : public Module
}
}
- virtual void OnPostConnect(User* ruser)
+ void OnPostConnect(User* ruser) CXX11_OVERRIDE
{
LocalUser* user = IS_LOCAL(ruser);
if (!user || user->password.empty())
return;
+ // If the connect class requires a password, don't forward it
+ if (!user->MyClass->config->getString("password").empty())
+ return;
+
if (!nickrequired.empty())
{
/* Check if nick exists and its server is ulined */
User* u = ServerInstance->FindNick(nickrequired);
- if (!u || !ServerInstance->ULine(u->server))
+ if (!u || !u->server->IsULine())
return;
}
@@ -102,7 +96,7 @@ class ModulePassForward : public Module
tmp.clear();
FormatStr(tmp,forwardcmd, user);
- ServerInstance->Parser->ProcessBuffer(tmp,user);
+ ServerInstance->Parser.ProcessBuffer(tmp,user);
}
};
diff --git a/src/modules/m_password_hash.cpp b/src/modules/m_password_hash.cpp
index 98462780b..926ba5632 100644
--- a/src/modules/m_password_hash.cpp
+++ b/src/modules/m_password_hash.cpp
@@ -18,10 +18,8 @@
*/
-/* $ModDesc: Allows for hashed oper passwords */
-
#include "inspircd.h"
-#include "hash.h"
+#include "modules/hash.h"
/* Handle /MKPASSWD
*/
@@ -36,21 +34,20 @@ class CommandMkpasswd : public Command
void MakeHash(User* user, const std::string& algo, const std::string& stuff)
{
- if (algo.substr(0,5) == "hmac-")
+ if (!algo.compare(0, 5, "hmac-", 5))
{
std::string type = algo.substr(5);
HashProvider* hp = ServerInstance->Modules->FindDataService<HashProvider>("hash/" + type);
if (!hp)
{
- user->WriteServ("NOTICE %s :Unknown hash type", user->nick.c_str());
+ user->WriteNotice("Unknown hash type");
return;
}
std::string salt = ServerInstance->GenRandomStr(6, false);
std::string target = hp->hmac(salt, stuff);
std::string str = BinToBase64(salt) + "$" + BinToBase64(target, NULL, 0);
- user->WriteServ("NOTICE %s :%s hashed password for %s is %s",
- user->nick.c_str(), algo.c_str(), stuff.c_str(), str.c_str());
+ user->WriteNotice(algo + " hashed password for " + stuff + " is " + str);
return;
}
HashProvider* hp = ServerInstance->Modules->FindDataService<HashProvider>("hash/" + algo);
@@ -58,12 +55,11 @@ class CommandMkpasswd : public Command
{
/* Now attempt to generate a hash */
std::string hexsum = hp->hexsum(stuff);
- user->WriteServ("NOTICE %s :%s hashed password for %s is %s",
- user->nick.c_str(), algo.c_str(), stuff.c_str(), hexsum.c_str());
+ user->WriteNotice(algo + " hashed password for " + stuff + " is " + hexsum);
}
else
{
- user->WriteServ("NOTICE %s :Unknown hash type", user->nick.c_str());
+ user->WriteNotice("Unknown hash type");
}
}
@@ -84,19 +80,9 @@ class ModuleOperHash : public Module
{
}
- void init()
- {
- /* Read the config file first */
- OnRehash(NULL);
-
- ServerInstance->Modules->AddService(cmd);
- Implementation eventlist[] = { I_OnPassCompare };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- virtual ModResult OnPassCompare(Extensible* ex, const std::string &data, const std::string &input, const std::string &hashtype)
+ ModResult OnPassCompare(Extensible* ex, const std::string &data, const std::string &input, const std::string &hashtype) CXX11_OVERRIDE
{
- if (hashtype.substr(0,5) == "hmac-")
+ if (!hashtype.compare(0, 5, "hmac-", 5))
{
std::string type = hashtype.substr(5);
HashProvider* hp = ServerInstance->Modules->FindDataService<HashProvider>("hash/" + type);
@@ -120,19 +106,19 @@ class ModuleOperHash : public Module
/* Is this a valid hash name? */
if (hp)
{
- /* Compare the hash in the config to the generated hash */
- if (data == hp->hexsum(input))
+ // Use the timing-safe compare function to compare the hashes
+ if (InspIRCd::TimingSafeCompare(data, hp->hexsum(input)))
return MOD_RES_ALLOW;
else
/* No match, and must be hashed, forbid */
return MOD_RES_DENY;
}
- /* Not a hash, fall through to strcmp in core */
+ // We don't handle this type, let other mods or the core decide
return MOD_RES_PASSTHRU;
}
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Allows for hashed oper passwords",VF_VENDOR);
}
diff --git a/src/modules/m_permchannels.cpp b/src/modules/m_permchannels.cpp
index e86b3cbf6..60c4578c5 100644
--- a/src/modules/m_permchannels.cpp
+++ b/src/modules/m_permchannels.cpp
@@ -19,149 +19,137 @@
#include "inspircd.h"
+#include "listmode.h"
+#include <fstream>
-/* $ModDesc: Provides support for channel mode +P to provide permanent channels */
-struct ListModeData
+/** Handles the +P channel mode
+ */
+class PermChannel : public ModeHandler
{
- std::string modes;
- std::string params;
+ public:
+ PermChannel(Module* Creator)
+ : ModeHandler(Creator, "permanent", 'P', PARAM_NONE, MODETYPE_CHANNEL)
+ {
+ oper = true;
+ }
+
+ ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string& parameter, bool adding)
+ {
+ if (adding == channel->IsModeSet(this))
+ return MODEACTION_DENY;
+
+ channel->SetMode(this, adding);
+ if (!adding)
+ channel->CheckDestroy();
+
+ return MODEACTION_ALLOW;
+ }
};
// Not in a class due to circular dependancy hell.
static std::string permchannelsconf;
-static bool WriteDatabase(Module* mod, bool save_listmodes)
+static bool WriteDatabase(PermChannel& permchanmode, Module* mod, bool save_listmodes)
{
- FILE *f;
+ ChanModeReference ban(mod, "ban");
+ /*
+ * We need to perform an atomic write so as not to fuck things up.
+ * So, let's write to a temporary file, flush it, then rename the file..
+ * -- w00t
+ */
+ // If the user has not specified a configuration file then we don't write one.
if (permchannelsconf.empty())
- {
- // Fake success.
return true;
- }
- std::string tempname = permchannelsconf + ".tmp";
-
- /*
- * We need to perform an atomic write so as not to fuck things up.
- * So, let's write to a temporary file, flush and sync the FD, then rename the file..
- * -- w00t
- */
- f = fopen(tempname.c_str(), "w");
- if (!f)
+ std::string permchannelsnewconf = permchannelsconf + ".tmp";
+ std::ofstream stream(permchannelsnewconf.c_str());
+ if (!stream.is_open())
{
- ServerInstance->Logs->Log("m_permchannels",DEFAULT, "permchannels: Cannot create database! %s (%d)", strerror(errno), errno);
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Cannot create database! %s (%d)", strerror(errno), errno);
ServerInstance->SNO->WriteToSnoMask('a', "database: cannot create new db: %s (%d)", strerror(errno), errno);
return false;
}
- fputs("# Permchannels DB\n# This file is autogenerated; any changes will be overwritten!\n<config format=\"compat\">\n", f);
- // Now, let's write.
- std::string line;
- for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
+ stream << "# This file is automatically generated by m_permchannels. Any changes will be overwritten." << std::endl
+ << "<config format=\"xml\">" << std::endl;
+
+ const chan_hash& chans = ServerInstance->GetChans();
+ for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); ++i)
{
Channel* chan = i->second;
- if (!chan->IsModeSet('P'))
+ if (!chan->IsModeSet(permchanmode))
continue;
std::string chanmodes = chan->ChanModes(true);
if (save_listmodes)
{
- ListModeData lm;
+ std::string modes;
+ std::string params;
- // Bans are managed by the core, so we have to process them separately
- lm.modes = std::string(chan->bans.size(), 'b');
- for (BanList::const_iterator j = chan->bans.begin(); j != chan->bans.end(); ++j)
+ const ModeParser::ListModeList& listmodes = ServerInstance->Modes->GetListModes();
+ for (ModeParser::ListModeList::const_iterator j = listmodes.begin(); j != listmodes.end(); ++j)
{
- lm.params += j->data;
- lm.params += ' ';
- }
+ ListModeBase* lm = *j;
+ ListModeBase::ModeList* list = lm->GetList(chan);
+ if (!list || list->empty())
+ continue;
+
+ size_t n = 0;
+ // Append the parameters
+ for (ListModeBase::ModeList::const_iterator k = list->begin(); k != list->end(); ++k, n++)
+ {
+ params += k->mask;
+ params += ' ';
+ }
- // All other listmodes are managed by modules, so we need to ask them (call their
- // OnSyncChannel() handler) to give our ProtoSendMode() a list of modes that are
- // set on the channel. The ListModeData struct is passed as an opaque pointer
- // that will be passed back to us by the module handling the mode.
- FOREACH_MOD(I_OnSyncChannel, OnSyncChannel(chan, mod, &lm));
+ // Append the mode letters (for example "IIII", "gg")
+ modes.append(n, lm->GetModeChar());
+ }
- if (!lm.modes.empty())
+ if (!params.empty())
{
// Remove the last space
- lm.params.erase(lm.params.end()-1);
+ params.erase(params.end()-1);
// If there is at least a space in chanmodes (that is, a non-listmode has a parameter)
// insert the listmode mode letters before the space. Otherwise just append them.
std::string::size_type p = chanmodes.find(' ');
if (p == std::string::npos)
- chanmodes += lm.modes;
+ chanmodes += modes;
else
- chanmodes.insert(p, lm.modes);
+ chanmodes.insert(p, modes);
// Append the listmode parameters (the masks themselves)
chanmodes += ' ';
- chanmodes += lm.params;
+ chanmodes += params;
}
}
- std::string chants = ConvToStr(chan->age);
- std::string topicts = ConvToStr(chan->topicset);
- const char* items[] =
- {
- "<permchannels channel=",
- chan->name.c_str(),
- " ts=",
- chants.c_str(),
- " topic=",
- chan->topic.c_str(),
- " topicts=",
- topicts.c_str(),
- " topicsetby=",
- chan->setby.c_str(),
- " modes=",
- chanmodes.c_str(),
- ">\n"
- };
-
- line.clear();
- int item = 0, ipos = 0;
- while (item < 13)
- {
- char c = items[item][ipos++];
- if (c == 0)
- {
- // end of this string; hop to next string, insert a quote
- item++;
- ipos = 0;
- c = '"';
- }
- else if (c == '\\' || c == '"')
- {
- line += '\\';
- }
- line += c;
- }
-
- // Erase last '"'
- line.erase(line.end()-1);
- fputs(line.c_str(), f);
+ stream << "<permchannels channel=\"" << ServerConfig::Escape(chan->name)
+ << "\" ts=\"" << chan->age
+ << "\" topic=\"" << ServerConfig::Escape(chan->topic)
+ << "\" topicts=\"" << chan->topicset
+ << "\" topicsetby=\"" << ServerConfig::Escape(chan->setby)
+ << "\" modes=\"" << ServerConfig::Escape(chanmodes)
+ << "\">" << std::endl;
}
- int write_error = 0;
- write_error = ferror(f);
- write_error |= fclose(f);
- if (write_error)
+ if (stream.fail())
{
- ServerInstance->Logs->Log("m_permchannels",DEFAULT, "permchannels: Cannot write to new database! %s (%d)", strerror(errno), errno);
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Cannot write to new database! %s (%d)", strerror(errno), errno);
ServerInstance->SNO->WriteToSnoMask('a', "database: cannot write to new db: %s (%d)", strerror(errno), errno);
return false;
}
+ stream.close();
#ifdef _WIN32
remove(permchannelsconf.c_str());
#endif
// Use rename to move temporary to new db - this is guarenteed not to fuck up, even in case of a crash.
- if (rename(tempname.c_str(), permchannelsconf.c_str()) < 0)
+ if (rename(permchannelsnewconf.c_str(), permchannelsconf.c_str()) < 0)
{
- ServerInstance->Logs->Log("m_permchannels",DEFAULT, "permchannels: Cannot move new to old database! %s (%d)", strerror(errno), errno);
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Cannot move new to old database! %s (%d)", strerror(errno), errno);
ServerInstance->SNO->WriteToSnoMask('a', "database: cannot replace old with new db: %s (%d)", strerror(errno), errno);
return false;
}
@@ -169,42 +157,6 @@ static bool WriteDatabase(Module* mod, bool save_listmodes)
return true;
}
-
-
-/** Handles the +P channel mode
- */
-class PermChannel : public ModeHandler
-{
- public:
- PermChannel(Module* Creator) : ModeHandler(Creator, "permanent", 'P', PARAM_NONE, MODETYPE_CHANNEL) { oper = true; }
-
- ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
- {
- if (adding)
- {
- if (!channel->IsModeSet('P'))
- {
- channel->SetMode('P',true);
- return MODEACTION_ALLOW;
- }
- }
- else
- {
- if (channel->IsModeSet('P'))
- {
- channel->SetMode(this,false);
- if (channel->GetUserCounter() == 0)
- {
- channel->DelUser(ServerInstance->FakeClient);
- }
- return MODEACTION_ALLOW;
- }
- }
-
- return MODEACTION_DENY;
- }
-};
-
class ModulePermanentChannels : public Module
{
PermChannel p;
@@ -218,46 +170,14 @@ public:
{
}
- void init()
- {
- ServerInstance->Modules->AddService(p);
- Implementation eventlist[] = { I_OnChannelPreDelete, I_OnPostTopicChange, I_OnRawMode, I_OnRehash, I_OnBackgroundTimer };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
-
- OnRehash(NULL);
- }
-
- CullResult cull()
- {
- /*
- * DelMode can't remove the +P mode on empty channels, or it will break
- * merging modes with remote servers. Remove the empty channels now as
- * we know this is not the case.
- */
- chan_hash::iterator iter = ServerInstance->chanlist->begin();
- while (iter != ServerInstance->chanlist->end())
- {
- Channel* c = iter->second;
- if (c->GetUserCounter() == 0)
- {
- chan_hash::iterator at = iter;
- iter++;
- FOREACH_MOD(I_OnChannelDelete, OnChannelDelete(c));
- ServerInstance->chanlist->erase(at);
- ServerInstance->GlobalCulls.AddItem(c);
- }
- else
- iter++;
- }
- ServerInstance->Modes->DelMode(&p);
- return Module::cull();
- }
-
- virtual void OnRehash(User *user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ConfigTag* tag = ServerInstance->Config->ConfValue("permchanneldb");
permchannelsconf = tag->getString("filename");
save_listmodes = tag->getBool("listmodes");
+
+ if (!permchannelsconf.empty())
+ permchannelsconf = ServerInstance->Config->Paths.PrependConfig(permchannelsconf);
}
void LoadDatabase()
@@ -271,12 +191,11 @@ public:
{
ConfigTag* tag = i->second;
std::string channel = tag->getString("channel");
- std::string topic = tag->getString("topic");
std::string modes = tag->getString("modes");
if ((channel.empty()) || (channel.length() > ServerInstance->Config->Limits.ChanMax))
{
- ServerInstance->Logs->Log("m_permchannels", DEFAULT, "Ignoring permchannels tag with empty or too long channel name (\"" + channel + "\")");
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Ignoring permchannels tag with empty or too long channel name (\"" + channel + "\")");
continue;
}
@@ -284,19 +203,23 @@ public:
if (!c)
{
- time_t TS = tag->getInt("ts");
- c = new Channel(channel, ((TS > 0) ? TS : ServerInstance->Time()));
+ time_t TS = tag->getInt("ts", ServerInstance->Time(), 1);
+ c = new Channel(channel, TS);
- c->SetTopic(NULL, topic, true);
- c->setby = tag->getString("topicsetby");
- if (c->setby.empty())
- c->setby = ServerInstance->Config->ServerName;
unsigned int topicset = tag->getInt("topicts");
- // SetTopic() sets the topic TS to now, if there was no topicts saved then don't overwrite that with a 0
- if (topicset > 0)
+ c->topic = tag->getString("topic");
+
+ if ((topicset != 0) || (!c->topic.empty()))
+ {
+ if (topicset == 0)
+ topicset = ServerInstance->Time();
c->topicset = topicset;
+ c->setby = tag->getString("topicsetby");
+ if (c->setby.empty())
+ c->setby = ServerInstance->Config->ServerName;
+ }
- ServerInstance->Logs->Log("m_permchannels", DEBUG, "Added %s with topic %s", channel.c_str(), topic.c_str());
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Added %s with topic %s", channel.c_str(), c->topic.c_str());
if (modes.empty())
continue;
@@ -325,24 +248,24 @@ public:
}
}
- virtual ModResult OnRawMode(User* user, Channel* chan, const char mode, const std::string &param, bool adding, int pcnt)
+ ModResult OnRawMode(User* user, Channel* chan, ModeHandler* mh, const std::string& param, bool adding) CXX11_OVERRIDE
{
- if (chan && (chan->IsModeSet('P') || mode == 'P'))
+ if (chan && (chan->IsModeSet(p) || mh == &p))
dirty = true;
return MOD_RES_PASSTHRU;
}
- virtual void OnPostTopicChange(User*, Channel *c, const std::string&)
+ void OnPostTopicChange(User*, Channel *c, const std::string&) CXX11_OVERRIDE
{
- if (c->IsModeSet('P'))
+ if (c->IsModeSet(p))
dirty = true;
}
- void OnBackgroundTimer(time_t)
+ void OnBackgroundTimer(time_t) CXX11_OVERRIDE
{
if (dirty)
- WriteDatabase(this, save_listmodes);
+ WriteDatabase(p, this, save_listmodes);
dirty = false;
}
@@ -361,7 +284,7 @@ public:
// Load only when there are no linked servers - we set the TS of the channels we
// create to the current time, this can lead to desync because spanningtree has
// no way of knowing what we do
- ProtoServerList serverlist;
+ ProtocolInterface::ServerList serverlist;
ServerInstance->PI->GetServerList(serverlist);
if (serverlist.size() < 2)
{
@@ -371,38 +294,19 @@ public:
}
catch (CoreException& e)
{
- ServerInstance->Logs->Log("m_permchannels", DEFAULT, "Error loading permchannels database: " + std::string(e.GetReason()));
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Error loading permchannels database: " + std::string(e.GetReason()));
}
}
}
- void ProtoSendMode(void* opaque, TargetTypeFlags type, void* target, const std::vector<std::string>& modes, const std::vector<TranslateType>& translate)
- {
- // We never pass an empty modelist but better be sure
- if (modes.empty())
- return;
-
- ListModeData* lm = static_cast<ListModeData*>(opaque);
-
- // Append the mode letters without the trailing '+' (for example "IIII", "gg")
- lm->modes.append(modes[0].begin()+1, modes[0].end());
-
- // Append the parameters
- for (std::vector<std::string>::const_iterator i = modes.begin()+1; i != modes.end(); ++i)
- {
- lm->params += *i;
- lm->params += ' ';
- }
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for channel mode +P to provide permanent channels",VF_VENDOR);
}
- virtual ModResult OnChannelPreDelete(Channel *c)
+ ModResult OnChannelPreDelete(Channel *c) CXX11_OVERRIDE
{
- if (c->IsModeSet('P'))
+ if (c->IsModeSet(p))
return MOD_RES_DENY;
return MOD_RES_PASSTHRU;
diff --git a/src/modules/m_randquote.cpp b/src/modules/m_randquote.cpp
index 668eea0e5..1bb28583e 100644
--- a/src/modules/m_randquote.cpp
+++ b/src/modules/m_randquote.cpp
@@ -21,80 +21,37 @@
*/
-/* $ModDesc: Provides random quotes on connect. */
-
#include "inspircd.h"
-static FileReader *quotes = NULL;
-
-std::string prefix;
-std::string suffix;
-
-/** Handle /RANDQUOTE
- */
-class CommandRandquote : public Command
-{
- public:
- CommandRandquote(Module* Creator) : Command(Creator,"RANDQUOTE", 0)
- {
- }
-
- CmdResult Handle (const std::vector<std::string>& parameters, User *user)
- {
- int fsize = quotes->FileSize();
- if (fsize)
- {
- std::string str = quotes->GetLine(ServerInstance->GenRandomInt(fsize));
- if (!str.empty())
- user->WriteServ("NOTICE %s :%s%s%s",user->nick.c_str(),prefix.c_str(),str.c_str(),suffix.c_str());
- }
-
- return CMD_SUCCESS;
- }
-};
-
class ModuleRandQuote : public Module
{
private:
- CommandRandquote cmd;
- public:
- ModuleRandQuote()
- : cmd(this)
- {
- }
+ std::string prefix;
+ std::string suffix;
+ std::vector<std::string> quotes;
- void init()
+ public:
+ void init() CXX11_OVERRIDE
{
ConfigTag* conf = ServerInstance->Config->ConfValue("randquote");
-
- std::string q_file = conf->getString("file","quotes");
prefix = conf->getString("prefix");
suffix = conf->getString("suffix");
-
- quotes = new FileReader(q_file);
- if (!quotes->Exists())
- {
- throw ModuleException("m_randquote: QuoteFile not Found!! Please check your config - module will not function.");
- }
- ServerInstance->Modules->AddService(cmd);
- Implementation eventlist[] = { I_OnUserConnect };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
+ FileReader reader(conf->getString("file", "quotes"));
+ quotes = reader.GetVector();
}
-
- virtual ~ModuleRandQuote()
+ void OnUserConnect(LocalUser* user) CXX11_OVERRIDE
{
- delete quotes;
- }
-
- virtual Version GetVersion()
- {
- return Version("Provides random quotes on connect.",VF_VENDOR);
+ if (!quotes.empty())
+ {
+ unsigned long random = ServerInstance->GenRandomInt(quotes.size());
+ user->WriteNotice(prefix + quotes[random] + suffix);
+ }
}
- virtual void OnUserConnect(LocalUser* user)
+ Version GetVersion() CXX11_OVERRIDE
{
- cmd.Handle(std::vector<std::string>(), user);
+ return Version("Provides random quotes on connect.", VF_VENDOR);
}
};
diff --git a/src/modules/m_redirect.cpp b/src/modules/m_redirect.cpp
index 26d6b162b..e822676bf 100644
--- a/src/modules/m_redirect.cpp
+++ b/src/modules/m_redirect.cpp
@@ -24,66 +24,51 @@
#include "inspircd.h"
-/* $ModDesc: Provides channel mode +L (limit redirection) and usermode +L (no forced redirection) */
-
/** Handle channel mode +L
*/
-class Redirect : public ModeHandler
+class Redirect : public ParamMode<Redirect, LocalStringExt>
{
public:
- Redirect(Module* Creator) : ModeHandler(Creator, "redirect", 'L', PARAM_SETONLY, MODETYPE_CHANNEL) { }
+ Redirect(Module* Creator)
+ : ParamMode<Redirect, LocalStringExt>(Creator, "redirect", 'L') { }
- ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
+ ModeAction OnSet(User* source, Channel* channel, std::string& parameter)
{
- if (adding)
+ if (IS_LOCAL(source))
{
- if (IS_LOCAL(source))
+ if (!ServerInstance->IsChannel(parameter))
{
- if (!ServerInstance->IsChannel(parameter.c_str(), ServerInstance->Config->Limits.ChanMax))
- {
- source->WriteNumeric(403, "%s %s :Invalid channel name", source->nick.c_str(), parameter.c_str());
- parameter.clear();
- return MODEACTION_DENY;
- }
+ source->WriteNumeric(ERR_NOSUCHCHANNEL, "%s :Invalid channel name", parameter.c_str());
+ return MODEACTION_DENY;
}
+ }
- if (IS_LOCAL(source) && !IS_OPER(source))
+ if (IS_LOCAL(source) && !source->IsOper())
+ {
+ Channel* c = ServerInstance->FindChan(parameter);
+ if (!c)
{
- Channel* c = ServerInstance->FindChan(parameter);
- if (!c)
- {
- source->WriteNumeric(690, "%s :Target channel %s must exist to be set as a redirect.",source->nick.c_str(),parameter.c_str());
- parameter.clear();
- return MODEACTION_DENY;
- }
- else if (c->GetPrefixValue(source) < OP_VALUE)
- {
- source->WriteNumeric(690, "%s :You must be opped on %s to set it as a redirect.",source->nick.c_str(),parameter.c_str());
- parameter.clear();
- return MODEACTION_DENY;
- }
- }
-
- if (channel->GetModeParameter('L') == parameter)
+ source->WriteNumeric(690, ":Target channel %s must exist to be set as a redirect.",parameter.c_str());
return MODEACTION_DENY;
- /*
- * We used to do some checking for circular +L here, but there is no real need for this any more especially as we
- * now catch +L looping in PreJoin. Remove it, since O(n) logic makes me sad, and we catch it anyway. :) -- w00t
- */
- channel->SetModeParam('L', parameter);
- return MODEACTION_ALLOW;
- }
- else
- {
- if (channel->IsModeSet('L'))
+ }
+ else if (c->GetPrefixValue(source) < OP_VALUE)
{
- channel->SetModeParam('L', "");
- return MODEACTION_ALLOW;
+ source->WriteNumeric(690, ":You must be opped on %s to set it as a redirect.",parameter.c_str());
+ return MODEACTION_DENY;
}
}
- return MODEACTION_DENY;
+ /*
+ * We used to do some checking for circular +L here, but there is no real need for this any more especially as we
+ * now catch +L looping in PreJoin. Remove it, since O(n) logic makes me sad, and we catch it anyway. :) -- w00t
+ */
+ ext.set(channel, parameter);
+ return MODEACTION_ALLOW;
+ }
+ void SerializeParam(Channel* chan, const std::string* str, std::string& out)
+ {
+ out += *str;
}
};
@@ -92,75 +77,62 @@ class Redirect : public ModeHandler
class AntiRedirect : public SimpleUserModeHandler
{
public:
- AntiRedirect(Module* Creator) : SimpleUserModeHandler(Creator, "antiredirect", 'L') {}
+ AntiRedirect(Module* Creator) : SimpleUserModeHandler(Creator, "antiredirect", 'L')
+ {
+ if (!ServerInstance->Config->ConfValue("redirect")->getBool("antiredirect"))
+ DisableAutoRegister();
+ }
};
class ModuleRedirect : public Module
{
-
Redirect re;
AntiRedirect re_u;
+ ChanModeReference limitmode;
bool UseUsermode;
public:
-
ModuleRedirect()
- : re(this), re_u(this)
+ : re(this)
+ , re_u(this)
+ , limitmode(this, "limit")
{
}
- void init()
+ void init() CXX11_OVERRIDE
{
/* Setting this here so it isn't changable by rehasing the config later. */
UseUsermode = ServerInstance->Config->ConfValue("redirect")->getBool("antiredirect");
-
- /* Channel mode */
- ServerInstance->Modules->AddService(re);
-
- /* Check to see if the usermode is enabled in the config */
- if (UseUsermode)
- {
- /* Log noting that this breaks compatability. */
- ServerInstance->Logs->Log("m_redirect", DEFAULT, "REDIRECT: Enabled usermode +L. This breaks linking with servers that do not have this enabled. This is disabled by default in the 2.0 branch but will be enabled in the next version.");
-
- /* Try to add the usermode */
- ServerInstance->Modules->AddService(re_u);
- }
-
- Implementation eventlist[] = { I_OnUserPreJoin };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
}
- virtual ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven)
+ ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE
{
if (chan)
{
- if (chan->IsModeSet('L') && chan->IsModeSet('l'))
+ if (chan->IsModeSet(re) && chan->IsModeSet(limitmode))
{
- if (chan->GetUserCounter() >= ConvToInt(chan->GetModeParameter('l')))
+ if (chan->GetUserCounter() >= ConvToInt(chan->GetModeParameter(limitmode)))
{
- std::string channel = chan->GetModeParameter('L');
+ const std::string& channel = *re.ext.get(chan);
/* sometimes broken ulines can make circular or chained +L, avoid this */
- Channel* destchan = NULL;
- destchan = ServerInstance->FindChan(channel);
- if (destchan && destchan->IsModeSet('L'))
+ Channel* destchan = ServerInstance->FindChan(channel);
+ if (destchan && destchan->IsModeSet(re))
{
- user->WriteNumeric(470, "%s %s * :You may not join this channel. A redirect is set, but you may not be redirected as it is a circular loop.", user->nick.c_str(), cname);
+ user->WriteNumeric(470, "%s * :You may not join this channel. A redirect is set, but you may not be redirected as it is a circular loop.", cname.c_str());
return MOD_RES_DENY;
}
/* We check the bool value here to make sure we have it enabled, if we don't then
usermode +L might be assigned to something else. */
- if (UseUsermode && user->IsModeSet('L'))
+ if (UseUsermode && user->IsModeSet(re_u))
{
- user->WriteNumeric(470, "%s %s %s :Force redirection stopped.",
- user->nick.c_str(), cname, channel.c_str());
+ user->WriteNumeric(470, "%s %s :Force redirection stopped.", cname.c_str(), channel.c_str());
return MOD_RES_DENY;
}
else
{
- user->WriteNumeric(470, "%s %s %s :You may not join this channel, so you are automatically being transferred to the redirect channel.", user->nick.c_str(), cname, channel.c_str());
- Channel::JoinUser(user, channel.c_str(), false, "", false, ServerInstance->Time());
+ user->WriteNumeric(470, "%s %s :You may not join this channel, so you are automatically being transferred to the redirect channel.", cname.c_str(), channel.c_str());
+ Channel::JoinUser(user, channel);
return MOD_RES_DENY;
}
}
@@ -169,11 +141,7 @@ class ModuleRedirect : public Module
return MOD_RES_PASSTHRU;
}
- virtual ~ModuleRedirect()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides channel mode +L (limit redirection) and user mode +L (no forced redirection)", VF_VENDOR);
}
diff --git a/src/modules/m_regex.h b/src/modules/m_regex.h
deleted file mode 100644
index 0233f938a..000000000
--- a/src/modules/m_regex.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#ifndef M_REGEX_H
-#define M_REGEX_H
-
-#include "inspircd.h"
-
-class Regex : public classbase
-{
-protected:
- std::string regex_string; // The raw uncompiled regex string.
-
- // Constructor may as well be protected, as this class is abstract.
- Regex(const std::string& rx) : regex_string(rx)
- {
- }
-
-public:
-
- virtual ~Regex()
- {
- }
-
- virtual bool Matches(const std::string& text) = 0;
-
- const std::string& GetRegexString() const
- {
- return regex_string;
- }
-};
-
-class RegexFactory : public DataProvider
-{
- public:
- RegexFactory(Module* Creator, const std::string& Name) : DataProvider(Creator, Name) {}
-
- virtual Regex* Create(const std::string& expr) = 0;
-};
-
-#endif
diff --git a/src/modules/m_regex_glob.cpp b/src/modules/m_regex_glob.cpp
index 44d1a5898..9c3162885 100644
--- a/src/modules/m_regex_glob.cpp
+++ b/src/modules/m_regex_glob.cpp
@@ -18,11 +18,9 @@
*/
-#include "m_regex.h"
+#include "modules/regex.h"
#include "inspircd.h"
-/* $ModDesc: Regex module using plain wildcard matching. */
-
class GlobRegex : public Regex
{
public:
@@ -30,11 +28,7 @@ public:
{
}
- virtual ~GlobRegex()
- {
- }
-
- virtual bool Matches(const std::string& text)
+ bool Matches(const std::string& text) CXX11_OVERRIDE
{
return InspIRCd::Match(text, this->regex_string);
}
@@ -43,7 +37,7 @@ public:
class GlobFactory : public RegexFactory
{
public:
- Regex* Create(const std::string& expr)
+ Regex* Create(const std::string& expr) CXX11_OVERRIDE
{
return new GlobRegex(expr);
}
@@ -55,11 +49,12 @@ class ModuleRegexGlob : public Module
{
GlobFactory gf;
public:
- ModuleRegexGlob() : gf(this) {
- ServerInstance->Modules->AddService(gf);
+ ModuleRegexGlob()
+ : gf(this)
+ {
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Regex module using plain wildcard matching.", VF_VENDOR);
}
diff --git a/src/modules/m_regonlycreate.cpp b/src/modules/m_regonlycreate.cpp
index 61f94c0bd..0ffe5e085 100644
--- a/src/modules/m_regonlycreate.cpp
+++ b/src/modules/m_regonlycreate.cpp
@@ -21,28 +21,27 @@
#include "inspircd.h"
-#include "account.h"
-
-/* $ModDesc: Prevents users whose nicks are not registered from creating new channels */
+#include "modules/account.h"
class ModuleRegOnlyCreate : public Module
{
+ UserModeReference regusermode;
+
public:
- void init()
+ ModuleRegOnlyCreate()
+ : regusermode(this, "u_registered")
{
- Implementation eventlist[] = { I_OnUserPreJoin };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
}
- ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven)
+ ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE
{
if (chan)
return MOD_RES_PASSTHRU;
- if (IS_OPER(user))
+ if (user->IsOper())
return MOD_RES_PASSTHRU;
- if (user->IsModeSet('r'))
+ if (user->IsModeSet(regusermode))
return MOD_RES_PASSTHRU;
const AccountExtItem* ext = GetAccountExtItem();
@@ -50,15 +49,11 @@ class ModuleRegOnlyCreate : public Module
return MOD_RES_PASSTHRU;
// XXX. there may be a better numeric for this..
- user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have a registered nickname to create a new channel", user->nick.c_str(), cname);
+ user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s :You must have a registered nickname to create a new channel", cname.c_str());
return MOD_RES_DENY;
}
- ~ModuleRegOnlyCreate()
- {
- }
-
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Prevents users whose nicks are not registered from creating new channels", VF_VENDOR);
}
diff --git a/src/modules/m_remove.cpp b/src/modules/m_remove.cpp
index cf139f4a3..30924eb2f 100644
--- a/src/modules/m_remove.cpp
+++ b/src/modules/m_remove.cpp
@@ -24,8 +24,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides a /remove command, this is mostly an alternative to /kick, except makes users appear to have parted the channel */
-
/*
* This module supports the use of the +q and +a usermodes, but should work without them too.
* Usage of the command is restricted to +hoaq, and you cannot remove a user with a "higher" level than yourself.
@@ -36,23 +34,27 @@
*/
class RemoveBase : public Command
{
- private:
bool& supportnokicks;
+ ChanModeReference& nokicksmode;
public:
- RemoveBase(Module* Creator, bool& snk, const char* cmdn)
- : Command(Creator, cmdn, 2, 3), supportnokicks(snk)
+ unsigned int protectedrank;
+
+ RemoveBase(Module* Creator, bool& snk, ChanModeReference& nkm, const char* cmdn)
+ : Command(Creator, cmdn, 2, 3)
+ , supportnokicks(snk)
+ , nokicksmode(nkm)
{
}
- CmdResult HandleRMB(const std::vector<std::string>& parameters, User *user, bool neworder)
+ CmdResult HandleRMB(const std::vector<std::string>& parameters, User *user, bool fpart)
{
User* target;
Channel* channel;
std::string reason;
- std::string protectkey;
- std::string founderkey;
- bool hasnokicks;
+
+ // If the command is a /REMOVE then detect the parameter order
+ bool neworder = ((fpart) || (parameters[0][0] == '#'));
/* Set these to the parameters needed, the new version of this module switches it's parameters around
* supplying a new command with the new order while keeping the old /remove with the older order.
@@ -74,7 +76,7 @@ class RemoveBase : public Command
/* Fix by brain - someone needs to learn to validate their input! */
if ((!target) || (target->registered != REG_ALL) || (!channel))
{
- user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel", user->nick.c_str(), !channel ? channame.c_str() : username.c_str());
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", !channel ? channame.c_str() : username.c_str());
return CMD_FAILURE;
}
@@ -84,30 +86,38 @@ class RemoveBase : public Command
return CMD_FAILURE;
}
- int ulevel = channel->GetPrefixValue(user);
- int tlevel = channel->GetPrefixValue(target);
-
- hasnokicks = (ServerInstance->Modules->Find("m_nokicks.so") && channel->IsModeSet('Q'));
-
- if (ServerInstance->ULine(target->server))
+ if (target->server->IsULine())
{
- user->WriteNumeric(482, "%s %s :Only a u-line may remove a u-line from a channel.", user->nick.c_str(), channame.c_str());
+ user->WriteNumeric(482, "%s :Only a u-line may remove a u-line from a channel.", channame.c_str());
return CMD_FAILURE;
}
/* We support the +Q channel mode via. the m_nokicks module, if the module is loaded and the mode is set then disallow the /remove */
- if ((!IS_LOCAL(user)) || (!supportnokicks || !hasnokicks))
+ if ((!IS_LOCAL(user)) || (!supportnokicks) || (!channel->IsModeSet(nokicksmode)))
{
/* We'll let everyone remove their level and below, eg:
* ops can remove ops, halfops, voices, and those with no mode (no moders actually are set to 1)
* a ulined target will get a higher level than it's possible for a /remover to get..so they're safe.
- * Nobody may remove a founder.
+ * Nobody may remove people with >= protectedrank rank.
*/
- if ((!IS_LOCAL(user)) || ((ulevel > VOICE_VALUE) && (ulevel >= tlevel) && (tlevel != 50000)))
+ unsigned int ulevel = channel->GetPrefixValue(user);
+ unsigned int tlevel = channel->GetPrefixValue(target);
+ if ((!IS_LOCAL(user)) || ((ulevel > VOICE_VALUE) && (ulevel >= tlevel) && ((protectedrank == 0) || (tlevel < protectedrank))))
{
- // REMOVE/FPART will be sent to the target's server and it will reply with a PART (or do nothing if it doesn't understand the command)
+ // REMOVE will be sent to the target's server and it will reply with a PART (or do nothing if it doesn't understand the command)
if (!IS_LOCAL(target))
+ {
+ // Send an ENCAP REMOVE with parameters being in the old <user> <chan> order which is
+ // compatible with both 2.0 and 2.2. This also turns FPART into REMOVE.
+ std::vector<std::string> p;
+ p.push_back(target->uuid);
+ p.push_back(channel->name);
+ if (parameters.size() > 2)
+ p.push_back(":" + parameters[2]);
+ ServerInstance->PI->SendEncapsulatedData(target->server->GetName(), "REMOVE", p, user);
+
return CMD_SUCCESS;
+ }
std::string reasonparam;
@@ -121,7 +131,7 @@ class RemoveBase : public Command
reason = "Removed by " + user->nick + ": " + reasonparam;
channel->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s removed %s from the channel", channel->name.c_str(), user->nick.c_str(), target->nick.c_str());
- target->WriteServ("NOTICE %s :*** %s removed you from %s with the message: %s", target->nick.c_str(), user->nick.c_str(), channel->name.c_str(), reasonparam.c_str());
+ target->WriteNotice("*** " + user->nick + " removed you from " + channel->name + " with the message: " + reasonparam);
channel->PartUser(target, reason);
}
@@ -134,13 +144,12 @@ class RemoveBase : public Command
else
{
/* m_nokicks.so was loaded and +Q was set, block! */
- user->WriteServ( "484 %s %s :Can't remove user %s from channel (+Q set)", user->nick.c_str(), channel->name.c_str(), target->nick.c_str());
+ user->WriteNumeric(ERR_RESTRICTED, "%s :Can't remove user %s from channel (nokicks mode is set)", channel->name.c_str(), target->nick.c_str());
return CMD_FAILURE;
}
return CMD_SUCCESS;
}
- virtual RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) = 0;
};
/** Handle /REMOVE
@@ -148,25 +157,17 @@ class RemoveBase : public Command
class CommandRemove : public RemoveBase
{
public:
- CommandRemove(Module* Creator, bool& snk)
- : RemoveBase(Creator, snk, "REMOVE")
+ CommandRemove(Module* Creator, bool& snk, ChanModeReference& nkm)
+ : RemoveBase(Creator, snk, nkm, "REMOVE")
{
- syntax = "<nick> <channel> [<reason>]";
- TRANSLATE4(TR_NICK, TR_TEXT, TR_TEXT, TR_END);
+ syntax = "<channel> <nick> [<reason>]";
+ TRANSLATE3(TR_NICK, TR_TEXT, TR_TEXT);
}
CmdResult Handle (const std::vector<std::string>& parameters, User *user)
{
return HandleRMB(parameters, user, false);
}
-
- RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
- {
- User* dest = ServerInstance->FindNick(parameters[0]);
- if (dest)
- return ROUTE_OPT_UCAST(dest->server);
- return ROUTE_LOCALONLY;
- }
};
/** Handle /FPART
@@ -174,67 +175,50 @@ class CommandRemove : public RemoveBase
class CommandFpart : public RemoveBase
{
public:
- CommandFpart(Module* Creator, bool& snk)
- : RemoveBase(Creator, snk, "FPART")
+ CommandFpart(Module* Creator, bool& snk, ChanModeReference& nkm)
+ : RemoveBase(Creator, snk, nkm, "FPART")
{
syntax = "<channel> <nick> [<reason>]";
- TRANSLATE4(TR_TEXT, TR_NICK, TR_TEXT, TR_END);
+ TRANSLATE3(TR_TEXT, TR_NICK, TR_TEXT);
}
CmdResult Handle (const std::vector<std::string>& parameters, User *user)
{
return HandleRMB(parameters, user, true);
}
-
- RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
- {
- User* dest = ServerInstance->FindNick(parameters[1]);
- if (dest)
- return ROUTE_OPT_UCAST(dest->server);
- return ROUTE_LOCALONLY;
- }
};
class ModuleRemove : public Module
{
+ ChanModeReference nokicksmode;
CommandRemove cmd1;
CommandFpart cmd2;
bool supportnokicks;
-
public:
- ModuleRemove() : cmd1(this, supportnokicks), cmd2(this, supportnokicks)
- {
- }
-
- void init()
+ ModuleRemove()
+ : nokicksmode(this, "nokick")
+ , cmd1(this, supportnokicks, nokicksmode)
+ , cmd2(this, supportnokicks, nokicksmode)
{
- ServerInstance->Modules->AddService(cmd1);
- ServerInstance->Modules->AddService(cmd2);
- OnRehash(NULL);
- Implementation eventlist[] = { I_On005Numeric, I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
}
- virtual void On005Numeric(std::string &output)
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
- output.append(" REMOVE");
+ tokens["REMOVE"];
}
- virtual void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
- supportnokicks = ServerInstance->Config->ConfValue("remove")->getBool("supportnokicks");
+ ConfigTag* tag = ServerInstance->Config->ConfValue("remove");
+ supportnokicks = tag->getBool("supportnokicks");
+ cmd1.protectedrank = cmd2.protectedrank = tag->getInt("protectedrank", 50000);
}
- virtual ~ModuleRemove()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides a /remove command, this is mostly an alternative to /kick, except makes users appear to have parted the channel", VF_OPTCOMMON | VF_VENDOR);
}
-
};
MODULE_INIT(ModuleRemove)
diff --git a/src/modules/m_repeat.cpp b/src/modules/m_repeat.cpp
new file mode 100644
index 000000000..b992fe0f4
--- /dev/null
+++ b/src/modules/m_repeat.cpp
@@ -0,0 +1,403 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2013 Daniel Vassdal <shutter@canternet.org>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+
+class ChannelSettings
+{
+ public:
+ enum RepeatAction
+ {
+ ACT_KICK,
+ ACT_BLOCK,
+ ACT_BAN
+ };
+
+ RepeatAction Action;
+ unsigned int Backlog;
+ unsigned int Lines;
+ unsigned int Diff;
+ unsigned int Seconds;
+
+ void serialize(std::string& out) const
+ {
+ if (Action == ACT_BAN)
+ out.push_back('*');
+ else if (Action == ACT_BLOCK)
+ out.push_back('~');
+
+ out.append(ConvToStr(Lines)).push_back(':');
+ out.append(ConvToStr(Seconds));
+ if (Diff)
+ {
+ out.push_back(':');
+ out.append(ConvToStr(Diff));
+ if (Backlog)
+ {
+ out.push_back(':');
+ out.append(ConvToStr(Backlog));
+ }
+ }
+ }
+};
+
+class RepeatMode : public ParamMode<RepeatMode, SimpleExtItem<ChannelSettings> >
+{
+ private:
+ struct RepeatItem
+ {
+ time_t ts;
+ std::string line;
+ RepeatItem(time_t TS, const std::string& Line) : ts(TS), line(Line) { }
+ };
+
+ typedef std::deque<RepeatItem> RepeatItemList;
+
+ struct MemberInfo
+ {
+ RepeatItemList ItemList;
+ unsigned int Counter;
+ MemberInfo() : Counter(0) {}
+ };
+
+ struct ModuleSettings
+ {
+ unsigned int MaxLines;
+ unsigned int MaxSecs;
+ unsigned int MaxBacklog;
+ unsigned int MaxDiff;
+ unsigned int MaxMessageSize;
+ ModuleSettings() : MaxLines(0), MaxSecs(0), MaxBacklog(0), MaxDiff() { }
+ };
+
+ std::vector<unsigned int> mx[2];
+ ModuleSettings ms;
+
+ bool CompareLines(const std::string& message, const std::string& historyline, unsigned int trigger)
+ {
+ if (message == historyline)
+ return true;
+ else if (trigger)
+ return (Levenshtein(message, historyline) <= trigger);
+
+ return false;
+ }
+
+ unsigned int Levenshtein(const std::string& s1, const std::string& s2)
+ {
+ unsigned int l1 = s1.size();
+ unsigned int l2 = s2.size();
+
+ for (unsigned int i = 0; i < l2; i++)
+ mx[0][i] = i;
+ for (unsigned int i = 0; i < l1; i++)
+ {
+ mx[1][0] = i + 1;
+ for (unsigned int j = 0; j < l2; j++)
+ mx[1][j + 1] = std::min(std::min(mx[1][j] + 1, mx[0][j + 1] + 1), mx[0][j] + ((s1[i] == s2[j]) ? 0 : 1));
+
+ mx[0].swap(mx[1]);
+ }
+ return mx[0][l2];
+ }
+
+ public:
+ SimpleExtItem<MemberInfo> MemberInfoExt;
+
+ RepeatMode(Module* Creator)
+ : ParamMode<RepeatMode, SimpleExtItem<ChannelSettings> >(Creator, "repeat", 'E')
+ , MemberInfoExt("repeat_memb", Creator)
+ {
+ }
+
+ void OnUnset(User* source, Channel* chan)
+ {
+ // Unset the per-membership extension when the mode is removed
+ const Channel::MemberMap& users = chan->GetUsers();
+ for (Channel::MemberMap::const_iterator i = users.begin(); i != users.end(); ++i)
+ MemberInfoExt.unset(i->second);
+ }
+
+ ModeAction OnSet(User* source, Channel* channel, std::string& parameter)
+ {
+ ChannelSettings settings;
+ if (!ParseSettings(source, parameter, settings))
+ {
+ source->WriteNotice("*** Invalid syntax. Syntax is {[~*]}[lines]:[time]{:[difference]}{:[backlog]}");
+ return MODEACTION_DENY;
+ }
+
+ if ((settings.Backlog > 0) && (settings.Lines > settings.Backlog))
+ {
+ source->WriteNotice("*** You can't set needed lines higher than backlog");
+ return MODEACTION_DENY;
+ }
+
+ LocalUser* localsource = IS_LOCAL(source);
+ if ((localsource) && (!ValidateSettings(localsource, settings)))
+ return MODEACTION_DENY;
+
+ ext.set(channel, settings);
+
+ return MODEACTION_ALLOW;
+ }
+
+ bool MatchLine(Membership* memb, ChannelSettings* rs, std::string message)
+ {
+ // If the message is larger than whatever size it's set to,
+ // let's pretend it isn't. If the first 512 (def. setting) match, it's probably spam.
+ if (message.size() > ms.MaxMessageSize)
+ message.erase(ms.MaxMessageSize);
+
+ MemberInfo* rp = MemberInfoExt.get(memb);
+ if (!rp)
+ {
+ rp = new MemberInfo;
+ MemberInfoExt.set(memb, rp);
+ }
+
+ unsigned int matches = 0;
+ if (!rs->Backlog)
+ matches = rp->Counter;
+
+ RepeatItemList& items = rp->ItemList;
+ const unsigned int trigger = (message.size() * rs->Diff / 100);
+ const time_t now = ServerInstance->Time();
+
+ std::transform(message.begin(), message.end(), message.begin(), ::tolower);
+
+ for (std::deque<RepeatItem>::iterator it = items.begin(); it != items.end(); ++it)
+ {
+ if (it->ts < now)
+ {
+ items.erase(it, items.end());
+ matches = 0;
+ break;
+ }
+
+ if (CompareLines(message, it->line, trigger))
+ {
+ if (++matches >= rs->Lines)
+ {
+ if (rs->Action != ChannelSettings::ACT_BLOCK)
+ rp->Counter = 0;
+ return true;
+ }
+ }
+ else if ((ms.MaxBacklog == 0) || (rs->Backlog == 0))
+ {
+ matches = 0;
+ items.clear();
+ break;
+ }
+ }
+
+ unsigned int max_items = (rs->Backlog ? rs->Backlog : 1);
+ if (items.size() >= max_items)
+ items.pop_back();
+
+ items.push_front(RepeatItem(now + rs->Seconds, message));
+ rp->Counter = matches;
+ return false;
+ }
+
+ void Resize(size_t size)
+ {
+ size_t newsize = size+1;
+ if (newsize <= mx[0].size())
+ return;
+ ms.MaxMessageSize = size;
+ mx[0].resize(newsize);
+ mx[1].resize(newsize);
+ }
+
+ void ReadConfig()
+ {
+ ConfigTag* conf = ServerInstance->Config->ConfValue("repeat");
+ ms.MaxLines = conf->getInt("maxlines", 20);
+ ms.MaxBacklog = conf->getInt("maxbacklog", 20);
+ ms.MaxSecs = conf->getInt("maxsecs", 0);
+
+ ms.MaxDiff = conf->getInt("maxdistance", 50);
+ if (ms.MaxDiff > 100)
+ ms.MaxDiff = 100;
+
+ unsigned int newsize = conf->getInt("size", 512);
+ if (newsize > ServerInstance->Config->Limits.MaxLine)
+ newsize = ServerInstance->Config->Limits.MaxLine;
+ Resize(newsize);
+ }
+
+ std::string GetModuleSettings() const
+ {
+ return ConvToStr(ms.MaxLines) + ":" + ConvToStr(ms.MaxSecs) + ":" + ConvToStr(ms.MaxDiff) + ":" + ConvToStr(ms.MaxBacklog);
+ }
+
+ void SerializeParam(Channel* chan, const ChannelSettings* chset, std::string& out)
+ {
+ chset->serialize(out);
+ }
+
+ private:
+ bool ParseSettings(User* source, std::string& parameter, ChannelSettings& settings)
+ {
+ irc::sepstream stream(parameter, ':');
+ std::string item;
+ if (!stream.GetToken(item))
+ // Required parameter missing
+ return false;
+
+ if ((item[0] == '*') || (item[0] == '~'))
+ {
+ settings.Action = ((item[0] == '*') ? ChannelSettings::ACT_BAN : ChannelSettings::ACT_BLOCK);
+ item.erase(item.begin());
+ }
+ else
+ settings.Action = ChannelSettings::ACT_KICK;
+
+ if ((settings.Lines = ConvToInt(item)) == 0)
+ return false;
+
+ if ((!stream.GetToken(item)) || ((settings.Seconds = InspIRCd::Duration(item)) == 0))
+ // Required parameter missing
+ return false;
+
+ // The diff and backlog parameters are optional
+ settings.Diff = settings.Backlog = 0;
+ if (stream.GetToken(item))
+ {
+ // There is a diff parameter, see if it's valid (> 0)
+ if ((settings.Diff = ConvToInt(item)) == 0)
+ return false;
+
+ if (stream.GetToken(item))
+ {
+ // There is a backlog parameter, see if it's valid
+ if ((settings.Backlog = ConvToInt(item)) == 0)
+ return false;
+
+ // If there are still tokens, then it's invalid because we allow only 4
+ if (stream.GetToken(item))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ bool ValidateSettings(LocalUser* source, const ChannelSettings& settings)
+ {
+ if (settings.Backlog && !ms.MaxBacklog)
+ {
+ source->WriteNotice("*** The server administrator has disabled backlog matching");
+ return false;
+ }
+
+ if (settings.Diff)
+ {
+ if (settings.Diff > ms.MaxDiff)
+ {
+ if (ms.MaxDiff == 0)
+ source->WriteNotice("*** The server administrator has disabled matching on edit distance");
+ else
+ source->WriteNotice("*** The distance you specified is too great. Maximum allowed is " + ConvToStr(ms.MaxDiff));
+ return false;
+ }
+
+ if (ms.MaxLines && settings.Lines > ms.MaxLines)
+ {
+ source->WriteNotice("*** The line number you specified is too great. Maximum allowed is " + ConvToStr(ms.MaxLines));
+ return false;
+ }
+
+ if (ms.MaxSecs && settings.Seconds > ms.MaxSecs)
+ {
+ source->WriteNotice("*** The seconds you specified is too great. Maximum allowed is " + ConvToStr(ms.MaxSecs));
+ return false;
+ }
+ }
+
+ return true;
+ }
+};
+
+class RepeatModule : public Module
+{
+ RepeatMode rm;
+
+ public:
+ RepeatModule() : rm(this) {}
+
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
+ {
+ rm.ReadConfig();
+ }
+
+ ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE
+ {
+ if (target_type != TYPE_CHANNEL || !IS_LOCAL(user))
+ return MOD_RES_PASSTHRU;
+
+ Channel* chan = reinterpret_cast<Channel*>(dest);
+ ChannelSettings* settings = rm.ext.get(chan);
+ if (!settings)
+ return MOD_RES_PASSTHRU;
+
+ Membership* memb = chan->GetUser(user);
+ if (!memb)
+ return MOD_RES_PASSTHRU;
+
+ if (ServerInstance->OnCheckExemption(user, chan, "repeat") == MOD_RES_ALLOW)
+ return MOD_RES_PASSTHRU;
+
+ if (rm.MatchLine(memb, settings, text))
+ {
+ if (settings->Action == ChannelSettings::ACT_BLOCK)
+ {
+ user->WriteNotice("*** This line is too similiar to one of your last lines.");
+ return MOD_RES_DENY;
+ }
+
+ if (settings->Action == ChannelSettings::ACT_BAN)
+ {
+ std::vector<std::string> parameters;
+ parameters.push_back(memb->chan->name);
+ parameters.push_back("+b");
+ parameters.push_back("*!*@" + user->dhost);
+ ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient);
+ }
+
+ memb->chan->KickUser(ServerInstance->FakeClient, user, "Repeat flood");
+ return MOD_RES_DENY;
+ }
+ return MOD_RES_PASSTHRU;
+ }
+
+ void Prioritize() CXX11_OVERRIDE
+ {
+ ServerInstance->Modules->SetPriority(this, I_OnUserPreMessage, PRIORITY_LAST);
+ }
+
+ Version GetVersion() CXX11_OVERRIDE
+ {
+ return Version("Provides the +E channel mode - for blocking of similiar messages", VF_COMMON|VF_VENDOR, rm.GetModuleSettings());
+ }
+};
+
+MODULE_INIT(RepeatModule)
diff --git a/src/modules/m_restrictchans.cpp b/src/modules/m_restrictchans.cpp
index c76b0e79f..b619ee448 100644
--- a/src/modules/m_restrictchans.cpp
+++ b/src/modules/m_restrictchans.cpp
@@ -22,13 +22,12 @@
#include "inspircd.h"
-/* $ModDesc: Only opers may create new channels if this module is loaded */
-
class ModuleRestrictChans : public Module
{
- std::set<irc::string> allowchans;
+ std::set<std::string, irc::insensitive_swo> allowchans;
- void ReadConfig()
+ public:
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
allowchans.clear();
ConfigTagList tags = ServerInstance->Config->ConfTags("allowchannel");
@@ -36,48 +35,26 @@ class ModuleRestrictChans : public Module
{
ConfigTag* tag = i->second;
std::string txt = tag->getString("name");
- allowchans.insert(txt.c_str());
+ allowchans.insert(txt);
}
}
- public:
- void init()
- {
- ReadConfig();
- Implementation eventlist[] = { I_OnUserPreJoin, I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- virtual void OnRehash(User* user)
- {
- ReadConfig();
- }
-
-
- virtual ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven)
+ ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE
{
- irc::string x = cname;
- if (!IS_LOCAL(user))
- return MOD_RES_PASSTHRU;
-
// channel does not yet exist (record is null, about to be created IF we were to allow it)
if (!chan)
{
// user is not an oper and its not in the allow list
- if ((!IS_OPER(user)) && (allowchans.find(x) == allowchans.end()))
+ if ((!user->IsOper()) && (allowchans.find(cname) == allowchans.end()))
{
- user->WriteNumeric(ERR_BANNEDFROMCHAN, "%s %s :Only IRC operators may create new channels",user->nick.c_str(),cname);
+ user->WriteNumeric(ERR_BANNEDFROMCHAN, "%s :Only IRC operators may create new channels", cname.c_str());
return MOD_RES_DENY;
}
}
return MOD_RES_PASSTHRU;
}
- virtual ~ModuleRestrictChans()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Only opers may create new channels if this module is loaded",VF_VENDOR);
}
diff --git a/src/modules/m_restrictmsg.cpp b/src/modules/m_restrictmsg.cpp
index e814f3b16..e0887e587 100644
--- a/src/modules/m_restrictmsg.cpp
+++ b/src/modules/m_restrictmsg.cpp
@@ -21,22 +21,10 @@
#include "inspircd.h"
-/* $ModDesc: Forbids users from messaging each other. Users may still message opers and opers may message other opers. */
-
-
class ModuleRestrictMsg : public Module
{
-
public:
-
- void init()
- {
- Implementation eventlist[] = { I_OnUserPreMessage, I_OnUserPreNotice };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
-
- virtual ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+ ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE
{
if ((target_type == TYPE_USER) && (IS_LOCAL(user)))
{
@@ -46,11 +34,11 @@ class ModuleRestrictMsg : public Module
// (1) the sender is opered
// (2) the recipient is opered
// anything else, blocked.
- if (IS_OPER(u) || IS_OPER(user))
+ if (u->IsOper() || user->IsOper())
{
return MOD_RES_PASSTHRU;
}
- user->WriteNumeric(ERR_CANTSENDTOUSER, "%s %s :You are not permitted to send private messages to this user",user->nick.c_str(),u->nick.c_str());
+ user->WriteNumeric(ERR_CANTSENDTOUSER, "%s :You are not permitted to send private messages to this user", u->nick.c_str());
return MOD_RES_DENY;
}
@@ -58,16 +46,7 @@ class ModuleRestrictMsg : public Module
return MOD_RES_PASSTHRU;
}
- virtual ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
- {
- return this->OnUserPreMessage(user,dest,target_type,text,status,exempt_list);
- }
-
- virtual ~ModuleRestrictMsg()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Forbids users from messaging each other. Users may still message opers and opers may message other opers.",VF_VENDOR);
}
diff --git a/src/modules/m_ripemd160.cpp b/src/modules/m_ripemd160.cpp
index 04c27e83d..261cd1e27 100644
--- a/src/modules/m_ripemd160.cpp
+++ b/src/modules/m_ripemd160.cpp
@@ -56,25 +56,15 @@
*/
-/* $ModDesc: Allows for RIPEMD-160 encrypted oper passwords */
-
/* macro definitions */
#include "inspircd.h"
-#ifdef HAS_STDINT
-#include <stdint.h>
-#endif
-#include "hash.h"
+#include "modules/hash.h"
#define RMDsize 160
-#ifndef HAS_STDINT
-typedef unsigned char byte;
-typedef unsigned int dword;
-#else
-typedef uint8_t byte;
-typedef uint32_t dword;
-#endif
+typedef uint8_t byte;
+typedef uint32_t dword;
/* collect four bytes into one word: */
#define BYTES_TO_DWORD(strptr) \
@@ -167,7 +157,6 @@ class RIProv : public HashProvider
{
if (key)
{
- ServerInstance->Logs->Log("m_ripemd160.so", DEBUG, "initialize with custom mdbuf");
MDbuf[0] = key[0];
MDbuf[1] = key[1];
MDbuf[2] = key[2];
@@ -176,7 +165,6 @@ class RIProv : public HashProvider
}
else
{
- ServerInstance->Logs->Log("m_ripemd160.so", DEBUG, "initialize with default mdbuf");
MDbuf[0] = 0x67452301UL;
MDbuf[1] = 0xefcdab89UL;
MDbuf[2] = 0x98badcfeUL;
@@ -417,7 +405,6 @@ class RIProv : public HashProvider
byte *RMD(byte *message, dword length, unsigned int* key)
{
- ServerInstance->Logs->Log("m_ripemd160", DEBUG, "RMD: '%s' length=%u", (const char*)message, length);
dword MDbuf[RMDsize/32]; /* contains (A, B, C, D(E)) */
dword X[16]; /* current 16-word chunk */
unsigned int i; /* counter */
@@ -453,11 +440,6 @@ public:
return std::string(rv, RMDsize / 8);
}
- std::string sumIV(unsigned int* IV, const char* HexMap, const std::string &sdata)
- {
- return "";
- }
-
RIProv(Module* m) : HashProvider(m, "hash/ripemd160", 20, 64) {}
};
@@ -467,15 +449,12 @@ class ModuleRIPEMD160 : public Module
RIProv mr;
ModuleRIPEMD160() : mr(this)
{
- ServerInstance->Modules->AddService(mr);
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides RIPEMD-160 hashing", VF_VENDOR);
}
-
};
MODULE_INIT(ModuleRIPEMD160)
-
diff --git a/src/modules/m_rline.cpp b/src/modules/m_rline.cpp
index d1ab5d9ba..2aee89ad2 100644
--- a/src/modules/m_rline.cpp
+++ b/src/modules/m_rline.cpp
@@ -20,10 +20,8 @@
*/
-/* $ModDesc: RLINE: Regexp user banning. */
-
#include "inspircd.h"
-#include "m_regex.h"
+#include "modules/regex.h"
#include "xline.h"
static bool ZlineOnMatch = false;
@@ -60,7 +58,8 @@ class RLine : public XLine
bool Matches(User *u)
{
- if (u->exempt)
+ LocalUser* lu = IS_LOCAL(u);
+ if (lu && lu->exempt)
return false;
std::string compare = u->nick + "!" + u->ident + "@" + u->host + " " + u->fullname;
@@ -79,7 +78,7 @@ class RLine : public XLine
ZLine* zl = new ZLine(ServerInstance->Time(), duration ? expiry - ServerInstance->Time() : 0, ServerInstance->Config->ServerName.c_str(), reason.c_str(), u->GetIPString());
if (ServerInstance->XLines->AddLine(zl, NULL))
{
- std::string timestr = ServerInstance->TimeString(zl->expiry);
+ std::string timestr = InspIRCd::TimeString(zl->expiry);
ServerInstance->SNO->WriteToSnoMask('x', "Z-line added due to R-line match on *@%s%s%s: %s",
zl->ipaddr.c_str(), zl->duration ? " to expire on " : "", zl->duration ? timestr.c_str() : "", zl->reason.c_str());
added_zline = true;
@@ -90,15 +89,9 @@ class RLine : public XLine
DefaultApply(u, "R", false);
}
- void DisplayExpiry()
+ const std::string& Displayable()
{
- ServerInstance->SNO->WriteToSnoMask('x',"Removing expired R-line %s (set by %s %ld seconds ago)",
- this->matchtext.c_str(), this->source.c_str(), (long int)(ServerInstance->Time() - this->set_time));
- }
-
- const char* Displayable()
- {
- return matchtext.c_str();
+ return matchtext;
}
std::string matchtext;
@@ -116,7 +109,7 @@ class RLineFactory : public XLineFactory
RLineFactory(dynamic_reference<RegexFactory>& rx) : XLineFactory("R"), rxfactory(rx)
{
}
-
+
/** Generate a RLine
*/
XLine* Generate(time_t set_time, long duration, std::string source, std::string reason, std::string xline_specific_mask)
@@ -129,10 +122,6 @@ class RLineFactory : public XLineFactory
return new RLine(set_time, duration, source, reason, xline_specific_mask, rxfactory);
}
-
- ~RLineFactory()
- {
- }
};
/** Handle /RLINE
@@ -156,7 +145,7 @@ class CommandRLine : public Command
{
// Adding - XXX todo make this respect <insane> tag perhaps..
- long duration = ServerInstance->Duration(parameters[1]);
+ unsigned long duration = InspIRCd::Duration(parameters[1]);
XLine *r = NULL;
try
@@ -165,7 +154,7 @@ class CommandRLine : public Command
}
catch (ModuleException &e)
{
- ServerInstance->SNO->WriteToSnoMask('a',"Could not add RLINE: %s", e.GetReason());
+ ServerInstance->SNO->WriteToSnoMask('a',"Could not add RLINE: " + e.GetReason());
}
if (r)
@@ -179,7 +168,7 @@ class CommandRLine : public Command
else
{
time_t c_requires_crap = duration + ServerInstance->Time();
- std::string timestr = ServerInstance->TimeString(c_requires_crap);
+ std::string timestr = InspIRCd::TimeString(c_requires_crap);
ServerInstance->SNO->WriteToSnoMask('x', "%s added timed R-line for %s to expire on %s: %s", user->nick.c_str(), parameters[0].c_str(), timestr.c_str(), parameters[2].c_str());
}
@@ -188,7 +177,7 @@ class CommandRLine : public Command
else
{
delete r;
- user->WriteServ("NOTICE %s :*** R-Line for %s already exists", user->nick.c_str(), parameters[0].c_str());
+ user->WriteNotice("*** R-Line for " + parameters[0] + " already exists");
}
}
}
@@ -200,7 +189,7 @@ class CommandRLine : public Command
}
else
{
- user->WriteServ("NOTICE %s :*** R-Line %s not found in list, try /stats R.",user->nick.c_str(),parameters[0].c_str());
+ user->WriteNotice("*** R-Line " + parameters[0] + " not found in list, try /stats R.");
}
}
@@ -218,7 +207,6 @@ class CommandRLine : public Command
class ModuleRLine : public Module
{
- private:
dynamic_reference<RegexFactory> rxfactory;
RLineFactory f;
CommandRLine r;
@@ -233,29 +221,23 @@ class ModuleRLine : public Module
{
}
- void init()
+ void init() CXX11_OVERRIDE
{
- OnRehash(NULL);
-
- ServerInstance->Modules->AddService(r);
ServerInstance->XLines->RegisterFactory(&f);
-
- Implementation eventlist[] = { I_OnUserRegister, I_OnRehash, I_OnUserPostNick, I_OnStats, I_OnBackgroundTimer, I_OnUnloadModule };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
}
- virtual ~ModuleRLine()
+ ~ModuleRLine()
{
ServerInstance->XLines->DelAll("R");
ServerInstance->XLines->UnregisterFactory(&f);
}
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("RLINE: Regexp user banning.", VF_COMMON | VF_VENDOR, rxfactory ? rxfactory->name : "");
}
- ModResult OnUserRegister(LocalUser* user)
+ ModResult OnUserRegister(LocalUser* user) CXX11_OVERRIDE
{
// Apply lines on user connect
XLine *rl = ServerInstance->XLines->MatchesLine("R", user);
@@ -269,7 +251,7 @@ class ModuleRLine : public Module
return MOD_RES_PASSTHRU;
}
- virtual void OnRehash(User *user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ConfigTag* tag = ServerInstance->Config->ConfValue("rline");
@@ -302,7 +284,7 @@ class ModuleRLine : public Module
initing = false;
}
- virtual ModResult OnStats(char symbol, User* user, string_list &results)
+ ModResult OnStats(char symbol, User* user, string_list &results) CXX11_OVERRIDE
{
if (symbol != 'R')
return MOD_RES_PASSTHRU;
@@ -311,7 +293,7 @@ class ModuleRLine : public Module
return MOD_RES_DENY;
}
- virtual void OnUserPostNick(User *user, const std::string &oldnick)
+ void OnUserPostNick(User *user, const std::string &oldnick) CXX11_OVERRIDE
{
if (!IS_LOCAL(user))
return;
@@ -328,7 +310,7 @@ class ModuleRLine : public Module
}
}
- virtual void OnBackgroundTimer(time_t curtime)
+ void OnBackgroundTimer(time_t curtime) CXX11_OVERRIDE
{
if (added_zline)
{
@@ -337,7 +319,7 @@ class ModuleRLine : public Module
}
}
- void OnUnloadModule(Module* mod)
+ void OnUnloadModule(Module* mod) CXX11_OVERRIDE
{
// If the regex engine became unavailable or has changed, remove all rlines
if (!rxfactory)
diff --git a/src/modules/m_rmode.cpp b/src/modules/m_rmode.cpp
new file mode 100644
index 000000000..c81fbd7e7
--- /dev/null
+++ b/src/modules/m_rmode.cpp
@@ -0,0 +1,117 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2013 Daniel Vassdal <shutter@canternet.org>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "listmode.h"
+
+/** Handle /RMODE
+ */
+class CommandRMode : public Command
+{
+ public:
+ CommandRMode(Module* Creator) : Command(Creator,"RMODE", 2, 3)
+ {
+ allow_empty_last_param = false;
+ syntax = "<channel> <mode> [pattern]";
+ }
+
+ CmdResult Handle(const std::vector<std::string> &parameters, User *user)
+ {
+ ModeHandler* mh;
+ Channel* chan = ServerInstance->FindChan(parameters[0]);
+ char modeletter = parameters[1][0];
+
+ if (chan == NULL)
+ {
+ user->WriteNotice("The channel " + parameters[0] + " does not exist.");
+ return CMD_FAILURE;
+ }
+
+ mh = ServerInstance->Modes->FindMode(modeletter, MODETYPE_CHANNEL);
+ if (mh == NULL || parameters[1].size() > 1)
+ {
+ user->WriteNotice(parameters[1] + " is not a valid channel mode.");
+ return CMD_FAILURE;
+ }
+
+ if (chan->GetPrefixValue(user) < mh->GetLevelRequired())
+ {
+ user->WriteNotice("You do not have access to unset " + ConvToStr(modeletter) + " on " + chan->name + ".");
+ return CMD_FAILURE;
+ }
+
+ std::string pattern = parameters.size() > 2 ? parameters[2] : "*";
+ PrefixMode* pm;
+ ListModeBase* lm;
+ ListModeBase::ModeList* ml;
+ irc::modestacker modestack(false);
+
+ if ((pm = mh->IsPrefixMode()))
+ {
+ // As user prefix modes don't have a GetList() method, let's iterate through the channel's users.
+ const Channel::MemberMap& users = chan->GetUsers();
+ for (Channel::MemberMap::const_iterator it = users.begin(); it != users.end(); ++it)
+ {
+ if (!InspIRCd::Match(it->first->nick, pattern))
+ continue;
+ if (it->second->hasMode(modeletter) && !((it->first == user) && (pm->GetPrefixRank() > VOICE_VALUE)))
+ modestack.Push(modeletter, it->first->nick);
+ }
+ }
+ else if ((lm = mh->IsListModeBase()) && ((ml = lm->GetList(chan)) != NULL))
+ {
+ for (ListModeBase::ModeList::iterator it = ml->begin(); it != ml->end(); ++it)
+ {
+ if (!InspIRCd::Match(it->mask, pattern))
+ continue;
+ modestack.Push(modeletter, it->mask);
+ }
+ }
+ else
+ {
+ if (chan->IsModeSet(mh))
+ modestack.Push(modeletter);
+ }
+
+ parameterlist stackresult;
+ stackresult.push_back(chan->name);
+ while (modestack.GetStackedLine(stackresult))
+ {
+ ServerInstance->Modes->Process(stackresult, user);
+ stackresult.erase(stackresult.begin() + 1, stackresult.end());
+ }
+
+ return CMD_SUCCESS;
+ }
+};
+
+class ModuleRMode : public Module
+{
+ CommandRMode cmd;
+
+ public:
+ ModuleRMode() : cmd(this) { }
+
+ Version GetVersion() CXX11_OVERRIDE
+ {
+ return Version("Allows glob-based removal of list modes", VF_VENDOR);
+ }
+};
+
+MODULE_INIT(ModuleRMode)
diff --git a/src/modules/m_sajoin.cpp b/src/modules/m_sajoin.cpp
index 7ac465732..d1321947b 100644
--- a/src/modules/m_sajoin.cpp
+++ b/src/modules/m_sajoin.cpp
@@ -21,62 +21,71 @@
#include "inspircd.h"
-/* $ModDesc: Provides command SAJOIN to allow opers to force-join users to channels */
-
/** Handle /SAJOIN
*/
class CommandSajoin : public Command
{
public:
- CommandSajoin(Module* Creator) : Command(Creator,"SAJOIN", 2)
+ CommandSajoin(Module* Creator) : Command(Creator,"SAJOIN", 1)
{
allow_empty_last_param = false;
- flags_needed = 'o'; Penalty = 0; syntax = "<nick> <channel>";
- TRANSLATE3(TR_NICK, TR_TEXT, TR_END);
+ flags_needed = 'o'; Penalty = 0; syntax = "[<nick>] <channel>[,<channel>]";
+ TRANSLATE2(TR_NICK, TR_TEXT);
}
CmdResult Handle (const std::vector<std::string>& parameters, User *user)
{
- User* dest = ServerInstance->FindNick(parameters[0]);
+ const unsigned int channelindex = (parameters.size() > 1) ? 1 : 0;
+ if (CommandParser::LoopCall(user, this, parameters, channelindex))
+ return CMD_FAILURE;
+
+ const std::string& channel = parameters[channelindex];
+ const std::string& nickname = parameters.size() > 1 ? parameters[0] : user->nick;
+
+ User* dest = ServerInstance->FindNick(nickname);
if ((dest) && (dest->registered == REG_ALL))
{
- if (ServerInstance->ULine(dest->server))
+ if (user != dest && !user->HasPrivPermission("users/sajoin-others", false))
{
- user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Cannot use an SA command on a u-lined client",user->nick.c_str());
+ user->WriteNotice("*** You are not allowed to /SAJOIN other users (the privilege users/sajoin-others is needed to /SAJOIN others).");
return CMD_FAILURE;
}
- if (IS_LOCAL(user) && !ServerInstance->IsChannel(parameters[1].c_str(), ServerInstance->Config->Limits.ChanMax))
+
+ if (dest->server->IsULine())
+ {
+ user->WriteNumeric(ERR_NOPRIVILEGES, ":Cannot use an SA command on a u-lined client");
+ return CMD_FAILURE;
+ }
+ if (IS_LOCAL(user) && !ServerInstance->IsChannel(channel))
{
/* we didn't need to check this for each character ;) */
- user->WriteServ("NOTICE "+user->nick+" :*** Invalid characters in channel name or name too long");
+ user->WriteNotice("*** Invalid characters in channel name or name too long");
+ return CMD_FAILURE;
+ }
+
+ Channel* chan = ServerInstance->FindChan(channel);
+ if ((chan) && (chan->HasUser(dest)))
+ {
+ user->SendText(":" + user->server->GetName() + " NOTICE " + user->nick + " :*** " + dest->nick + " is already on " + channel);
return CMD_FAILURE;
}
- /* For local users, we send the JoinUser which may create a channel and set its TS.
+ /* For local users, we call Channel::JoinUser which may create a channel and set its TS.
* For non-local users, we just return CMD_SUCCESS, knowing this will propagate it where it needs to be
- * and then that server will generate the users JOIN or FJOIN instead.
+ * and then that server will handle the command.
*/
- if (IS_LOCAL(dest))
+ LocalUser* localuser = IS_LOCAL(dest);
+ if (localuser)
{
- Channel::JoinUser(dest, parameters[1].c_str(), true, "", false, ServerInstance->Time());
- /* Fix for dotslasher and w00t - if the join didnt succeed, return CMD_FAILURE so that it doesnt propagate */
- Channel* n = ServerInstance->FindChan(parameters[1]);
- if (n)
+ chan = Channel::JoinUser(localuser, channel, true);
+ if (chan)
{
- if (n->HasUser(dest))
- {
- ServerInstance->SNO->WriteGlobalSno('a', user->nick+" used SAJOIN to make "+dest->nick+" join "+parameters[1]);
- return CMD_SUCCESS;
- }
- else
- {
- user->WriteServ("NOTICE "+user->nick+" :*** Could not join "+dest->nick+" to "+parameters[1]+" (User is probably banned, or blocking modes)");
- return CMD_FAILURE;
- }
+ ServerInstance->SNO->WriteGlobalSno('a', user->nick+" used SAJOIN to make "+dest->nick+" join "+channel);
+ return CMD_SUCCESS;
}
else
{
- user->WriteServ("NOTICE "+user->nick+" :*** Could not join "+dest->nick+" to "+parameters[1]);
+ user->WriteNotice("*** Could not join "+dest->nick+" to "+channel);
return CMD_FAILURE;
}
}
@@ -87,7 +96,7 @@ class CommandSajoin : public Command
}
else
{
- user->WriteServ("NOTICE "+user->nick+" :*** No such nickname "+parameters[0]);
+ user->WriteNotice("*** No such nickname "+nickname);
return CMD_FAILURE;
}
}
@@ -110,20 +119,10 @@ class ModuleSajoin : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cmd);
- }
-
- virtual ~ModuleSajoin()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides command SAJOIN to allow opers to force-join users to channels", VF_OPTCOMMON | VF_VENDOR);
}
-
};
MODULE_INIT(ModuleSajoin)
diff --git a/src/modules/m_sakick.cpp b/src/modules/m_sakick.cpp
index 7dfcd8904..911b826dc 100644
--- a/src/modules/m_sakick.cpp
+++ b/src/modules/m_sakick.cpp
@@ -20,8 +20,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides a SAKICK command */
-
/** Handle /SAKICK
*/
class CommandSakick : public Command
@@ -30,29 +28,27 @@ class CommandSakick : public Command
CommandSakick(Module* Creator) : Command(Creator,"SAKICK", 2, 3)
{
flags_needed = 'o'; Penalty = 0; syntax = "<channel> <nick> [reason]";
- TRANSLATE4(TR_TEXT, TR_NICK, TR_TEXT, TR_END);
+ TRANSLATE3(TR_TEXT, TR_NICK, TR_TEXT);
}
CmdResult Handle (const std::vector<std::string>& parameters, User *user)
{
User* dest = ServerInstance->FindNick(parameters[1]);
Channel* channel = ServerInstance->FindChan(parameters[0]);
- const char* reason = "";
if ((dest) && (dest->registered == REG_ALL) && (channel))
{
- if (parameters.size() > 2)
- {
- reason = parameters[2].c_str();
- }
- else
+ const std::string& reason = (parameters.size() > 2) ? parameters[2] : dest->nick;
+
+ if (dest->server->IsULine())
{
- reason = dest->nick.c_str();
+ user->WriteNumeric(ERR_NOPRIVILEGES, ":Cannot use an SA command on a u-lined client");
+ return CMD_FAILURE;
}
- if (ServerInstance->ULine(dest->server))
+ if (!channel->HasUser(dest))
{
- user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Cannot use an SA command on a u-lined client", user->nick.c_str());
+ user->WriteNotice("*** " + dest->nick + " is not on " + channel->name);
return CMD_FAILURE;
}
@@ -62,28 +58,16 @@ class CommandSakick : public Command
*/
if (IS_LOCAL(dest))
{
+ // Target is on this server, kick them and send the snotice
channel->KickUser(ServerInstance->FakeClient, dest, reason);
-
- Channel *n = ServerInstance->FindChan(parameters[1]);
- if (n && n->HasUser(dest))
- {
- /* Sort-of-bug: If the command was issued remotely, this message won't be sent */
- user->WriteServ("NOTICE %s :*** Unable to kick %s from %s", user->nick.c_str(), dest->nick.c_str(), parameters[0].c_str());
- return CMD_FAILURE;
- }
- }
-
- if (IS_LOCAL(user))
- {
- /* Locally issued command; send the snomasks */
- ServerInstance->SNO->WriteGlobalSno('a', user->nick + " SAKICKed " + dest->nick + " on " + parameters[0]);
+ ServerInstance->SNO->WriteGlobalSno('a', user->nick + " SAKICKed " + dest->nick + " on " + channel->name);
}
return CMD_SUCCESS;
}
else
{
- user->WriteServ("NOTICE %s :*** Invalid nickname or channel", user->nick.c_str());
+ user->WriteNotice("*** Invalid nickname or channel");
}
return CMD_FAILURE;
@@ -107,21 +91,10 @@ class ModuleSakick : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cmd);
- }
-
- virtual ~ModuleSakick()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides a SAKICK command", VF_OPTCOMMON|VF_VENDOR);
}
-
};
MODULE_INIT(ModuleSakick)
-
diff --git a/src/modules/m_samode.cpp b/src/modules/m_samode.cpp
index ea2ae24ab..14f79aaf7 100644
--- a/src/modules/m_samode.cpp
+++ b/src/modules/m_samode.cpp
@@ -20,8 +20,6 @@
*/
-/* $ModDesc: Provides command SAMODE to allow opers to change modes on channels and users */
-
#include "inspircd.h"
/** Handle /SAMODE
@@ -48,9 +46,14 @@ class CommandSamode : public Command
return CMD_FAILURE;
}
}
-
+ User* target = ServerInstance->FindNick(parameters[0]);
+ if ((target) && (target != user))
+ {
+ if (!user->HasPrivPermission("users/samode-usermodes", true))
+ return CMD_FAILURE;
+ }
this->active = true;
- ServerInstance->Parser->CallHandler("MODE", parameters, user);
+ ServerInstance->Modes->Process(parameters, user);
if (ServerInstance->Modes->GetLastParse().length())
ServerInstance->SNO->WriteGlobalSno('a', user->nick + " used SAMODE: " +ServerInstance->Modes->GetLastParse());
this->active = false;
@@ -67,22 +70,12 @@ class ModuleSaMode : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cmd);
- ServerInstance->Modules->Attach(I_OnPreMode, this);
- }
-
- ~ModuleSaMode()
- {
- }
-
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides command SAMODE to allow opers to change modes on channels and users", VF_VENDOR);
}
- ModResult OnPreMode(User* source,User* dest,Channel* channel, const std::vector<std::string>& parameters)
+ ModResult OnPreMode(User* source,User* dest,Channel* channel, const std::vector<std::string>& parameters) CXX11_OVERRIDE
{
if (cmd.active)
return MOD_RES_ALLOW;
diff --git a/src/modules/m_sanick.cpp b/src/modules/m_sanick.cpp
index 4e4be77ae..ba265fddd 100644
--- a/src/modules/m_sanick.cpp
+++ b/src/modules/m_sanick.cpp
@@ -21,8 +21,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides support for SANICK command */
-
/** Handle /SANICK
*/
class CommandSanick : public Command
@@ -32,7 +30,7 @@ class CommandSanick : public Command
{
allow_empty_last_param = false;
flags_needed = 'o'; Penalty = 0; syntax = "<nick> <new-nick>";
- TRANSLATE3(TR_NICK, TR_TEXT, TR_END);
+ TRANSLATE2(TR_NICK, TR_TEXT);
}
CmdResult Handle (const std::vector<std::string>& parameters, User *user)
@@ -42,21 +40,21 @@ class CommandSanick : public Command
/* Do local sanity checks and bails */
if (IS_LOCAL(user))
{
- if (target && ServerInstance->ULine(target->server))
+ if (target && target->server->IsULine())
{
- user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Cannot use an SA command on a u-lined client",user->nick.c_str());
+ user->WriteNumeric(ERR_NOPRIVILEGES, ":Cannot use an SA command on a u-lined client");
return CMD_FAILURE;
}
if ((!target) || (target->registered != REG_ALL))
{
- user->WriteServ("NOTICE %s :*** No such nickname: '%s'", user->nick.c_str(), parameters[0].c_str());
+ user->WriteNotice("*** No such nickname: '" + parameters[0] + "'");
return CMD_FAILURE;
}
- if (!ServerInstance->IsNick(parameters[1].c_str(), ServerInstance->Config->Limits.NickMax))
+ if (!ServerInstance->IsNick(parameters[1]))
{
- user->WriteServ("NOTICE %s :*** Invalid nickname '%s'", user->nick.c_str(), parameters[1].c_str());
+ user->WriteNotice("*** Invalid nickname '" + parameters[1] + "'");
return CMD_FAILURE;
}
}
@@ -66,7 +64,7 @@ class CommandSanick : public Command
{
std::string oldnick = user->nick;
std::string newnick = target->nick;
- if (target->ChangeNick(parameters[1], true))
+ if (target->ChangeNick(parameters[1]))
{
ServerInstance->SNO->WriteGlobalSno('a', oldnick+" used SANICK to change "+newnick+" to "+parameters[1]);
}
@@ -98,20 +96,10 @@ class ModuleSanick : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cmd);
- }
-
- virtual ~ModuleSanick()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for SANICK command", VF_OPTCOMMON | VF_VENDOR);
}
-
};
MODULE_INIT(ModuleSanick)
diff --git a/src/modules/m_sapart.cpp b/src/modules/m_sapart.cpp
index 89256e0e4..730bf0823 100644
--- a/src/modules/m_sapart.cpp
+++ b/src/modules/m_sapart.cpp
@@ -21,8 +21,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides command SAPART to force-part users from a channel. */
-
/** Handle /SAPART
*/
class CommandSapart : public Command
@@ -30,12 +28,15 @@ class CommandSapart : public Command
public:
CommandSapart(Module* Creator) : Command(Creator,"SAPART", 2, 3)
{
- flags_needed = 'o'; Penalty = 0; syntax = "<nick> <channel> [reason]";
- TRANSLATE4(TR_NICK, TR_TEXT, TR_TEXT, TR_END);
+ flags_needed = 'o'; Penalty = 0; syntax = "<nick> <channel>[,<channel>] [reason]";
+ TRANSLATE3(TR_NICK, TR_TEXT, TR_TEXT);
}
CmdResult Handle (const std::vector<std::string>& parameters, User *user)
{
+ if (CommandParser::LoopCall(user, this, parameters, 1))
+ return CMD_FAILURE;
+
User* dest = ServerInstance->FindNick(parameters[0]);
Channel* channel = ServerInstance->FindChan(parameters[1]);
std::string reason;
@@ -45,9 +46,15 @@ class CommandSapart : public Command
if (parameters.size() > 2)
reason = parameters[2];
- if (ServerInstance->ULine(dest->server))
+ if (dest->server->IsULine())
+ {
+ user->WriteNumeric(ERR_NOPRIVILEGES, ":Cannot use an SA command on a u-lined client");
+ return CMD_FAILURE;
+ }
+
+ if (!channel->HasUser(dest))
{
- user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Cannot use an SA command on a u-lined client",user->nick.c_str());
+ user->WriteNotice("*** " + dest->nick + " is not on " + channel->name);
return CMD_FAILURE;
}
@@ -58,33 +65,14 @@ class CommandSapart : public Command
if (IS_LOCAL(dest))
{
channel->PartUser(dest, reason);
-
- Channel* n = ServerInstance->FindChan(parameters[1]);
- if (!n)
- {
- ServerInstance->SNO->WriteGlobalSno('a', user->nick+" used SAPART to make "+dest->nick+" part "+parameters[1]);
- return CMD_SUCCESS;
- }
- else
- {
- if (!n->HasUser(dest))
- {
- ServerInstance->SNO->WriteGlobalSno('a', user->nick+" used SAPART to make "+dest->nick+" part "+parameters[1]);
- return CMD_SUCCESS;
- }
- else
- {
- user->WriteServ("NOTICE %s :*** Unable to make %s part %s",user->nick.c_str(), dest->nick.c_str(), parameters[1].c_str());
- return CMD_FAILURE;
- }
- }
+ ServerInstance->SNO->WriteGlobalSno('a', user->nick+" used SAPART to make "+dest->nick+" part "+channel->name);
}
return CMD_SUCCESS;
}
else
{
- user->WriteServ("NOTICE %s :*** Invalid nickname or channel", user->nick.c_str());
+ user->WriteNotice("*** Invalid nickname or channel");
}
return CMD_FAILURE;
@@ -109,21 +97,10 @@ class ModuleSapart : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cmd);
- }
-
- virtual ~ModuleSapart()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides command SAPART to force-part users from a channel.", VF_OPTCOMMON | VF_VENDOR);
}
-
};
MODULE_INIT(ModuleSapart)
-
diff --git a/src/modules/m_saquit.cpp b/src/modules/m_saquit.cpp
index 909a026ab..aa6aa0180 100644
--- a/src/modules/m_saquit.cpp
+++ b/src/modules/m_saquit.cpp
@@ -21,8 +21,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides support for an SAQUIT command, exits user with a reason */
-
/** Handle /SAQUIT
*/
class CommandSaquit : public Command
@@ -31,7 +29,7 @@ class CommandSaquit : public Command
CommandSaquit(Module* Creator) : Command(Creator, "SAQUIT", 2, 2)
{
flags_needed = 'o'; Penalty = 0; syntax = "<nick> <reason>";
- TRANSLATE3(TR_NICK, TR_TEXT, TR_END);
+ TRANSLATE2(TR_NICK, TR_TEXT);
}
CmdResult Handle (const std::vector<std::string>& parameters, User *user)
@@ -39,16 +37,16 @@ class CommandSaquit : public Command
User* dest = ServerInstance->FindNick(parameters[0]);
if ((dest) && (!IS_SERVER(dest)) && (dest->registered == REG_ALL))
{
- if (ServerInstance->ULine(dest->server))
+ if (dest->server->IsULine())
{
- user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Cannot use an SA command on a u-lined client",user->nick.c_str());
+ user->WriteNumeric(ERR_NOPRIVILEGES, ":Cannot use an SA command on a u-lined client");
return CMD_FAILURE;
}
// Pass the command on, so the client's server can quit it properly.
if (!IS_LOCAL(dest))
return CMD_SUCCESS;
-
+
ServerInstance->SNO->WriteGlobalSno('a', user->nick+" used SAQUIT to make "+dest->nick+" quit with a reason of "+parameters[1]);
ServerInstance->Users->QuitUser(dest, parameters[1]);
@@ -56,7 +54,7 @@ class CommandSaquit : public Command
}
else
{
- user->WriteServ("NOTICE %s :*** Invalid nickname '%s'", user->nick.c_str(), parameters[0].c_str());
+ user->WriteNotice("*** Invalid nickname '" + parameters[0] + "'");
return CMD_FAILURE;
}
}
@@ -79,20 +77,10 @@ class ModuleSaquit : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cmd);
- }
-
- virtual ~ModuleSaquit()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for an SAQUIT command, exits user with a reason", VF_OPTCOMMON | VF_VENDOR);
}
-
};
MODULE_INIT(ModuleSaquit)
diff --git a/src/modules/m_sasl.cpp b/src/modules/m_sasl.cpp
index 66efcfe4e..074362651 100644
--- a/src/modules/m_sasl.cpp
+++ b/src/modules/m_sasl.cpp
@@ -19,12 +19,10 @@
#include "inspircd.h"
-#include "m_cap.h"
-#include "account.h"
-#include "sasl.h"
-#include "ssl.h"
-
-/* $ModDesc: Provides support for IRC Authentication Layer (aka: atheme SASL) via AUTHENTICATE. */
+#include "modules/cap.h"
+#include "modules/account.h"
+#include "modules/sasl.h"
+#include "modules/ssl.h"
enum SaslState { SASL_INIT, SASL_COMM, SASL_DONE };
enum SaslResult { SASL_OK, SASL_FAIL, SASL_ABORT };
@@ -33,7 +31,7 @@ static std::string sasl_target = "*";
static void SendSASL(const parameterlist& params)
{
- if (!ServerInstance->PI->SendEncapsulatedData(params))
+ if (!ServerInstance->PI->SendEncapsulatedData(sasl_target, "SASL", params))
{
SASLFallback(NULL, params);
}
@@ -56,17 +54,15 @@ class SaslAuthenticator
: user(user_), state(SASL_INIT), state_announced(false)
{
parameterlist params;
- params.push_back(sasl_target);
- params.push_back("SASL");
params.push_back(user->uuid);
params.push_back("*");
params.push_back("S");
params.push_back(method);
- if (method == "EXTERNAL" && IS_LOCAL(user_))
+ LocalUser* localuser = IS_LOCAL(user);
+ if (method == "EXTERNAL" && localuser)
{
- SocketCertificateRequest req(&((LocalUser*)user_)->eh, ServerInstance->Modules->Find("m_sasl.so"));
- std::string fp = req.GetFingerprint();
+ std::string fp = SSLClientCert::GetFingerprint(&localuser->eh);
if (fp.size())
params.push_back(fp);
@@ -109,13 +105,13 @@ class SaslAuthenticator
else if (msg[2] == "M")
this->user->WriteNumeric(908, "%s %s :are available SASL mechanisms", this->user->nick.c_str(), msg[3].c_str());
else
- ServerInstance->Logs->Log("m_sasl", DEFAULT, "Services sent an unknown SASL message \"%s\" \"%s\"", msg[2].c_str(), msg[3].c_str());
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Services sent an unknown SASL message \"%s\" \"%s\"", msg[2].c_str(), msg[3].c_str());
break;
case SASL_DONE:
break;
default:
- ServerInstance->Logs->Log("m_sasl", DEFAULT, "WTF: SaslState is not a known state (%d)", this->state);
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "WTF: SaslState is not a known state (%d)", this->state);
break;
}
@@ -134,8 +130,6 @@ class SaslAuthenticator
return true;
parameterlist params;
- params.push_back(sasl_target);
- params.push_back("SASL");
params.push_back(this->user->uuid);
params.push_back(this->agent);
params.push_back("C");
@@ -161,13 +155,13 @@ class SaslAuthenticator
switch (this->result)
{
case SASL_OK:
- this->user->WriteNumeric(903, "%s :SASL authentication successful", this->user->nick.c_str());
+ this->user->WriteNumeric(903, ":SASL authentication successful");
break;
case SASL_ABORT:
- this->user->WriteNumeric(906, "%s :SASL authentication aborted", this->user->nick.c_str());
+ this->user->WriteNumeric(906, ":SASL authentication aborted");
break;
case SASL_FAIL:
- this->user->WriteNumeric(904, "%s :SASL authentication failed", this->user->nick.c_str());
+ this->user->WriteNumeric(904, ":SASL authentication failed");
break;
default:
break;
@@ -223,7 +217,7 @@ class CommandSASL : public Command
User* target = ServerInstance->FindNick(parameters[1]);
if ((!target) || (IS_SERVER(target)))
{
- ServerInstance->Logs->Log("m_sasl", DEBUG,"User not found in sasl ENCAP event: %s", parameters[1].c_str());
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "User not found in sasl ENCAP event: %s", parameters[1].c_str());
return CMD_FAILURE;
}
@@ -252,31 +246,25 @@ class ModuleSASL : public Module
GenericCap cap;
CommandAuthenticate auth;
CommandSASL sasl;
+
public:
ModuleSASL()
: authExt("sasl_auth", this), cap(this, "sasl"), auth(this, authExt, cap), sasl(this, authExt)
{
}
- void init()
+ void init() CXX11_OVERRIDE
{
- OnRehash(NULL);
- Implementation eventlist[] = { I_OnEvent, I_OnUserRegister, I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
-
- ServiceProvider* providelist[] = { &auth, &sasl, &authExt };
- ServerInstance->Modules->AddServices(providelist, 3);
-
if (!ServerInstance->Modules->Find("m_services_account.so") || !ServerInstance->Modules->Find("m_cap.so"))
- ServerInstance->Logs->Log("m_sasl", DEFAULT, "WARNING: m_services_account.so and m_cap.so are not loaded! m_sasl.so will NOT function correctly until these two modules are loaded!");
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "WARNING: m_services_account.so and m_cap.so are not loaded! m_sasl.so will NOT function correctly until these two modules are loaded!");
}
- void OnRehash(User*)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
sasl_target = ServerInstance->Config->ConfValue("sasl")->getString("target", "*");
}
- ModResult OnUserRegister(LocalUser *user)
+ ModResult OnUserRegister(LocalUser *user) CXX11_OVERRIDE
{
SaslAuthenticator *sasl_ = authExt.get(user);
if (sasl_)
@@ -288,12 +276,12 @@ class ModuleSASL : public Module
return MOD_RES_PASSTHRU;
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for IRC Authentication Layer (aka: atheme SASL) via AUTHENTICATE.",VF_VENDOR);
}
- void OnEvent(Event &ev)
+ void OnEvent(Event &ev) CXX11_OVERRIDE
{
cap.HandleEvent(ev);
}
diff --git a/src/modules/m_satopic.cpp b/src/modules/m_satopic.cpp
index ae1c19d91..4a6f85536 100644
--- a/src/modules/m_satopic.cpp
+++ b/src/modules/m_satopic.cpp
@@ -17,8 +17,6 @@
*/
-/* $ModDesc: Provides a SATOPIC command */
-
#include "inspircd.h"
/** Handle /SATOPIC
@@ -40,17 +38,15 @@ class CommandSATopic : public Command
if(target)
{
- std::string newTopic = parameters[1];
-
- // 3rd parameter overrides access checks
- target->SetTopic(user, newTopic, true);
+ const std::string& newTopic = parameters[1];
+ target->SetTopic(user, newTopic);
ServerInstance->SNO->WriteGlobalSno('a', user->nick + " used SATOPIC on " + target->name + ", new topic: " + newTopic);
return CMD_SUCCESS;
}
else
{
- user->WriteNumeric(401, "%s %s :No such nick/channel", user->nick.c_str(), parameters[0].c_str());
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", parameters[0].c_str());
return CMD_FAILURE;
}
}
@@ -65,16 +61,7 @@ class ModuleSATopic : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cmd);
- }
-
- virtual ~ModuleSATopic()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides a SATOPIC command", VF_VENDOR);
}
diff --git a/src/modules/m_securelist.cpp b/src/modules/m_securelist.cpp
index 6013d1fd7..f4042b8f6 100644
--- a/src/modules/m_securelist.cpp
+++ b/src/modules/m_securelist.cpp
@@ -21,31 +21,18 @@
#include "inspircd.h"
-/* $ModDesc: Disallows /LIST for recently connected clients to hinder spam bots */
-
class ModuleSecureList : public Module
{
- private:
std::vector<std::string> allowlist;
time_t WaitTime;
- public:
- void init()
- {
- OnRehash(NULL);
- Implementation eventlist[] = { I_OnRehash, I_OnPreCommand, I_On005Numeric };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
- virtual ~ModuleSecureList()
- {
- }
-
- virtual Version GetVersion()
+ public:
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Disallows /LIST for recently connected clients to hinder spam bots", VF_VENDOR);
}
- void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
allowlist.clear();
@@ -61,13 +48,13 @@ class ModuleSecureList : public Module
* OnPreCommand()
* Intercept the LIST command.
*/
- virtual ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line)
+ ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line) CXX11_OVERRIDE
{
/* If the command doesnt appear to be valid, we dont want to mess with it. */
if (!validated)
return MOD_RES_PASSTHRU;
- if ((command == "LIST") && (ServerInstance->Time() < (user->signon+WaitTime)) && (!IS_OPER(user)))
+ if ((command == "LIST") && (ServerInstance->Time() < (user->signon+WaitTime)) && (!user->IsOper()))
{
/* Normally wouldnt be allowed here, are they exempt? */
for (std::vector<std::string>::iterator x = allowlist.begin(); x != allowlist.end(); x++)
@@ -75,20 +62,20 @@ class ModuleSecureList : public Module
return MOD_RES_PASSTHRU;
/* Not exempt, BOOK EM DANNO! */
- user->WriteServ("NOTICE %s :*** You cannot list within the first %lu seconds of connecting. Please try again later.",user->nick.c_str(), (unsigned long) WaitTime);
+ user->WriteNotice("*** You cannot list within the first " + ConvToStr(WaitTime) + " seconds of connecting. Please try again later.");
/* Some crap clients (read: mIRC, various java chat applets) muck up if they don't
* receive these numerics whenever they send LIST, so give them an empty LIST to mull over.
*/
- user->WriteNumeric(321, "%s Channel :Users Name",user->nick.c_str());
- user->WriteNumeric(323, "%s :End of channel list.",user->nick.c_str());
+ user->WriteNumeric(RPL_LISTSTART, "Channel :Users Name");
+ user->WriteNumeric(RPL_LISTEND, ":End of channel list.");
return MOD_RES_DENY;
}
return MOD_RES_PASSTHRU;
}
- virtual void On005Numeric(std::string &output)
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
- output.append(" SECURELIST");
+ tokens["SECURELIST"];
}
};
diff --git a/src/modules/m_seenicks.cpp b/src/modules/m_seenicks.cpp
index 95872b5b2..bff3516f1 100644
--- a/src/modules/m_seenicks.cpp
+++ b/src/modules/m_seenicks.cpp
@@ -21,24 +21,20 @@
#include "inspircd.h"
-/* $ModDesc: Provides support for seeing local and remote nickchanges via snomasks 'n' and 'N'. */
-
class ModuleSeeNicks : public Module
{
public:
- void init()
+ void init() CXX11_OVERRIDE
{
ServerInstance->SNO->EnableSnomask('n',"NICK");
- Implementation eventlist[] = { I_OnUserPostNick };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
}
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for seeing local and remote nickchanges via snomasks", VF_VENDOR);
}
- virtual void OnUserPostNick(User* user, const std::string &oldnick)
+ void OnUserPostNick(User* user, const std::string &oldnick) CXX11_OVERRIDE
{
ServerInstance->SNO->WriteToSnoMask(IS_LOCAL(user) ? 'n' : 'N',"User %s changed their nickname to %s", oldnick.c_str(), user->nick.c_str());
}
diff --git a/src/modules/m_serverban.cpp b/src/modules/m_serverban.cpp
index cf77ae9ba..f51d1d373 100644
--- a/src/modules/m_serverban.cpp
+++ b/src/modules/m_serverban.cpp
@@ -19,43 +19,28 @@
#include "inspircd.h"
-/* $ModDesc: Implements extban +b s: - server name bans */
-
class ModuleServerBan : public Module
{
- private:
public:
- void init()
- {
- Implementation eventlist[] = { I_OnCheckBan, I_On005Numeric };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- ~ModuleServerBan()
- {
- }
-
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Extban 's' - server ban",VF_OPTCOMMON|VF_VENDOR);
}
- ModResult OnCheckBan(User *user, Channel *c, const std::string& mask)
+ ModResult OnCheckBan(User *user, Channel *c, const std::string& mask) CXX11_OVERRIDE
{
if ((mask.length() > 2) && (mask[0] == 's') && (mask[1] == ':'))
{
- if (InspIRCd::Match(user->server, mask.substr(2)))
+ if (InspIRCd::Match(user->server->GetName(), mask.substr(2)))
return MOD_RES_DENY;
}
return MOD_RES_PASSTHRU;
}
- void On005Numeric(std::string &output)
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
- ServerInstance->AddExtBanChar('s');
+ tokens["EXTBAN"].push_back('s');
}
};
-
MODULE_INIT(ModuleServerBan)
-
diff --git a/src/modules/m_services_account.cpp b/src/modules/m_services_account.cpp
index 154968e9e..edb6f6ef5 100644
--- a/src/modules/m_services_account.cpp
+++ b/src/modules/m_services_account.cpp
@@ -22,10 +22,8 @@
*/
-/* $ModDesc: Provides support for ircu-style services accounts, including chmode +R, etc. */
-
#include "inspircd.h"
-#include "account.h"
+#include "modules/account.h"
/** Channel mode +r - mark a channel as identified
*/
@@ -40,15 +38,15 @@ class Channel_r : public ModeHandler
if (!IS_LOCAL(source))
{
// Only change the mode if it's not redundant
- if ((adding != channel->IsModeSet('r')))
+ if ((adding != channel->IsModeSet(this)))
{
- channel->SetMode('r',adding);
+ channel->SetMode(this, adding);
return MODEACTION_ALLOW;
}
}
else
{
- source->WriteNumeric(500, "%s :Only a server may modify the +r channel mode", source->nick.c_str());
+ source->WriteNumeric(500, ":Only a server may modify the +r channel mode");
}
return MODEACTION_DENY;
}
@@ -66,15 +64,15 @@ class User_r : public ModeHandler
{
if (!IS_LOCAL(source))
{
- if ((adding != dest->IsModeSet('r')))
+ if ((adding != dest->IsModeSet(this)))
{
- dest->SetMode('r',adding);
+ dest->SetMode(this, adding);
return MODEACTION_ALLOW;
}
}
else
{
- source->WriteNumeric(500, "%s :Only a server may modify the +r user mode", source->nick.c_str());
+ source->WriteNumeric(500, ":Only a server may modify the +r user mode");
}
return MODEACTION_DENY;
}
@@ -104,6 +102,40 @@ class AChannel_M : public SimpleChannelModeHandler
AChannel_M(Module* Creator) : SimpleChannelModeHandler(Creator, "regmoderated", 'M') { }
};
+class AccountExtItemImpl : public AccountExtItem
+{
+ public:
+ AccountExtItemImpl(Module* mod)
+ : AccountExtItem("accountname", mod)
+ {
+ }
+
+ void unserialize(SerializeFormat format, Extensible* container, const std::string& value)
+ {
+ User* user = dynamic_cast<User*>(container);
+ if (!user)
+ return;
+
+ StringExtItem::unserialize(format, container, value);
+ if (!value.empty())
+ {
+ // Logged in
+ if (IS_LOCAL(user))
+ {
+ user->WriteNumeric(900, "%s %s :You are now logged in as %s",
+ user->GetFullHost().c_str(), value.c_str(), value.c_str());
+ }
+
+ AccountEvent(creator, user, value).Send();
+ }
+ else
+ {
+ // Logged out
+ AccountEvent(creator, user, "").Send();
+ }
+ }
+};
+
class ModuleServicesAccount : public Module
{
AChannel_R m1;
@@ -111,79 +143,50 @@ class ModuleServicesAccount : public Module
AUser_R m3;
Channel_r m4;
User_r m5;
- AccountExtItem accountname;
+ AccountExtItemImpl accountname;
bool checking_ban;
-
- static bool ReadCGIIRCExt(const char* extname, User* user, const std::string*& out)
- {
- ExtensionItem* wiext = ServerInstance->Extensions.GetItem(extname);
- if (!wiext)
- return false;
-
- if (wiext->creator->ModuleSourceFile != "m_cgiirc.so")
- return false;
-
- StringExtItem* stringext = static_cast<StringExtItem*>(wiext);
- std::string* addr = stringext->get(user);
- if (!addr)
- return false;
-
- out = addr;
- return true;
- }
-
public:
ModuleServicesAccount() : m1(this), m2(this), m3(this), m4(this), m5(this),
- accountname("accountname", this), checking_ban(false)
- {
- }
-
- void init()
+ accountname(this)
{
- ServiceProvider* providerlist[] = { &m1, &m2, &m3, &m4, &m5, &accountname };
- ServerInstance->Modules->AddServices(providerlist, sizeof(providerlist)/sizeof(ServiceProvider*));
- Implementation eventlist[] = { I_OnWhois, I_OnUserPreMessage, I_OnUserPreNotice, I_OnUserPreJoin, I_OnCheckBan,
- I_OnDecodeMetaData, I_On005Numeric, I_OnUserPostNick, I_OnSetConnectClass };
-
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
}
- void On005Numeric(std::string &t)
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
- ServerInstance->AddExtBanChar('R');
- ServerInstance->AddExtBanChar('U');
+ tokens["EXTBAN"].push_back('R');
+ tokens["EXTBAN"].push_back('U');
}
/* <- :twisted.oscnet.org 330 w00t2 w00t2 w00t :is logged in as */
- void OnWhois(User* source, User* dest)
+ void OnWhois(User* source, User* dest) CXX11_OVERRIDE
{
std::string *account = accountname.get(dest);
if (account)
{
- ServerInstance->SendWhoisLine(source, dest, 330, "%s %s %s :is logged in as", source->nick.c_str(), dest->nick.c_str(), account->c_str());
+ ServerInstance->SendWhoisLine(source, dest, 330, "%s %s :is logged in as", dest->nick.c_str(), account->c_str());
}
- if (dest->IsModeSet('r'))
+ if (dest->IsModeSet(m5))
{
/* user is registered */
- ServerInstance->SendWhoisLine(source, dest, 307, "%s %s :is a registered nick", source->nick.c_str(), dest->nick.c_str());
+ ServerInstance->SendWhoisLine(source, dest, 307, "%s :is a registered nick", dest->nick.c_str());
}
}
- void OnUserPostNick(User* user, const std::string &oldnick)
+ void OnUserPostNick(User* user, const std::string &oldnick) CXX11_OVERRIDE
{
/* On nickchange, if they have +r, remove it */
- if (user->IsModeSet('r') && assign(user->nick) != oldnick)
+ if (user->IsModeSet(m5) && assign(user->nick) != oldnick)
{
std::vector<std::string> modechange;
modechange.push_back(user->nick);
modechange.push_back("-r");
- ServerInstance->SendMode(modechange, ServerInstance->FakeClient);
+ ServerInstance->Modes->Process(modechange, ServerInstance->FakeClient, ModeParser::MODE_LOCALONLY);
}
}
- ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+ ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE
{
if (!IS_LOCAL(user))
return MOD_RES_PASSTHRU;
@@ -196,10 +199,10 @@ class ModuleServicesAccount : public Module
Channel* c = (Channel*)dest;
ModResult res = ServerInstance->OnCheckExemption(user,c,"regmoderated");
- if (c->IsModeSet('M') && !is_registered && res != MOD_RES_ALLOW)
+ if (c->IsModeSet(m2) && !is_registered && res != MOD_RES_ALLOW)
{
// user messaging a +M channel and is not registered
- user->WriteNumeric(477, user->nick+" "+c->name+" :You need to be identified to a registered account to message this channel");
+ user->WriteNumeric(477, c->name+" :You need to be identified to a registered account to message this channel");
return MOD_RES_DENY;
}
}
@@ -207,17 +210,17 @@ class ModuleServicesAccount : public Module
{
User* u = (User*)dest;
- if (u->IsModeSet('R') && !is_registered)
+ if (u->IsModeSet(m3) && !is_registered)
{
// user messaging a +R user and is not registered
- user->WriteNumeric(477, ""+ user->nick +" "+ u->nick +" :You need to be identified to a registered account to message this user");
+ user->WriteNumeric(477, u->nick +" :You need to be identified to a registered account to message this user");
return MOD_RES_DENY;
}
}
return MOD_RES_PASSTHRU;
}
- ModResult OnCheckBan(User* user, Channel* chan, const std::string& mask)
+ ModResult OnCheckBan(User* user, Channel* chan, const std::string& mask) CXX11_OVERRIDE
{
if (checking_ban)
return MOD_RES_PASSTHRU;
@@ -253,27 +256,19 @@ class ModuleServicesAccount : public Module
return MOD_RES_PASSTHRU;
}
- ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
- {
- return OnUserPreMessage(user, dest, target_type, text, status, exempt_list);
- }
-
- ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven)
+ ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE
{
- if (!IS_LOCAL(user))
- return MOD_RES_PASSTHRU;
-
std::string *account = accountname.get(user);
bool is_registered = account && !account->empty();
if (chan)
{
- if (chan->IsModeSet('R'))
+ if (chan->IsModeSet(m1))
{
if (!is_registered)
{
// joining a +R channel and not identified
- user->WriteNumeric(477, user->nick + " " + chan->name + " :You need to be identified to a registered account to join this channel");
+ user->WriteNumeric(477, chan->name + " :You need to be identified to a registered account to join this channel");
return MOD_RES_DENY;
}
}
@@ -281,56 +276,14 @@ class ModuleServicesAccount : public Module
return MOD_RES_PASSTHRU;
}
- // Whenever the linking module receives metadata from another server and doesnt know what
- // to do with it (of course, hence the 'meta') it calls this method, and it is up to each
- // module in turn to figure out if this metadata key belongs to them, and what they want
- // to do with it.
- // In our case we're only sending a single string around, so we just construct a std::string.
- // Some modules will probably get much more complex and format more detailed structs and classes
- // in a textual way for sending over the link.
- void OnDecodeMetaData(Extensible* target, const std::string &extname, const std::string &extdata)
- {
- User* dest = dynamic_cast<User*>(target);
- // check if its our metadata key, and its associated with a user
- if (dest && (extname == "accountname"))
- {
- std::string *account = accountname.get(dest);
- if (account && !account->empty())
- {
- trim(*account);
-
- if (IS_LOCAL(dest))
- {
- const std::string* host = &dest->dhost;
- if (dest->registered != REG_ALL)
- {
- if (!ReadCGIIRCExt("cgiirc_webirc_hostname", dest, host))
- {
- ReadCGIIRCExt("cgiirc_webirc_ip", dest, host);
- }
- }
-
- dest->WriteNumeric(900, "%s %s!%s@%s %s :You are now logged in as %s",
- dest->nick.c_str(), dest->nick.c_str(), dest->ident.c_str(), host->c_str(), account->c_str(), account->c_str());
- }
-
- AccountEvent(this, dest, *account).Send();
- }
- else
- {
- AccountEvent(this, dest, "").Send();
- }
- }
- }
-
- ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass)
+ ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass) CXX11_OVERRIDE
{
if (myclass->config->getBool("requireaccount") && !accountname.get(user))
return MOD_RES_DENY;
return MOD_RES_PASSTHRU;
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for ircu-style services accounts, including chmode +R, etc.",VF_OPTCOMMON|VF_VENDOR);
}
diff --git a/src/modules/m_servprotect.cpp b/src/modules/m_servprotect.cpp
index b4f2b5bbd..26453020f 100644
--- a/src/modules/m_servprotect.cpp
+++ b/src/modules/m_servprotect.cpp
@@ -21,8 +21,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides usermode +k to protect services from kicks, kills and mode changes. */
-
/** Handles user mode +k
*/
class ServProtectMode : public ModeHandler
@@ -53,37 +51,25 @@ class ModuleServProtectMode : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(bm);
- Implementation eventlist[] = { I_OnWhois, I_OnKill, I_OnWhoisLine, I_OnRawMode, I_OnUserPreKick };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
-
- ~ModuleServProtectMode()
- {
- }
-
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides usermode +k to protect services from kicks, kills, and mode changes.", VF_VENDOR);
}
- void OnWhois(User* src, User* dst)
+ void OnWhois(User* user, User* dest) CXX11_OVERRIDE
{
- if (dst->IsModeSet('k'))
+ if (dest->IsModeSet(bm))
{
- ServerInstance->SendWhoisLine(src, dst, 310, src->nick+" "+dst->nick+" :is an "+ServerInstance->Config->Network+" Service");
+ ServerInstance->SendWhoisLine(user, dest, 310, dest->nick+" :is a Network Service on "+ServerInstance->Config->Network);
}
}
- ModResult OnRawMode(User* user, Channel* chan, const char mode, const std::string &param, bool adding, int pcnt)
+ ModResult OnRawMode(User* user, Channel* chan, ModeHandler* mh, const std::string& param, bool adding) CXX11_OVERRIDE
{
/* Check that the mode is not a server mode, it is being removed, the user making the change is local, there is a parameter,
* and the user making the change is not a uline
*/
- if (!adding && chan && IS_LOCAL(user) && !param.empty() && !ServerInstance->ULine(user->server))
+ if (!adding && chan && IS_LOCAL(user) && !param.empty())
{
/* Check if the parameter is a valid nick/uuid
*/
@@ -95,10 +81,10 @@ class ModuleServProtectMode : public Module
* This includes any prefix permission mode, even those registered in other modules, e.g. +qaohv. Using ::ModeString()
* here means that the number of modes is restricted to only modes the user has, limiting it to as short a loop as possible.
*/
- if (u->IsModeSet('k') && memb && memb->modes.find(mode) != std::string::npos)
+ if (u->IsModeSet(bm) && memb && memb->hasMode(mh->GetModeChar()))
{
/* BZZZT, Denied! */
- user->WriteNumeric(482, "%s %s :You are not permitted to remove privileges from %s services", user->nick.c_str(), chan->name.c_str(), ServerInstance->Config->Network.c_str());
+ user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s :You are not permitted to remove privileges from %s services", chan->name.c_str(), ServerInstance->Config->Network.c_str());
return MOD_RES_DENY;
}
}
@@ -107,37 +93,36 @@ class ModuleServProtectMode : public Module
return MOD_RES_PASSTHRU;
}
- ModResult OnKill(User* src, User* dst, const std::string &reason)
+ ModResult OnKill(User* src, User* dst, const std::string &reason) CXX11_OVERRIDE
{
if (src == NULL)
return MOD_RES_PASSTHRU;
- if (dst->IsModeSet('k'))
+ if (dst->IsModeSet(bm))
{
- src->WriteNumeric(485, "%s :You are not permitted to kill %s services!", src->nick.c_str(), ServerInstance->Config->Network.c_str());
+ src->WriteNumeric(485, ":You are not permitted to kill %s services!", ServerInstance->Config->Network.c_str());
ServerInstance->SNO->WriteGlobalSno('a', src->nick+" tried to kill service "+dst->nick+" ("+reason+")");
return MOD_RES_DENY;
}
return MOD_RES_PASSTHRU;
}
- ModResult OnUserPreKick(User *src, Membership* memb, const std::string &reason)
+ ModResult OnUserPreKick(User *src, Membership* memb, const std::string &reason) CXX11_OVERRIDE
{
- if (memb->user->IsModeSet('k'))
+ if (memb->user->IsModeSet(bm))
{
- src->WriteNumeric(484, "%s %s :You are not permitted to kick services",
- src->nick.c_str(), memb->chan->name.c_str());
+ src->WriteNumeric(ERR_RESTRICTED, "%s :You are not permitted to kick services",
+ memb->chan->name.c_str());
return MOD_RES_DENY;
}
return MOD_RES_PASSTHRU;
}
- ModResult OnWhoisLine(User* src, User* dst, int &numeric, std::string &text)
+ ModResult OnWhoisLine(User* src, User* dst, int &numeric, std::string &text) CXX11_OVERRIDE
{
- return ((src != dst) && (numeric == 319) && dst->IsModeSet('k')) ? MOD_RES_DENY : MOD_RES_PASSTHRU;
+ return ((src != dst) && (numeric == 319) && dst->IsModeSet(bm)) ? MOD_RES_DENY : MOD_RES_PASSTHRU;
}
};
-
MODULE_INIT(ModuleServProtectMode)
diff --git a/src/modules/m_sethost.cpp b/src/modules/m_sethost.cpp
index 2ef0c0548..75dbe1c6a 100644
--- a/src/modules/m_sethost.cpp
+++ b/src/modules/m_sethost.cpp
@@ -21,20 +21,17 @@
#include "inspircd.h"
-/* $ModDesc: Provides support for the SETHOST command */
-
/** Handle /SETHOST
*/
class CommandSethost : public Command
{
- private:
char* hostmap;
+
public:
CommandSethost(Module* Creator, char* hmap) : Command(Creator,"SETHOST", 1), hostmap(hmap)
{
allow_empty_last_param = false;
flags_needed = 'o'; syntax = "<new-hostname>";
- TRANSLATE2(TR_TEXT, TR_END);
}
CmdResult Handle (const std::vector<std::string>& parameters, User *user)
@@ -44,18 +41,18 @@ class CommandSethost : public Command
{
if (!hostmap[(const unsigned char)*x])
{
- user->WriteServ("NOTICE "+user->nick+" :*** SETHOST: Invalid characters in hostname");
+ user->WriteNotice("*** SETHOST: Invalid characters in hostname");
return CMD_FAILURE;
}
}
- if (len > 64)
+ if (len > ServerInstance->Config->Limits.MaxHost)
{
- user->WriteServ("NOTICE %s :*** SETHOST: Host too long",user->nick.c_str());
+ user->WriteNotice("*** SETHOST: Host too long");
return CMD_FAILURE;
}
- if (user->ChangeDisplayedHost(parameters[0].c_str()))
+ if (user->ChangeDisplayedHost(parameters[0]))
{
ServerInstance->SNO->WriteGlobalSno('a', user->nick+" used SETHOST to change their displayed host to "+user->dhost);
return CMD_SUCCESS;
@@ -70,21 +67,14 @@ class ModuleSetHost : public Module
{
CommandSethost cmd;
char hostmap[256];
+
public:
ModuleSetHost()
: cmd(this, hostmap)
{
}
- void init()
- {
- OnRehash(NULL);
- ServerInstance->Modules->AddService(cmd);
- Implementation eventlist[] = { I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
std::string hmap = ServerInstance->Config->ConfValue("hostname")->getString("charmap", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_/0123456789");
@@ -93,15 +83,10 @@ class ModuleSetHost : public Module
hostmap[(unsigned char)*n] = 1;
}
- virtual ~ModuleSetHost()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for the SETHOST command", VF_VENDOR);
}
-
};
MODULE_INIT(ModuleSetHost)
diff --git a/src/modules/m_setident.cpp b/src/modules/m_setident.cpp
index f63be1381..93dd4c332 100644
--- a/src/modules/m_setident.cpp
+++ b/src/modules/m_setident.cpp
@@ -22,8 +22,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides support for the SETIDENT command */
-
/** Handle /SETIDENT
*/
class CommandSetident : public Command
@@ -33,31 +31,29 @@ class CommandSetident : public Command
{
allow_empty_last_param = false;
flags_needed = 'o'; syntax = "<new-ident>";
- TRANSLATE2(TR_TEXT, TR_END);
}
CmdResult Handle(const std::vector<std::string>& parameters, User *user)
{
if (parameters[0].size() > ServerInstance->Config->Limits.IdentMax)
{
- user->WriteServ("NOTICE %s :*** SETIDENT: Ident is too long", user->nick.c_str());
+ user->WriteNotice("*** SETIDENT: Ident is too long");
return CMD_FAILURE;
}
- if (!ServerInstance->IsIdent(parameters[0].c_str()))
+ if (!ServerInstance->IsIdent(parameters[0]))
{
- user->WriteServ("NOTICE %s :*** SETIDENT: Invalid characters in ident", user->nick.c_str());
+ user->WriteNotice("*** SETIDENT: Invalid characters in ident");
return CMD_FAILURE;
}
- user->ChangeIdent(parameters[0].c_str());
+ user->ChangeIdent(parameters[0]);
ServerInstance->SNO->WriteGlobalSno('a', "%s used SETIDENT to change their ident to '%s'", user->nick.c_str(), user->ident.c_str());
return CMD_SUCCESS;
}
};
-
class ModuleSetIdent : public Module
{
CommandSetident cmd;
@@ -67,21 +63,10 @@ class ModuleSetIdent : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cmd);
- }
-
- virtual ~ModuleSetIdent()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for the SETIDENT command", VF_VENDOR);
}
-
};
-
MODULE_INIT(ModuleSetIdent)
diff --git a/src/modules/m_setidle.cpp b/src/modules/m_setidle.cpp
index fdb29d14f..dd82aef29 100644
--- a/src/modules/m_setidle.cpp
+++ b/src/modules/m_setidle.cpp
@@ -21,25 +21,22 @@
#include "inspircd.h"
-/* $ModDesc: Allows opers to set their idle time */
-
/** Handle /SETIDLE
*/
-class CommandSetidle : public Command
+class CommandSetidle : public SplitCommand
{
public:
- CommandSetidle(Module* Creator) : Command(Creator,"SETIDLE", 1)
+ CommandSetidle(Module* Creator) : SplitCommand(Creator,"SETIDLE", 1)
{
flags_needed = 'o'; syntax = "<duration>";
- TRANSLATE2(TR_TEXT, TR_END);
}
- CmdResult Handle (const std::vector<std::string>& parameters, User *user)
+ CmdResult HandleLocal(const std::vector<std::string>& parameters, LocalUser* user)
{
- time_t idle = ServerInstance->Duration(parameters[0]);
+ int idle = InspIRCd::Duration(parameters[0]);
if (idle < 1)
{
- user->WriteNumeric(948, "%s :Invalid idle time.",user->nick.c_str());
+ user->WriteNumeric(948, ":Invalid idle time.");
return CMD_FAILURE;
}
user->idle_lastmsg = (ServerInstance->Time() - idle);
@@ -47,7 +44,7 @@ class CommandSetidle : public Command
if (user->signon > user->idle_lastmsg)
user->signon = user->idle_lastmsg;
ServerInstance->SNO->WriteToSnoMask('a', user->nick+" used SETIDLE to set their idle time to "+ConvToStr(idle)+" seconds");
- user->WriteNumeric(944, "%s :Idle time set.",user->nick.c_str());
+ user->WriteNumeric(944, ":Idle time set.");
return CMD_SUCCESS;
}
@@ -63,16 +60,7 @@ class ModuleSetIdle : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cmd);
- }
-
- virtual ~ModuleSetIdle()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Allows opers to set their idle time", VF_VENDOR);
}
diff --git a/src/modules/m_setname.cpp b/src/modules/m_setname.cpp
index d0610853b..0e71840f7 100644
--- a/src/modules/m_setname.cpp
+++ b/src/modules/m_setname.cpp
@@ -21,8 +21,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides support for the SETNAME command */
-
class CommandSetname : public Command
@@ -32,18 +30,17 @@ class CommandSetname : public Command
{
allow_empty_last_param = false;
syntax = "<new-gecos>";
- TRANSLATE2(TR_TEXT, TR_END);
}
CmdResult Handle (const std::vector<std::string>& parameters, User *user)
{
if (parameters[0].size() > ServerInstance->Config->Limits.MaxGecos)
{
- user->WriteServ("NOTICE %s :*** SETNAME: GECOS too long", user->nick.c_str());
+ user->WriteNotice("*** SETNAME: GECOS too long");
return CMD_FAILURE;
}
- if (user->ChangeName(parameters[0].c_str()))
+ if (user->ChangeName(parameters[0]))
{
ServerInstance->SNO->WriteGlobalSno('a', "%s used SETNAME to change their GECOS to '%s'", user->nick.c_str(), parameters[0].c_str());
}
@@ -62,16 +59,7 @@ class ModuleSetName : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cmd);
- }
-
- virtual ~ModuleSetName()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for the SETNAME command", VF_VENDOR);
}
diff --git a/src/modules/m_sha256.cpp b/src/modules/m_sha256.cpp
index 86970968a..d2755bacc 100644
--- a/src/modules/m_sha256.cpp
+++ b/src/modules/m_sha256.cpp
@@ -56,17 +56,8 @@
* SUCH DAMAGE.
*/
-/* $ModDesc: Allows for SHA-256 encrypted oper passwords */
-
#include "inspircd.h"
-#ifdef HAS_STDINT
-#include <stdint.h>
-#endif
-#include "hash.h"
-
-#ifndef HAS_STDINT
-typedef unsigned int uint32_t;
-#endif
+#include "modules/hash.h"
#define SHA256_DIGEST_SIZE (256 / 8)
#define SHA256_BLOCK_SIZE (512 / 8)
@@ -263,11 +254,6 @@ class HashSHA256 : public HashProvider
return std::string((char*)bytes, SHA256_DIGEST_SIZE);
}
- std::string sumIV(unsigned int* IV, const char* HexMap, const std::string &sdata)
- {
- return "";
- }
-
HashSHA256(Module* parent) : HashProvider(parent, "hash/sha256", 32, 64) {}
};
@@ -277,10 +263,9 @@ class ModuleSHA256 : public Module
public:
ModuleSHA256() : sha(this)
{
- ServerInstance->Modules->AddService(sha);
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Implements SHA-256 hashing", VF_VENDOR);
}
diff --git a/src/modules/m_showfile.cpp b/src/modules/m_showfile.cpp
new file mode 100644
index 000000000..132a22267
--- /dev/null
+++ b/src/modules/m_showfile.cpp
@@ -0,0 +1,169 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2013 Attila Molnar <attilamolnar@hush.com>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+
+class CommandShowFile : public Command
+{
+ enum Method
+ {
+ SF_MSG,
+ SF_NOTICE,
+ SF_NUMERIC
+ };
+
+ std::string introtext;
+ std::string endtext;
+ unsigned int intronumeric;
+ unsigned int textnumeric;
+ unsigned int endnumeric;
+ file_cache contents;
+ Method method;
+
+ public:
+ CommandShowFile(Module* parent, const std::string& cmdname)
+ : Command(parent, cmdname)
+ {
+ }
+
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user) CXX11_OVERRIDE
+ {
+ const std::string& sn = ServerInstance->Config->ServerName;
+ if (method == SF_NUMERIC)
+ {
+ if (!introtext.empty())
+ user->SendText(":%s %03d %s :%s %s", sn.c_str(), intronumeric, user->nick.c_str(), sn.c_str(), introtext.c_str());
+
+ for (file_cache::const_iterator i = contents.begin(); i != contents.end(); ++i)
+ user->SendText(":%s %03d %s :- %s", sn.c_str(), textnumeric, user->nick.c_str(), i->c_str());
+
+ user->SendText(":%s %03d %s :%s", sn.c_str(), endnumeric, user->nick.c_str(), endtext.c_str());
+ }
+ else
+ {
+ const char* msgcmd = (method == SF_MSG ? "PRIVMSG" : "NOTICE");
+ std::string header = InspIRCd::Format(":%s %s %s :", sn.c_str(), msgcmd, user->nick.c_str());
+ for (file_cache::const_iterator i = contents.begin(); i != contents.end(); ++i)
+ user->SendText(header + *i);
+ }
+ return CMD_SUCCESS;
+ }
+
+ void UpdateSettings(ConfigTag* tag, const std::vector<std::string>& filecontents)
+ {
+ introtext = tag->getString("introtext", "Showing " + name);
+ endtext = tag->getString("endtext", "End of " + name);
+ intronumeric = tag->getInt("intronumeric", RPL_RULESTART, 0, 999);
+ textnumeric = tag->getInt("numeric", RPL_RULES, 0, 999);
+ endnumeric = tag->getInt("endnumeric", RPL_RULESEND, 0, 999);
+ std::string smethod = tag->getString("method");
+
+ method = SF_NUMERIC;
+ if (smethod == "msg")
+ method = SF_MSG;
+ else if (smethod == "notice")
+ method = SF_NOTICE;
+
+ contents = filecontents;
+ if (tag->getBool("colors"))
+ InspIRCd::ProcessColors(contents);
+ }
+};
+
+class ModuleShowFile : public Module
+{
+ std::vector<CommandShowFile*> cmds;
+
+ void ReadTag(ConfigTag* tag, std::vector<CommandShowFile*>& newcmds)
+ {
+ std::string cmdname = tag->getString("name");
+ if (cmdname.empty())
+ throw ModuleException("Empty value for 'name'");
+
+ std::transform(cmdname.begin(), cmdname.end(), cmdname.begin(), ::toupper);
+
+ const std::string file = tag->getString("file", cmdname);
+ if (file.empty())
+ throw ModuleException("Empty value for 'file'");
+ FileReader reader(file);
+
+ CommandShowFile* sfcmd;
+ Command* handler = ServerInstance->Parser.GetHandler(cmdname);
+ if (handler)
+ {
+ // Command exists, check if it is ours
+ if (handler->creator != this)
+ throw ModuleException("Command " + cmdname + " already exists");
+
+ // This is our command, make sure we don't have the same entry twice
+ sfcmd = static_cast<CommandShowFile*>(handler);
+ if (std::find(newcmds.begin(), newcmds.end(), sfcmd) != newcmds.end())
+ throw ModuleException("Command " + cmdname + " is already used in a <showfile> tag");
+ }
+ else
+ {
+ // Command doesn't exist, create it
+ sfcmd = new CommandShowFile(this, cmdname);
+ ServerInstance->Modules->AddService(*sfcmd);
+ }
+
+ sfcmd->UpdateSettings(tag, reader.GetVector());
+ newcmds.push_back(sfcmd);
+ }
+
+ public:
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
+ {
+ std::vector<CommandShowFile*> newcmds;
+
+ ConfigTagList tags = ServerInstance->Config->ConfTags("showfile");
+ for (ConfigIter i = tags.first; i != tags.second; ++i)
+ {
+ ConfigTag* tag = i->second;
+ try
+ {
+ ReadTag(tag, newcmds);
+ }
+ catch (CoreException& ex)
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Error: " + ex.GetReason() + " at " + tag->getTagLocation());
+ }
+ }
+
+ // Remove all commands that were removed from the config
+ std::vector<CommandShowFile*> removed(cmds.size());
+ std::sort(newcmds.begin(), newcmds.end());
+ std::set_difference(cmds.begin(), cmds.end(), newcmds.begin(), newcmds.end(), removed.begin());
+
+ stdalgo::delete_all(removed);
+ cmds.swap(newcmds);
+ }
+
+ ~ModuleShowFile()
+ {
+ stdalgo::delete_all(cmds);
+ }
+
+ Version GetVersion() CXX11_OVERRIDE
+ {
+ return Version("Provides support for showing text files to users", VF_VENDOR);
+ }
+};
+
+MODULE_INIT(ModuleShowFile)
diff --git a/src/modules/m_showwhois.cpp b/src/modules/m_showwhois.cpp
index 398ebf571..ba17942cb 100644
--- a/src/modules/m_showwhois.cpp
+++ b/src/modules/m_showwhois.cpp
@@ -23,16 +23,19 @@
#include "inspircd.h"
-/* $ModDesc: Allows opers to set +W to see when a user uses WHOIS on them */
-
/** Handle user mode +W
*/
class SeeWhois : public SimpleUserModeHandler
{
public:
- SeeWhois(Module* Creator, bool IsOpersOnly) : SimpleUserModeHandler(Creator, "showwhois", 'W')
+ SeeWhois(Module* Creator)
+ : SimpleUserModeHandler(Creator, "showwhois", 'W')
{
- oper = IsOpersOnly;
+ }
+
+ void SetOperOnly(bool operonly)
+ {
+ oper = operonly;
}
};
@@ -46,9 +49,9 @@ class WhoisNoticeCmd : public Command
void HandleFast(User* dest, User* src)
{
- dest->WriteServ("NOTICE %s :*** %s (%s@%s) did a /whois on you",
- dest->nick.c_str(), src->nick.c_str(), src->ident.c_str(),
- dest->HasPrivPermission("users/auspex") ? src->host.c_str() : src->dhost.c_str());
+ dest->WriteNotice("*** " + src->nick + " (" + src->ident + "@" +
+ (dest->HasPrivPermission("users/auspex") ? src->host : src->dhost) +
+ ") did a /whois on you");
}
CmdResult Handle(const std::vector<std::string> &parameters, User *user)
@@ -69,46 +72,35 @@ class WhoisNoticeCmd : public Command
class ModuleShowwhois : public Module
{
bool ShowWhoisFromOpers;
- SeeWhois* sw;
+ SeeWhois sw;
WhoisNoticeCmd cmd;
public:
ModuleShowwhois()
- : sw(NULL), cmd(this)
+ : sw(this), cmd(this)
{
}
- void init()
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ConfigTag* tag = ServerInstance->Config->ConfValue("showwhois");
- bool OpersOnly = tag->getBool("opersonly", true);
+ sw.SetOperOnly(tag->getBool("opersonly", true));
ShowWhoisFromOpers = tag->getBool("showfromopers", true);
-
- sw = new SeeWhois(this, OpersOnly);
- ServerInstance->Modules->AddService(*sw);
- ServerInstance->Modules->AddService(cmd);
- Implementation eventlist[] = { I_OnWhois };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
}
- ~ModuleShowwhois()
- {
- delete sw;
- }
-
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Allows opers to set +W to see when a user uses WHOIS on them",VF_OPTCOMMON|VF_VENDOR);
}
- void OnWhois(User* source, User* dest)
+ void OnWhois(User* source, User* dest) CXX11_OVERRIDE
{
- if (!dest->IsModeSet('W') || source == dest)
+ if (!dest->IsModeSet(sw) || source == dest)
return;
- if (!ShowWhoisFromOpers && IS_OPER(source))
+ if (!ShowWhoisFromOpers && source->IsOper())
return;
if (IS_LOCAL(dest))
@@ -118,14 +110,11 @@ class ModuleShowwhois : public Module
else
{
std::vector<std::string> params;
- params.push_back(dest->server);
- params.push_back("WHOISNOTICE");
params.push_back(dest->uuid);
params.push_back(source->uuid);
- ServerInstance->PI->SendEncapsulatedData(params);
+ ServerInstance->PI->SendEncapsulatedData(dest->server->GetName(), cmd.name, params);
}
}
-
};
MODULE_INIT(ModuleShowwhois)
diff --git a/src/modules/m_shun.cpp b/src/modules/m_shun.cpp
index 8bf4d30e7..075b80eb7 100644
--- a/src/modules/m_shun.cpp
+++ b/src/modules/m_shun.cpp
@@ -23,8 +23,6 @@
#include "inspircd.h"
#include "xline.h"
-/* $ModDesc: Provides the /SHUN command, which stops a user from executing all except configured commands. */
-
class Shun : public XLine
{
public:
@@ -36,14 +34,11 @@ public:
{
}
- ~Shun()
- {
- }
-
bool Matches(User *u)
{
// E: overrides shun
- if (u->exempt)
+ LocalUser* lu = IS_LOCAL(u);
+ if (lu && lu->exempt)
return false;
if (InspIRCd::Match(u->GetFullHost(), matchtext) || InspIRCd::Match(u->GetFullRealHost(), matchtext) || InspIRCd::Match(u->nick+"!"+u->ident+"@"+u->GetIPString(), matchtext))
@@ -59,15 +54,9 @@ public:
return false;
}
- void DisplayExpiry()
- {
- ServerInstance->SNO->WriteToSnoMask('x',"Removing expired shun %s (set by %s %ld seconds ago)",
- this->matchtext.c_str(), this->source.c_str(), (long int)(ServerInstance->Time() - this->set_time));
- }
-
- const char* Displayable()
+ const std::string& Displayable()
{
- return matchtext.c_str();
+ return matchtext;
}
};
@@ -107,7 +96,7 @@ class CommandShun : public Command
/* 'time' is a human-readable timestring, like 2d3h2s. */
std::string target = parameters[0];
-
+
User *find = ServerInstance->FindNick(target);
if ((find) && (find->registered == REG_ALL))
target = std::string("*!*@") + find->GetIPString();
@@ -120,18 +109,18 @@ class CommandShun : public Command
}
else
{
- user->WriteServ("NOTICE %s :*** Shun %s not found in list, try /stats H.",user->nick.c_str(),target.c_str());
+ user->WriteNotice("*** Shun " + target + " not found in list, try /stats H.");
return CMD_FAILURE;
}
}
else
{
// Adding - XXX todo make this respect <insane> tag perhaps..
- long duration;
+ unsigned long duration;
std::string expr;
if (parameters.size() > 2)
{
- duration = ServerInstance->Duration(parameters[1]);
+ duration = InspIRCd::Duration(parameters[1]);
expr = parameters[2];
}
else
@@ -151,7 +140,7 @@ class CommandShun : public Command
else
{
time_t c_requires_crap = duration + ServerInstance->Time();
- std::string timestr = ServerInstance->TimeString(c_requires_crap);
+ std::string timestr = InspIRCd::TimeString(c_requires_crap);
ServerInstance->SNO->WriteToSnoMask('x', "%s added timed SHUN for %s to expire on %s: %s",
user->nick.c_str(), target.c_str(), timestr.c_str(), expr.c_str());
}
@@ -159,7 +148,7 @@ class CommandShun : public Command
else
{
delete r;
- user->WriteServ("NOTICE %s :*** Shun for %s already exists", user->nick.c_str(), target.c_str());
+ user->WriteNotice("*** Shun for " + target + " already exists");
return CMD_FAILURE;
}
}
@@ -188,17 +177,12 @@ class ModuleShun : public Module
{
}
- void init()
+ void init() CXX11_OVERRIDE
{
ServerInstance->XLines->RegisterFactory(&f);
- ServerInstance->Modules->AddService(cmd);
-
- Implementation eventlist[] = { I_OnStats, I_OnPreCommand, I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- OnRehash(NULL);
}
- virtual ~ModuleShun()
+ ~ModuleShun()
{
ServerInstance->XLines->DelAll("SHUN");
ServerInstance->XLines->UnregisterFactory(&f);
@@ -210,7 +194,7 @@ class ModuleShun : public Module
ServerInstance->Modules->SetPriority(this, I_OnPreCommand, PRIORITY_BEFORE, &alias);
}
- virtual ModResult OnStats(char symbol, User* user, string_list& out)
+ ModResult OnStats(char symbol, User* user, string_list& out) CXX11_OVERRIDE
{
if (symbol != 'H')
return MOD_RES_PASSTHRU;
@@ -219,7 +203,7 @@ class ModuleShun : public Module
return MOD_RES_DENY;
}
- virtual void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ConfigTag* tag = ServerInstance->Config->ConfValue("shun");
std::string cmds = tag->getString("enabledcommands");
@@ -242,7 +226,7 @@ class ModuleShun : public Module
affectopers = tag->getBool("affectopers", false);
}
- virtual ModResult OnPreCommand(std::string &command, std::vector<std::string>& parameters, LocalUser* user, bool validated, const std::string &original_line)
+ ModResult OnPreCommand(std::string &command, std::vector<std::string>& parameters, LocalUser* user, bool validated, const std::string &original_line) CXX11_OVERRIDE
{
if (validated)
return MOD_RES_PASSTHRU;
@@ -253,7 +237,7 @@ class ModuleShun : public Module
return MOD_RES_PASSTHRU;
}
- if (!affectopers && IS_OPER(user))
+ if (!affectopers && user->IsOper())
{
/* Don't do anything if the user is an operator and affectopers isn't set */
return MOD_RES_PASSTHRU;
@@ -264,7 +248,7 @@ class ModuleShun : public Module
if (i == ShunEnabledCommands.end())
{
if (NotifyOfShun)
- user->WriteServ("NOTICE %s :*** Command %s not processed, as you have been blocked from issuing commands (SHUN)", user->nick.c_str(), command.c_str());
+ user->WriteNotice("*** Command " + command + " not processed, as you have been blocked from issuing commands (SHUN)");
return MOD_RES_DENY;
}
@@ -283,11 +267,10 @@ class ModuleShun : public Module
return MOD_RES_PASSTHRU;
}
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides the /SHUN command, which stops a user from executing all except configured commands.",VF_VENDOR|VF_COMMON);
}
};
MODULE_INIT(ModuleShun)
-
diff --git a/src/modules/m_silence.cpp b/src/modules/m_silence.cpp
index c82ab3f9d..7298d77e1 100644
--- a/src/modules/m_silence.cpp
+++ b/src/modules/m_silence.cpp
@@ -23,8 +23,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides support for the /SILENCE command */
-
/* Improved drop-in replacement for the /SILENCE command
* syntax: /SILENCE [+|-]<mask> <p|c|i|n|t|a|x> as in <privatemessage|channelmessage|invites|privatenotice|channelnotice|all|exclude>
*
@@ -66,7 +64,7 @@ class CommandSVSSilence : public Command
CommandSVSSilence(Module* Creator) : Command(Creator,"SVSSILENCE", 2)
{
syntax = "<target> {[+|-]<mask> <p|c|i|n|t|a|x>}";
- TRANSLATE4(TR_NICK, TR_TEXT, TR_TEXT, TR_END); /* we watch for a nick. not a UID. */
+ TRANSLATE3(TR_NICK, TR_TEXT, TR_TEXT);
}
CmdResult Handle (const std::vector<std::string>& parameters, User *user)
@@ -78,7 +76,7 @@ class CommandSVSSilence : public Command
* style command so services can modify lots of entries at once.
* leaving it backwards compatible for now as it's late. -- w
*/
- if (!ServerInstance->ULine(user->server))
+ if (!user->server->IsULine())
return CMD_FAILURE;
User *u = ServerInstance->FindNick(parameters[0]);
@@ -87,7 +85,7 @@ class CommandSVSSilence : public Command
if (IS_LOCAL(u))
{
- ServerInstance->Parser->CallHandler("SILENCE", std::vector<std::string>(parameters.begin() + 1, parameters.end()), u);
+ ServerInstance->Parser.CallHandler("SILENCE", std::vector<std::string>(parameters.begin() + 1, parameters.end()), u);
}
return CMD_SUCCESS;
@@ -112,7 +110,6 @@ class CommandSilence : public Command
{
allow_empty_last_param = false;
syntax = "{[+|-]<mask> <p|c|i|n|t|a|x>}";
- TRANSLATE3(TR_TEXT, TR_TEXT, TR_END);
}
CmdResult Handle (const std::vector<std::string>& parameters, User *user)
@@ -127,10 +124,10 @@ class CommandSilence : public Command
for (silencelist::const_iterator c = sl->begin(); c != sl->end(); c++)
{
std::string decomppattern = DecompPattern(c->second);
- user->WriteNumeric(271, "%s %s %s %s",user->nick.c_str(), user->nick.c_str(),c->first.c_str(), decomppattern.c_str());
+ user->WriteNumeric(271, "%s %s %s", user->nick.c_str(),c->first.c_str(), decomppattern.c_str());
}
}
- user->WriteNumeric(272, "%s :End of Silence List",user->nick.c_str());
+ user->WriteNumeric(272, ":End of Silence List");
return CMD_SUCCESS;
}
@@ -149,7 +146,7 @@ class CommandSilence : public Command
if (pattern == 0)
{
- user->WriteServ("NOTICE %s :Bad SILENCE pattern",user->nick.c_str());
+ user->WriteNotice("Bad SILENCE pattern");
return CMD_INVALID;
}
@@ -176,7 +173,7 @@ class CommandSilence : public Command
if (listitem == mask && i->second == pattern)
{
sl->erase(i);
- user->WriteNumeric(950, "%s %s :Removed %s %s from silence list",user->nick.c_str(), user->nick.c_str(), mask.c_str(), decomppattern.c_str());
+ user->WriteNumeric(950, "%s :Removed %s %s from silence list", user->nick.c_str(), mask.c_str(), decomppattern.c_str());
if (!sl->size())
{
ext.unset(user);
@@ -185,7 +182,7 @@ class CommandSilence : public Command
}
}
}
- user->WriteNumeric(952, "%s %s :%s %s does not exist on your silence list",user->nick.c_str(), user->nick.c_str(), mask.c_str(), decomppattern.c_str());
+ user->WriteNumeric(952, "%s :%s %s does not exist on your silence list", user->nick.c_str(), mask.c_str(), decomppattern.c_str());
}
else if (action == '+')
{
@@ -198,7 +195,7 @@ class CommandSilence : public Command
}
if (sl->size() > maxsilence)
{
- user->WriteNumeric(952, "%s %s :Your silence list is full",user->nick.c_str(), user->nick.c_str());
+ user->WriteNumeric(952, "%s :Your silence list is full",user->nick.c_str());
return CMD_FAILURE;
}
@@ -208,7 +205,7 @@ class CommandSilence : public Command
irc::string listitem = n->first.c_str();
if (listitem == mask && n->second == pattern)
{
- user->WriteNumeric(952, "%s %s :%s %s is already on your silence list",user->nick.c_str(), user->nick.c_str(), mask.c_str(), decomppattern.c_str());
+ user->WriteNumeric(952, "%s :%s %s is already on your silence list", user->nick.c_str(), mask.c_str(), decomppattern.c_str());
return CMD_FAILURE;
}
}
@@ -220,7 +217,7 @@ class CommandSilence : public Command
{
sl->push_back(silenceset(mask,pattern));
}
- user->WriteNumeric(951, "%s %s :Added %s %s to silence list",user->nick.c_str(), user->nick.c_str(), mask.c_str(), decomppattern.c_str());
+ user->WriteNumeric(951, "%s :Added %s %s to silence list", user->nick.c_str(), mask.c_str(), decomppattern.c_str());
return CMD_SUCCESS;
}
}
@@ -302,36 +299,25 @@ class ModuleSilence : public Module
{
}
- void init()
- {
- OnRehash(NULL);
- ServerInstance->Modules->AddService(cmdsilence);
- ServerInstance->Modules->AddService(cmdsvssilence);
- ServerInstance->Modules->AddService(cmdsilence.ext);
-
- Implementation eventlist[] = { I_OnRehash, I_On005Numeric, I_OnUserPreNotice, I_OnUserPreMessage, I_OnUserPreInvite };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
maxsilence = ServerInstance->Config->ConfValue("silence")->getInt("maxentries", 32);
if (!maxsilence)
maxsilence = 32;
}
- void On005Numeric(std::string &output)
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
- // we don't really have a limit...
- output = output + " ESILENCE SILENCE=" + ConvToStr(maxsilence);
+ tokens["ESILENCE"];
+ tokens["SILENCE"] = ConvToStr(maxsilence);
}
void OnBuildExemptList(MessageType message_type, Channel* chan, User* sender, char status, CUList &exempt_list, const std::string &text)
{
int public_silence = (message_type == MSG_PRIVMSG ? SILENCE_CHANNEL : SILENCE_CNOTICE);
- const UserMembList *ulist = chan->GetUsers();
- for (UserMembCIter i = ulist->begin(); i != ulist->end(); i++)
+ const Channel::MemberMap& ulist = chan->GetUsers();
+ for (Channel::MemberMap::const_iterator i = ulist.begin(); i != ulist.end(); ++i)
{
if (IS_LOCAL(i->first))
{
@@ -343,44 +329,27 @@ class ModuleSilence : public Module
}
}
- ModResult PreText(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list, int silence_type)
+ ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE
{
if (target_type == TYPE_USER && IS_LOCAL(((User*)dest)))
{
- return MatchPattern((User*)dest, user, silence_type);
+ return MatchPattern((User*)dest, user, ((msgtype == MSG_PRIVMSG) ? SILENCE_PRIVATE : SILENCE_NOTICE));
}
else if (target_type == TYPE_CHANNEL)
{
Channel* chan = (Channel*)dest;
- if (chan)
- {
- this->OnBuildExemptList((silence_type == SILENCE_PRIVATE ? MSG_PRIVMSG : MSG_NOTICE), chan, user, status, exempt_list, "");
- }
+ this->OnBuildExemptList(msgtype, chan, user, status, exempt_list, "");
}
return MOD_RES_PASSTHRU;
}
- ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
- {
- return PreText(user, dest, target_type, text, status, exempt_list, SILENCE_PRIVATE);
- }
-
- ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
- {
- return PreText(user, dest, target_type, text, status, exempt_list, SILENCE_NOTICE);
- }
-
- ModResult OnUserPreInvite(User* source,User* dest,Channel* channel, time_t timeout)
+ ModResult OnUserPreInvite(User* source,User* dest,Channel* channel, time_t timeout) CXX11_OVERRIDE
{
return MatchPattern(dest, source, SILENCE_INVITE);
}
ModResult MatchPattern(User* dest, User* source, int pattern)
{
- /* Server source */
- if (!source || !dest)
- return MOD_RES_ALLOW;
-
silencelist* sl = cmdsilence.ext.get(dest);
if (sl)
{
@@ -393,11 +362,7 @@ class ModuleSilence : public Module
return MOD_RES_PASSTHRU;
}
- ~ModuleSilence()
- {
- }
-
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for the /SILENCE command", VF_OPTCOMMON | VF_VENDOR);
}
diff --git a/src/modules/m_spanningtree/addline.cpp b/src/modules/m_spanningtree/addline.cpp
index 16043b2aa..dbf0003bf 100644
--- a/src/modules/m_spanningtree/addline.cpp
+++ b/src/modules/m_spanningtree/addline.cpp
@@ -20,60 +20,37 @@
#include "inspircd.h"
#include "xline.h"
-#include "treesocket.h"
#include "treeserver.h"
#include "utils.h"
+#include "commands.h"
-/* $ModDep: m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h */
-
-bool TreeSocket::AddLine(const std::string &prefix, parameterlist &params)
+CmdResult CommandAddLine::Handle(User* usr, std::vector<std::string>& params)
{
- if (params.size() < 6)
- {
- std::string servername = MyRoot->GetName();
- ServerInstance->SNO->WriteToSnoMask('d', "%s sent me a malformed ADDLINE", servername.c_str());
- return true;
- }
-
XLineFactory* xlf = ServerInstance->XLines->GetFactory(params[0]);
-
- std::string setter = "<unknown>";
- User* usr = ServerInstance->FindNick(prefix);
- if (usr)
- setter = usr->nick;
- else
- {
- TreeServer* t = Utils->FindServer(prefix);
- if (t)
- setter = t->GetName();
- }
+ const std::string& setter = usr->nick;
if (!xlf)
{
ServerInstance->SNO->WriteToSnoMask('d',"%s sent me an unknown ADDLINE type (%s).",setter.c_str(),params[0].c_str());
- return true;
+ return CMD_FAILURE;
}
- long created = atol(params[3].c_str()), expires = atol(params[4].c_str());
- if (created < 0 || expires < 0)
- return true;
-
XLine* xl = NULL;
try
{
- xl = xlf->Generate(ServerInstance->Time(), expires, params[2], params[5], params[1]);
+ xl = xlf->Generate(ServerInstance->Time(), ConvToInt(params[4]), params[2], params[5], params[1]);
}
catch (ModuleException &e)
{
- ServerInstance->SNO->WriteToSnoMask('d',"Unable to ADDLINE type %s from %s: %s", params[0].c_str(), setter.c_str(), e.GetReason());
- return true;
+ ServerInstance->SNO->WriteToSnoMask('d',"Unable to ADDLINE type %s from %s: %s", params[0].c_str(), setter.c_str(), e.GetReason().c_str());
+ return CMD_FAILURE;
}
- xl->SetCreateTime(created);
+ xl->SetCreateTime(ConvToInt(params[3]));
if (ServerInstance->XLines->AddLine(xl, NULL))
{
if (xl->duration)
{
- std::string timestr = ServerInstance->TimeString(xl->expiry);
+ std::string timestr = InspIRCd::TimeString(xl->expiry);
ServerInstance->SNO->WriteToSnoMask('X',"%s added %s%s on %s to expire on %s: %s",setter.c_str(),params[0].c_str(),params[0].length() == 1 ? "-line" : "",
params[1].c_str(), timestr.c_str(), params[5].c_str());
}
@@ -82,20 +59,29 @@ bool TreeSocket::AddLine(const std::string &prefix, parameterlist &params)
ServerInstance->SNO->WriteToSnoMask('X',"%s added permanent %s%s on %s: %s",setter.c_str(),params[0].c_str(),params[0].length() == 1 ? "-line" : "",
params[1].c_str(),params[5].c_str());
}
- params[5] = ":" + params[5];
- User* u = ServerInstance->FindNick(prefix);
- Utils->DoOneToAllButSender(prefix, "ADDLINE", params, u ? u->server : prefix);
- TreeServer *remoteserver = Utils->FindServer(u ? u->server : prefix);
+ TreeServer* remoteserver = TreeServer::Get(usr);
if (!remoteserver->bursting)
{
ServerInstance->XLines->ApplyLines();
}
+ return CMD_SUCCESS;
}
else
+ {
delete xl;
-
- return true;
+ return CMD_FAILURE;
+ }
}
+CommandAddLine::Builder::Builder(XLine* xline, User* user)
+ : CmdBuilder(user, "ADDLINE")
+{
+ push(xline->type);
+ push(xline->Displayable());
+ push(xline->source);
+ push_int(xline->set_time);
+ push_int(xline->duration);
+ push_last(xline->reason);
+}
diff --git a/src/modules/m_spanningtree/away.cpp b/src/modules/m_spanningtree/away.cpp
index ed97c48cd..f14c8ac98 100644
--- a/src/modules/m_spanningtree/away.cpp
+++ b/src/modules/m_spanningtree/away.cpp
@@ -21,32 +21,38 @@
#include "main.h"
#include "utils.h"
-#include "treeserver.h"
-#include "treesocket.h"
+#include "commands.h"
-bool TreeSocket::Away(const std::string &prefix, parameterlist &params)
+CmdResult CommandAway::HandleRemote(RemoteUser* u, std::vector<std::string>& params)
{
- User* u = ServerInstance->FindNick(prefix);
- if ((!u) || (IS_SERVER(u)))
- return true;
if (params.size())
{
- FOREACH_MOD(I_OnSetAway, OnSetAway(u, params[params.size() - 1]));
+ FOREACH_MOD(OnSetAway, (u, params.back()));
if (params.size() > 1)
- u->awaytime = atoi(params[0].c_str());
+ u->awaytime = ConvToInt(params[0]);
else
u->awaytime = ServerInstance->Time();
- u->awaymsg = params[params.size() - 1];
-
- params[params.size() - 1] = ":" + params[params.size() - 1];
+ u->awaymsg = params.back();
}
else
{
- FOREACH_MOD(I_OnSetAway, OnSetAway(u, ""));
+ FOREACH_MOD(OnSetAway, (u, ""));
u->awaymsg.clear();
}
- Utils->DoOneToAllButSender(prefix,"AWAY",params,u->server);
- return true;
+ return CMD_SUCCESS;
+}
+
+CommandAway::Builder::Builder(User* user)
+ : CmdBuilder(user, "AWAY")
+{
+ push_int(user->awaytime).push_last(user->awaymsg);
+}
+
+CommandAway::Builder::Builder(User* user, const std::string& msg)
+ : CmdBuilder(user, "AWAY")
+{
+ if (!msg.empty())
+ push_int(ServerInstance->Time()).push_last(msg);
}
diff --git a/src/modules/m_spanningtree/cachetimer.cpp b/src/modules/m_spanningtree/cachetimer.cpp
deleted file mode 100644
index be438651d..000000000
--- a/src/modules/m_spanningtree/cachetimer.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-#include "socket.h"
-#include "xline.h"
-
-#include "cachetimer.h"
-#include "main.h"
-#include "utils.h"
-#include "treeserver.h"
-#include "link.h"
-#include "treesocket.h"
-
-/* $ModDep: m_spanningtree/cachetimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h */
-
-CacheRefreshTimer::CacheRefreshTimer(SpanningTreeUtilities *Util) : Timer(3600, ServerInstance->Time(), true), Utils(Util)
-{
-}
-
-void CacheRefreshTimer::Tick(time_t TIME)
-{
- Utils->RefreshIPCache();
-}
-
diff --git a/src/modules/m_spanningtree/cachetimer.h b/src/modules/m_spanningtree/cachetimer.h
index bad1b7419..89933cc4b 100644
--- a/src/modules/m_spanningtree/cachetimer.h
+++ b/src/modules/m_spanningtree/cachetimer.h
@@ -17,13 +17,7 @@
*/
-#ifndef M_SPANNINGTREE_CACHETIMER_H
-#define M_SPANNINGTREE_CACHETIMER_H
-
-#include "timer.h"
-
-class ModuleSpanningTree;
-class SpanningTreeUtilities;
+#pragma once
/** Create a timer which recurs every second, we inherit from Timer.
* Timer is only one-shot however, so at the end of each Tick() we simply
@@ -31,11 +25,7 @@ class SpanningTreeUtilities;
*/
class CacheRefreshTimer : public Timer
{
- private:
- SpanningTreeUtilities *Utils;
public:
- CacheRefreshTimer(SpanningTreeUtilities* Util);
- virtual void Tick(time_t TIME);
+ CacheRefreshTimer();
+ bool Tick(time_t TIME);
};
-
-#endif
diff --git a/src/modules/m_spanningtree/capab.cpp b/src/modules/m_spanningtree/capab.cpp
index 7b6435898..f27fe8889 100644
--- a/src/modules/m_spanningtree/capab.cpp
+++ b/src/modules/m_spanningtree/capab.cpp
@@ -20,9 +20,7 @@
#include "inspircd.h"
-#include "xline.h"
-#include "treesocket.h"
#include "treeserver.h"
#include "utils.h"
#include "link.h"
@@ -30,27 +28,22 @@
std::string TreeSocket::MyModules(int filter)
{
- std::vector<std::string> modlist = ServerInstance->Modules->GetAllModuleNames(filter);
-
- if (filter == VF_COMMON && proto_version != ProtocolVersion)
- CompatAddModules(modlist);
+ const ModuleManager::ModuleMap& modlist = ServerInstance->Modules->GetModules();
std::string capabilities;
- sort(modlist.begin(),modlist.end());
- for (std::vector<std::string>::const_iterator i = modlist.begin(); i != modlist.end(); ++i)
+ for (ModuleManager::ModuleMap::const_iterator i = modlist.begin(); i != modlist.end(); ++i)
{
+ Version v = i->second->GetVersion();
+ if (!(v.Flags & filter))
+ continue;
+
if (i != modlist.begin())
- capabilities.push_back(proto_version > 1201 ? ' ' : ',');
- capabilities.append(*i);
- Module* m = ServerInstance->Modules->Find(*i);
- if (m && proto_version > 1201)
+ capabilities.push_back(' ');
+ capabilities.append(i->first);
+ if (!v.link_data.empty())
{
- Version v = m->GetVersion();
- if (!v.link_data.empty())
- {
- capabilities.push_back('=');
- capabilities.append(v.link_data);
- }
+ capabilities.push_back('=');
+ capabilities.append(v.link_data);
}
}
return capabilities;
@@ -66,16 +59,18 @@ static std::string BuildModeList(ModeType type)
{
std::string mdesc = mh->name;
mdesc.push_back('=');
- if (mh->GetPrefix())
- mdesc.push_back(mh->GetPrefix());
- if (mh->GetModeChar())
- mdesc.push_back(mh->GetModeChar());
+ PrefixMode* pm = mh->IsPrefixMode();
+ if (pm)
+ {
+ if (pm->GetPrefix())
+ mdesc.push_back(pm->GetPrefix());
+ }
+ mdesc.push_back(mh->GetModeChar());
modes.push_back(mdesc);
}
}
- sort(modes.begin(), modes.end());
- irc::stringjoiner line(" ", modes, 0, modes.size() - 1);
- return line.GetJoined();
+ std::sort(modes.begin(), modes.end());
+ return irc::stringjoiner(modes);
}
void TreeSocket::SendCapabilities(int phase)
@@ -90,7 +85,7 @@ void TreeSocket::SendCapabilities(int phase)
if (phase < 2)
return;
- char sep = proto_version > 1201 ? ' ' : ',';
+ const char sep = ' ';
irc::sepstream modulelist(MyModules(VF_COMMON), sep);
irc::sepstream optmodulelist(MyModules(VF_OPTCOMMON), sep);
/* Send module names, split at 509 length */
@@ -134,13 +129,15 @@ void TreeSocket::SendCapabilities(int phase)
std::string extra;
/* Do we have sha256 available? If so, we send a challenge */
- if (Utils->ChallengeResponse && (ServerInstance->Modules->Find("m_sha256.so")))
+ if (ServerInstance->Modules->FindService(SERVICE_DATA, "hash/sha256"))
{
SetOurChallenge(ServerInstance->GenRandomStr(20));
extra = " CHALLENGE=" + this->GetOurChallenge();
}
- if (proto_version < 1202)
- extra += ServerInstance->Modes->FindMode('h', MODETYPE_CHANNEL) ? " HALFOP=1" : " HALFOP=0";
+
+ // 2.0 needs this key
+ if (proto_version == 1202)
+ extra.append(" PROTOCOL="+ConvToStr(ProtocolVersion));
this->WriteLine("CAPAB CAPABILITIES " /* Preprocessor does this one. */
":NICKMAX="+ConvToStr(ServerInstance->Config->Limits.NickMax)+
@@ -152,18 +149,18 @@ void TreeSocket::SendCapabilities(int phase)
" MAXKICK="+ConvToStr(ServerInstance->Config->Limits.MaxKick)+
" MAXGECOS="+ConvToStr(ServerInstance->Config->Limits.MaxGecos)+
" MAXAWAY="+ConvToStr(ServerInstance->Config->Limits.MaxAway)+
- " IP6SUPPORT=1"+
- " PROTOCOL="+ConvToStr(ProtocolVersion)+extra+
+ " MAXHOST="+ConvToStr(ServerInstance->Config->Limits.MaxHost)+
+ extra+
" PREFIX="+ServerInstance->Modes->BuildPrefixes()+
- " CHANMODES="+ServerInstance->Modes->GiveModeList(MASK_CHANNEL)+
- " USERMODES="+ServerInstance->Modes->GiveModeList(MASK_USER)+
+ " CHANMODES="+ServerInstance->Modes->GiveModeList(MODETYPE_CHANNEL)+
+ " USERMODES="+ServerInstance->Modes->GiveModeList(MODETYPE_USER)+
// XXX: Advertise the presence or absence of m_globops in CAPAB CAPABILITIES.
// Services want to know about it, and since m_globops was not marked as VF_(OPT)COMMON
// in 2.0, we advertise it here to not break linking to previous versions.
// Protocol version 1201 (1.2) does not have this issue because we advertise m_globops
// to 1201 protocol servers irrespectively of its module flags.
- (ServerInstance->Modules->Find("m_globops.so") != NULL ? " GLOBOPS=1" : " GLOBOPS=0")+
- " SVSPART=1");
+ (ServerInstance->Modules->Find("m_globops.so") != NULL ? " GLOBOPS=1" : " GLOBOPS=0")
+ );
this->WriteLine("CAPAB END");
}
@@ -208,7 +205,23 @@ bool TreeSocket::Capab(const parameterlist &params)
capab->OptModuleList.clear();
capab->CapKeys.clear();
if (params.size() > 1)
- proto_version = atoi(params[1].c_str());
+ proto_version = ConvToInt(params[1]);
+
+ if (proto_version < MinCompatProtocol)
+ {
+ SendError("CAPAB negotiation failed: Server is using protocol version " + (proto_version ? ConvToStr(proto_version) : "1201 or older")
+ + " which is too old to link with this server (version " + ConvToStr(ProtocolVersion)
+ + (ProtocolVersion != MinCompatProtocol ? ", links with " + ConvToStr(MinCompatProtocol) + " and above)" : ")"));
+ return false;
+ }
+
+ // Special case, may be removed in the future
+ if (proto_version == 1203 || proto_version == 1204)
+ {
+ SendError("CAPAB negotiation failed: InspIRCd 2.1 beta is not supported");
+ return false;
+ }
+
SendCapabilities(2);
}
else if (params[0] == "END")
@@ -218,7 +231,7 @@ bool TreeSocket::Capab(const parameterlist &params)
if ((this->capab->ModuleList != this->MyModules(VF_COMMON)) && (this->capab->ModuleList.length()))
{
std::string diffIneed, diffUneed;
- ListDifference(this->capab->ModuleList, this->MyModules(VF_COMMON), proto_version > 1201 ? ' ' : ',', diffIneed, diffUneed);
+ ListDifference(this->capab->ModuleList, this->MyModules(VF_COMMON), ' ', diffIneed, diffUneed);
if (diffIneed.length() || diffUneed.length())
{
reason = "Modules incorrectly matched on these servers.";
@@ -256,21 +269,6 @@ bool TreeSocket::Capab(const parameterlist &params)
}
}
- if (this->capab->CapKeys.find("PROTOCOL") == this->capab->CapKeys.end())
- {
- reason = "Protocol version not specified";
- }
- else
- {
- proto_version = atoi(capab->CapKeys.find("PROTOCOL")->second.c_str());
- if (proto_version < MinCompatProtocol)
- {
- reason = "Server is using protocol version " + ConvToStr(proto_version) +
- " which is too old to link with this server (version " + ConvToStr(ProtocolVersion)
- + (ProtocolVersion != MinCompatProtocol ? ", links with " + ConvToStr(MinCompatProtocol) + " and above)" : ")");
- }
- }
-
if(this->capab->CapKeys.find("PREFIX") != this->capab->CapKeys.end() && this->capab->CapKeys.find("PREFIX")->second != ServerInstance->Modes->BuildPrefixes())
reason = "One or more of the prefixes on the remote server are invalid on this server.";
@@ -292,7 +290,7 @@ bool TreeSocket::Capab(const parameterlist &params)
}
else if (this->capab->CapKeys.find("CHANMODES") != this->capab->CapKeys.end())
{
- if (this->capab->CapKeys.find("CHANMODES")->second != ServerInstance->Modes->GiveModeList(MASK_CHANNEL))
+ if (this->capab->CapKeys.find("CHANMODES")->second != ServerInstance->Modes->GiveModeList(MODETYPE_CHANNEL))
reason = "One or more of the channel modes on the remote server are invalid on this server.";
}
@@ -314,13 +312,13 @@ bool TreeSocket::Capab(const parameterlist &params)
}
else if (this->capab->CapKeys.find("USERMODES") != this->capab->CapKeys.end())
{
- if (this->capab->CapKeys.find("USERMODES")->second != ServerInstance->Modes->GiveModeList(MASK_USER))
+ if (this->capab->CapKeys.find("USERMODES")->second != ServerInstance->Modes->GiveModeList(MODETYPE_USER))
reason = "One or more of the user modes on the remote server are invalid on this server.";
}
/* Challenge response, store their challenge for our password */
std::map<std::string,std::string>::iterator n = this->capab->CapKeys.find("CHALLENGE");
- if (Utils->ChallengeResponse && (n != this->capab->CapKeys.end()) && (ServerInstance->Modules->Find("m_sha256.so")))
+ if ((n != this->capab->CapKeys.end()) && (ServerInstance->Modules->FindService(SERVICE_DATA, "hash/sha256")))
{
/* Challenge-response is on now */
this->SetTheirChallenge(n->second);
@@ -332,7 +330,7 @@ bool TreeSocket::Capab(const parameterlist &params)
}
else
{
- /* They didnt specify a challenge or we don't have m_sha256.so, we use plaintext */
+ // They didn't specify a challenge or we don't have sha256, we use plaintext
if (this->LinkState == CONNECTING)
{
this->SendCapabilities(2);
@@ -354,7 +352,7 @@ bool TreeSocket::Capab(const parameterlist &params)
}
else
{
- capab->ModuleList.push_back(proto_version > 1201 ? ' ' : ',');
+ capab->ModuleList.push_back(' ');
capab->ModuleList.append(params[1]);
}
}
@@ -396,4 +394,3 @@ bool TreeSocket::Capab(const parameterlist &params)
}
return true;
}
-
diff --git a/src/modules/m_spanningtree/commandbuilder.h b/src/modules/m_spanningtree/commandbuilder.h
new file mode 100644
index 000000000..c2b438deb
--- /dev/null
+++ b/src/modules/m_spanningtree/commandbuilder.h
@@ -0,0 +1,147 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2013 Attila Molnar <attilamolnar@hush.com>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#pragma once
+
+#include "utils.h"
+
+class TreeServer;
+
+class CmdBuilder
+{
+ protected:
+ std::string content;
+
+ public:
+ CmdBuilder(const char* cmd)
+ : content(1, ':')
+ {
+ content.append(ServerInstance->Config->GetSID());
+ push(cmd);
+ }
+
+ CmdBuilder(const std::string& src, const char* cmd)
+ : content(1, ':')
+ {
+ content.append(src);
+ push(cmd);
+ }
+
+ CmdBuilder(User* src, const char* cmd)
+ : content(1, ':')
+ {
+ content.append(src->uuid);
+ push(cmd);
+ }
+
+ CmdBuilder& push_raw(const std::string& s)
+ {
+ content.append(s);
+ return *this;
+ }
+
+ CmdBuilder& push_raw(const char* s)
+ {
+ content.append(s);
+ return *this;
+ }
+
+ CmdBuilder& push_raw(char c)
+ {
+ content.push_back(c);
+ return *this;
+ }
+
+ template <typename T>
+ CmdBuilder& push_raw_int(T i)
+ {
+ content.append(ConvToStr(i));
+ return *this;
+ }
+
+ CmdBuilder& push(const std::string& s)
+ {
+ content.push_back(' ');
+ content.append(s);
+ return *this;
+ }
+
+ CmdBuilder& push(const char* s)
+ {
+ content.push_back(' ');
+ content.append(s);
+ return *this;
+ }
+
+ CmdBuilder& push(char c)
+ {
+ content.push_back(' ');
+ content.push_back(c);
+ return *this;
+ }
+
+ template <typename T>
+ CmdBuilder& push_int(T i)
+ {
+ content.push_back(' ');
+ content.append(ConvToStr(i));
+ return *this;
+ }
+
+ CmdBuilder& push_last(const std::string& s)
+ {
+ content.push_back(' ');
+ content.push_back(':');
+ content.append(s);
+ return *this;
+ }
+
+ template<typename T>
+ CmdBuilder& insert(const T& cont)
+ {
+ for (typename T::const_iterator i = cont.begin(); i != cont.end(); ++i)
+ push(*i);
+ return *this;
+ }
+
+ void push_back(const std::string& s) { push(s); }
+
+ const std::string& str() const { return content; }
+ operator const std::string&() const { return str(); }
+
+ void Broadcast() const
+ {
+ Utils->DoOneToMany(*this);
+ }
+
+ void Forward(TreeServer* omit) const
+ {
+ Utils->DoOneToAllButSender(*this, omit);
+ }
+
+ bool Unicast(const std::string& target) const
+ {
+ return Utils->DoOneToOne(*this, target);
+ }
+
+ void Unicast(User* target) const
+ {
+ Utils->DoOneToOne(*this, target->server);
+ }
+};
diff --git a/src/modules/m_spanningtree/commands.h b/src/modules/m_spanningtree/commands.h
index 3b5b499c1..3047e7e60 100644
--- a/src/modules/m_spanningtree/commands.h
+++ b/src/modules/m_spanningtree/commands.h
@@ -17,126 +17,345 @@
*/
-#ifndef M_SPANNINGTREE_COMMANDS_H
-#define M_SPANNINGTREE_COMMANDS_H
+#pragma once
-#include "main.h"
+#include "servercommand.h"
+#include "commandbuilder.h"
/** Handle /RCONNECT
*/
class CommandRConnect : public Command
{
- SpanningTreeUtilities* Utils; /* Utility class */
public:
- CommandRConnect (Module* Callback, SpanningTreeUtilities* Util);
- CmdResult Handle (const std::vector<std::string>& parameters, User *user);
- RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters);
+ CommandRConnect(Module* Creator);
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user);
+ RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters);
};
class CommandRSQuit : public Command
{
- SpanningTreeUtilities* Utils; /* Utility class */
public:
- CommandRSQuit(Module* Callback, SpanningTreeUtilities* Util);
- CmdResult Handle (const std::vector<std::string>& parameters, User *user);
- RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters);
- void NoticeUser(User* user, const std::string &msg);
+ CommandRSQuit(Module* Creator);
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user);
+ RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters);
};
-class CommandSVSJoin : public Command
+class CommandMap : public Command
{
public:
- CommandSVSJoin(Module* Creator) : Command(Creator, "SVSJOIN", 2) { flags_needed = FLAG_SERVERONLY; }
- CmdResult Handle (const std::vector<std::string>& parameters, User *user);
+ CommandMap(Module* Creator);
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user);
RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters);
};
-class CommandSVSPart : public Command
+
+class CommandSVSJoin : public ServerCommand
{
public:
- CommandSVSPart(Module* Creator) : Command(Creator, "SVSPART", 2) { flags_needed = FLAG_SERVERONLY; }
- CmdResult Handle (const std::vector<std::string>& parameters, User *user);
+ CommandSVSJoin(Module* Creator) : ServerCommand(Creator, "SVSJOIN", 2) { }
+ CmdResult Handle(User* user, std::vector<std::string>& params);
RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters);
};
-class CommandSVSNick : public Command
+
+class CommandSVSPart : public ServerCommand
{
public:
- CommandSVSNick(Module* Creator) : Command(Creator, "SVSNICK", 3) { flags_needed = FLAG_SERVERONLY; }
- CmdResult Handle (const std::vector<std::string>& parameters, User *user);
+ CommandSVSPart(Module* Creator) : ServerCommand(Creator, "SVSPART", 2) { }
+ CmdResult Handle(User* user, std::vector<std::string>& params);
RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters);
};
-class CommandMetadata : public Command
+
+class CommandSVSNick : public ServerCommand
{
public:
- CommandMetadata(Module* Creator) : Command(Creator, "METADATA", 2) { flags_needed = FLAG_SERVERONLY; }
- CmdResult Handle (const std::vector<std::string>& parameters, User *user);
- RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_BROADCAST; }
+ CommandSVSNick(Module* Creator) : ServerCommand(Creator, "SVSNICK", 3) { }
+ CmdResult Handle(User* user, std::vector<std::string>& params);
+ RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters);
};
-class CommandUID : public Command
+
+class CommandMetadata : public ServerCommand
{
public:
- CommandUID(Module* Creator) : Command(Creator, "UID", 10) { flags_needed = FLAG_SERVERONLY; }
- CmdResult Handle (const std::vector<std::string>& parameters, User *user);
- RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_BROADCAST; }
+ CommandMetadata(Module* Creator) : ServerCommand(Creator, "METADATA", 2) { }
+ CmdResult Handle(User* user, std::vector<std::string>& params);
+
+ class Builder : public CmdBuilder
+ {
+ public:
+ Builder(User* user, const std::string& key, const std::string& val);
+ Builder(Channel* chan, const std::string& key, const std::string& val);
+ Builder(const std::string& key, const std::string& val);
+ };
};
-class CommandOpertype : public Command
+
+class CommandUID : public ServerOnlyServerCommand<CommandUID>
{
public:
- CommandOpertype(Module* Creator) : Command(Creator, "OPERTYPE", 1) { flags_needed = FLAG_SERVERONLY; }
- CmdResult Handle (const std::vector<std::string>& parameters, User *user);
- RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_BROADCAST; }
+ CommandUID(Module* Creator) : ServerOnlyServerCommand<CommandUID>(Creator, "UID", 10) { }
+ CmdResult HandleServer(TreeServer* server, std::vector<std::string>& params);
+
+ class Builder : public CmdBuilder
+ {
+ public:
+ Builder(User* user);
+ };
};
-class CommandFJoin : public Command
+
+class CommandOpertype : public UserOnlyServerCommand<CommandOpertype>
{
public:
- CommandFJoin(Module* Creator) : Command(Creator, "FJOIN", 3) { flags_needed = FLAG_SERVERONLY; }
- CmdResult Handle (const std::vector<std::string>& parameters, User *user);
- RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_BROADCAST; }
+ CommandOpertype(Module* Creator) : UserOnlyServerCommand<CommandOpertype>(Creator, "OPERTYPE", 1) { }
+ CmdResult HandleRemote(RemoteUser* user, std::vector<std::string>& params);
+
+ class Builder : public CmdBuilder
+ {
+ public:
+ Builder(User* user);
+ };
+};
+
+class TreeSocket;
+class CommandFJoin : public ServerCommand
+{
/** Remove all modes from a channel, including statusmodes (+qaovh etc), simplemodes, parameter modes.
* This does not update the timestamp of the target channel, this must be done seperately.
*/
- void RemoveStatus(User* source, parameterlist &params);
+ static void RemoveStatus(Channel* c);
+ static void ApplyModeStack(User* srcuser, Channel* c, irc::modestacker& stack);
+
+ /**
+ * Lowers the TS on the given channel: removes all modes, unsets all extensions,
+ * clears the topic and removes all pending invites.
+ * @param chan The target channel whose TS to lower
+ * @param TS The new TS to set
+ * @param newname The new name of the channel; must be the same or a case change of the current name
+ */
+ static void LowerTS(Channel* chan, time_t TS, const std::string& newname);
+ void ProcessModeUUIDPair(const std::string& item, TreeServer* sourceserver, Channel* chan, irc::modestacker* modestack);
+ public:
+ CommandFJoin(Module* Creator) : ServerCommand(Creator, "FJOIN", 3) { }
+ CmdResult Handle(User* user, std::vector<std::string>& params);
+
+ class Builder : public CmdBuilder
+ {
+ /** Maximum possible Membership::Id length in decimal digits, used for determining whether a user will fit into
+ * a message or not
+ */
+ static const size_t membid_max_digits = 20;
+ static const size_t maxline = 480;
+ std::string::size_type pos;
+
+ public:
+ Builder(Channel* chan);
+ void add(Membership* memb);
+ bool has_room(Membership* memb) const;
+ void clear();
+ const std::string& finalize();
+ };
+};
+
+class CommandFMode : public ServerCommand
+{
+ public:
+ CommandFMode(Module* Creator) : ServerCommand(Creator, "FMODE", 3) { }
+ CmdResult Handle(User* user, std::vector<std::string>& params);
+};
+
+class CommandFTopic : public ServerCommand
+{
+ public:
+ CommandFTopic(Module* Creator) : ServerCommand(Creator, "FTOPIC", 4, 5) { }
+ CmdResult Handle(User* user, std::vector<std::string>& params);
+
+ class Builder : public CmdBuilder
+ {
+ public:
+ Builder(Channel* chan);
+ Builder(User* user, Channel* chan);
+ };
+};
+
+class CommandFHost : public UserOnlyServerCommand<CommandFHost>
+{
+ public:
+ CommandFHost(Module* Creator) : UserOnlyServerCommand<CommandFHost>(Creator, "FHOST", 1) { }
+ CmdResult HandleRemote(RemoteUser* user, std::vector<std::string>& params);
+};
+
+class CommandFIdent : public UserOnlyServerCommand<CommandFIdent>
+{
+ public:
+ CommandFIdent(Module* Creator) : UserOnlyServerCommand<CommandFIdent>(Creator, "FIDENT", 1) { }
+ CmdResult HandleRemote(RemoteUser* user, std::vector<std::string>& params);
+};
+
+class CommandFName : public UserOnlyServerCommand<CommandFName>
+{
+ public:
+ CommandFName(Module* Creator) : UserOnlyServerCommand<CommandFName>(Creator, "FNAME", 1) { }
+ CmdResult HandleRemote(RemoteUser* user, std::vector<std::string>& params);
+};
+
+class CommandIJoin : public UserOnlyServerCommand<CommandIJoin>
+{
+ public:
+ CommandIJoin(Module* Creator) : UserOnlyServerCommand<CommandIJoin>(Creator, "IJOIN", 2) { }
+ CmdResult HandleRemote(RemoteUser* user, std::vector<std::string>& params);
+};
+
+class CommandResync : public ServerOnlyServerCommand<CommandResync>
+{
+ public:
+ CommandResync(Module* Creator) : ServerOnlyServerCommand<CommandResync>(Creator, "RESYNC", 1) { }
+ CmdResult HandleServer(TreeServer* server, std::vector<std::string>& parameters);
+ RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_LOCALONLY; }
+};
+
+class CommandAway : public UserOnlyServerCommand<CommandAway>
+{
+ public:
+ CommandAway(Module* Creator) : UserOnlyServerCommand<CommandAway>(Creator, "AWAY", 0, 2) { }
+ CmdResult HandleRemote(RemoteUser* user, std::vector<std::string>& parameters);
+
+ class Builder : public CmdBuilder
+ {
+ public:
+ Builder(User* user);
+ Builder(User* user, const std::string& msg);
+ };
+};
+
+class XLine;
+class CommandAddLine : public ServerCommand
+{
+ public:
+ CommandAddLine(Module* Creator) : ServerCommand(Creator, "ADDLINE", 6, 6) { }
+ CmdResult Handle(User* user, std::vector<std::string>& parameters);
+
+ class Builder : public CmdBuilder
+ {
+ public:
+ Builder(XLine* xline, User* user = ServerInstance->FakeClient);
+ };
+};
+
+class CommandDelLine : public ServerCommand
+{
+ public:
+ CommandDelLine(Module* Creator) : ServerCommand(Creator, "DELLINE", 2, 2) { }
+ CmdResult Handle(User* user, std::vector<std::string>& parameters);
+};
+
+class CommandEncap : public ServerCommand
+{
+ public:
+ CommandEncap(Module* Creator) : ServerCommand(Creator, "ENCAP", 2) { }
+ CmdResult Handle(User* user, std::vector<std::string>& parameters);
+ RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters);
+};
+
+class CommandIdle : public UserOnlyServerCommand<CommandIdle>
+{
+ public:
+ CommandIdle(Module* Creator) : UserOnlyServerCommand<CommandIdle>(Creator, "IDLE", 1) { }
+ CmdResult HandleRemote(RemoteUser* user, std::vector<std::string>& parameters);
+ RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_UNICAST(parameters[0]); }
+};
+
+class CommandNick : public UserOnlyServerCommand<CommandNick>
+{
+ public:
+ CommandNick(Module* Creator) : UserOnlyServerCommand<CommandNick>(Creator, "NICK", 2) { }
+ CmdResult HandleRemote(RemoteUser* user, std::vector<std::string>& parameters);
+};
+
+class CommandPing : public ServerCommand
+{
+ public:
+ CommandPing(Module* Creator) : ServerCommand(Creator, "PING", 1) { }
+ CmdResult Handle(User* user, std::vector<std::string>& parameters);
+ RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_UNICAST(parameters[0]); }
+};
+
+class CommandPong : public ServerOnlyServerCommand<CommandPong>
+{
+ public:
+ CommandPong(Module* Creator) : ServerOnlyServerCommand<CommandPong>(Creator, "PONG", 1) { }
+ CmdResult HandleServer(TreeServer* server, std::vector<std::string>& parameters);
+ RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_UNICAST(parameters[0]); }
+};
+
+class CommandPush : public ServerCommand
+{
+ public:
+ CommandPush(Module* Creator) : ServerCommand(Creator, "PUSH", 2) { }
+ CmdResult Handle(User* user, std::vector<std::string>& parameters);
+ RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_UNICAST(parameters[0]); }
+};
+
+class CommandSave : public ServerCommand
+{
+ public:
+ CommandSave(Module* Creator) : ServerCommand(Creator, "SAVE", 2) { }
+ CmdResult Handle(User* user, std::vector<std::string>& parameters);
};
-class CommandFMode : public Command
+
+class CommandServer : public ServerOnlyServerCommand<CommandServer>
{
public:
- CommandFMode(Module* Creator) : Command(Creator, "FMODE", 3) { flags_needed = FLAG_SERVERONLY; }
- CmdResult Handle (const std::vector<std::string>& parameters, User *user);
- RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_BROADCAST; }
+ CommandServer(Module* Creator) : ServerOnlyServerCommand<CommandServer>(Creator, "SERVER", 5) { }
+ CmdResult HandleServer(TreeServer* server, std::vector<std::string>& parameters);
+
+ class Builder : public CmdBuilder
+ {
+ public:
+ Builder(TreeServer* server);
+ };
};
-class CommandFTopic : public Command
+
+class CommandSQuit : public ServerOnlyServerCommand<CommandSQuit>
{
public:
- CommandFTopic(Module* Creator) : Command(Creator, "FTOPIC", 4) { flags_needed = FLAG_SERVERONLY; }
- CmdResult Handle (const std::vector<std::string>& parameters, User *user);
- RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_BROADCAST; }
+ CommandSQuit(Module* Creator) : ServerOnlyServerCommand<CommandSQuit>(Creator, "SQUIT", 2) { }
+ CmdResult HandleServer(TreeServer* server, std::vector<std::string>& parameters);
};
-class CommandFHost : public Command
+
+class CommandSNONotice : public ServerCommand
{
public:
- CommandFHost(Module* Creator) : Command(Creator, "FHOST", 1) { flags_needed = FLAG_SERVERONLY; }
- CmdResult Handle (const std::vector<std::string>& parameters, User *user);
- RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_BROADCAST; }
+ CommandSNONotice(Module* Creator) : ServerCommand(Creator, "SNONOTICE", 2) { }
+ CmdResult Handle(User* user, std::vector<std::string>& parameters);
};
-class CommandFIdent : public Command
+
+class CommandBurst : public ServerOnlyServerCommand<CommandBurst>
{
public:
- CommandFIdent(Module* Creator) : Command(Creator, "FIDENT", 1) { flags_needed = FLAG_SERVERONLY; }
- CmdResult Handle (const std::vector<std::string>& parameters, User *user);
- RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_BROADCAST; }
+ CommandBurst(Module* Creator) : ServerOnlyServerCommand<CommandBurst>(Creator, "BURST") { }
+ CmdResult HandleServer(TreeServer* server, std::vector<std::string>& parameters);
};
-class CommandFName : public Command
+
+class CommandEndBurst : public ServerOnlyServerCommand<CommandEndBurst>
{
public:
- CommandFName(Module* Creator) : Command(Creator, "FNAME", 1) { flags_needed = FLAG_SERVERONLY; }
- CmdResult Handle (const std::vector<std::string>& parameters, User *user);
- RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_BROADCAST; }
+ CommandEndBurst(Module* Creator) : ServerOnlyServerCommand<CommandEndBurst>(Creator, "ENDBURST") { }
+ CmdResult HandleServer(TreeServer* server, std::vector<std::string>& parameters);
+};
+
+class CommandSInfo : public ServerOnlyServerCommand<CommandSInfo>
+{
+ public:
+ CommandSInfo(Module* Creator) : ServerOnlyServerCommand<CommandSInfo>(Creator, "SINFO", 2) { }
+ CmdResult HandleServer(TreeServer* server, std::vector<std::string>& parameters);
+
+ class Builder : public CmdBuilder
+ {
+ public:
+ Builder(TreeServer* server, const char* type, const std::string& value);
+ };
};
class SpanningTreeCommands
{
public:
- CommandRConnect rconnect;
- CommandRSQuit rsquit;
CommandSVSJoin svsjoin;
CommandSVSPart svspart;
CommandSVSNick svsnick;
@@ -144,12 +363,28 @@ class SpanningTreeCommands
CommandUID uid;
CommandOpertype opertype;
CommandFJoin fjoin;
+ CommandIJoin ijoin;
+ CommandResync resync;
CommandFMode fmode;
CommandFTopic ftopic;
CommandFHost fhost;
CommandFIdent fident;
CommandFName fname;
+ CommandAway away;
+ CommandAddLine addline;
+ CommandDelLine delline;
+ CommandEncap encap;
+ CommandIdle idle;
+ CommandNick nick;
+ CommandPing ping;
+ CommandPong pong;
+ CommandPush push;
+ CommandSave save;
+ CommandServer server;
+ CommandSQuit squit;
+ CommandSNONotice snonotice;
+ CommandBurst burst;
+ CommandEndBurst endburst;
+ CommandSInfo sinfo;
SpanningTreeCommands(ModuleSpanningTree* module);
};
-
-#endif
diff --git a/src/modules/m_spanningtree/compat.cpp b/src/modules/m_spanningtree/compat.cpp
index ec0cdb036..0f55793f1 100644
--- a/src/modules/m_spanningtree/compat.cpp
+++ b/src/modules/m_spanningtree/compat.cpp
@@ -20,177 +20,418 @@
#include "inspircd.h"
#include "main.h"
#include "treesocket.h"
+#include "treeserver.h"
-static const char* const forge_common_1201[] = {
- "m_allowinvite.so",
- "m_alltime.so",
- "m_auditorium.so",
- "m_banexception.so",
- "m_blockcaps.so",
- "m_blockcolor.so",
- "m_botmode.so",
- "m_censor.so",
- "m_chanfilter.so",
- "m_chanhistory.so",
- "m_channelban.so",
- "m_chanprotect.so",
- "m_chghost.so",
- "m_chgname.so",
- "m_commonchans.so",
- "m_customtitle.so",
- "m_deaf.so",
- "m_delayjoin.so",
- "m_delaymsg.so",
- "m_exemptchanops.so",
- "m_gecosban.so",
- "m_globops.so",
- "m_helpop.so",
- "m_hidechans.so",
- "m_hideoper.so",
- "m_invisible.so",
- "m_inviteexception.so",
- "m_joinflood.so",
- "m_kicknorejoin.so",
- "m_knock.so",
- "m_messageflood.so",
- "m_muteban.so",
- "m_nickflood.so",
- "m_nicklock.so",
- "m_noctcp.so",
- "m_nokicks.so",
- "m_nonicks.so",
- "m_nonotice.so",
- "m_nopartmsg.so",
- "m_ojoin.so",
- "m_operprefix.so",
- "m_permchannels.so",
- "m_redirect.so",
- "m_regex_glob.so",
- "m_regex_pcre.so",
- "m_regex_posix.so",
- "m_regex_tre.so",
- "m_remove.so",
- "m_sajoin.so",
- "m_sakick.so",
- "m_sanick.so",
- "m_sapart.so",
- "m_saquit.so",
- "m_serverban.so",
- "m_services_account.so",
- "m_servprotect.so",
- "m_setident.so",
- "m_showwhois.so",
- "m_silence.so",
- "m_sslmodes.so",
- "m_stripcolor.so",
- "m_swhois.so",
- "m_uninvite.so",
- "m_watch.so"
-};
-
-static std::string wide_newline("\r\n");
static std::string newline("\n");
-void TreeSocket::CompatAddModules(std::vector<std::string>& modlist)
-{
- if (proto_version < 1202)
- {
- // you MUST have chgident loaded in order to be able to translate FIDENT
- modlist.push_back("m_chgident.so");
- for(int i=0; i * sizeof(char*) < sizeof(forge_common_1201); i++)
- {
- if (ServerInstance->Modules->Find(forge_common_1201[i]))
- modlist.push_back(forge_common_1201[i]);
- }
- // module was merged
- if (ServerInstance->Modules->Find("m_operchans.so"))
- {
- modlist.push_back("m_operchans.so");
- modlist.push_back("m_operinvex.so");
- }
- }
-}
-
-void TreeSocket::WriteLine(std::string line)
+void TreeSocket::WriteLine(const std::string& original_line)
{
if (LinkState == CONNECTED)
{
- if (line[0] != ':')
+ if (original_line.c_str()[0] != ':')
{
- ServerInstance->Logs->Log("m_spanningtree", DEFAULT, "Sending line without server prefix!");
- line = ":" + ServerInstance->Config->GetSID() + " " + line;
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Sending line without server prefix!");
+ WriteLine(":" + ServerInstance->Config->GetSID() + " " + original_line);
+ return;
}
if (proto_version != ProtocolVersion)
{
+ std::string line = original_line;
std::string::size_type a = line.find(' ');
std::string::size_type b = line.find(' ', a + 1);
std::string command = line.substr(a + 1, b-a-1);
// now try to find a translation entry
// TODO a more efficient lookup method will be needed later
- if (proto_version < 1202 && command == "FIDENT")
- {
- ServerInstance->Logs->Log("m_spanningtree",DEBUG,"Rewriting FIDENT for 1201-protocol server");
- line = ":" + ServerInstance->Config->GetSID() + " CHGIDENT " + line.substr(1,a-1) + line.substr(b);
- }
- else if (proto_version < 1202 && command == "SAVE")
- {
- ServerInstance->Logs->Log("m_spanningtree",DEBUG,"Rewriting SAVE for 1201-protocol server");
- std::string::size_type c = line.find(' ', b + 1);
- std::string uid = line.substr(b, c - b);
- line = ":" + ServerInstance->Config->GetSID() + " SVSNICK" + uid + line.substr(b);
- }
- else if (proto_version < 1202 && command == "AWAY")
+ if (proto_version < 1205)
{
- if (b != std::string::npos)
+ if (command == "IJOIN")
{
- ServerInstance->Logs->Log("m_spanningtree",DEBUG,"Stripping AWAY timestamp for 1201-protocol server");
+ // Convert
+ // :<uid> IJOIN <chan> <membid> [<ts> [<flags>]]
+ // to
+ // :<sid> FJOIN <chan> <ts> + [<flags>],<uuid>
std::string::size_type c = line.find(' ', b + 1);
- line.erase(b,c-b);
+ if (c == std::string::npos)
+ return;
+
+ std::string::size_type d = line.find(' ', c + 1);
+ // Erase membership id first
+ line.erase(c, d-c);
+ if (d == std::string::npos)
+ {
+ // No TS or modes in the command
+ // :22DAAAAAB IJOIN #chan
+ const std::string channame = line.substr(b+1, c-b-1);
+ Channel* chan = ServerInstance->FindChan(channame);
+ if (!chan)
+ return;
+
+ line.push_back(' ');
+ line.append(ConvToStr(chan->age));
+ line.append(" + ,");
+ }
+ else
+ {
+ d = line.find(' ', c + 1);
+ if (d == std::string::npos)
+ {
+ // TS present, no modes
+ // :22DAAAAAC IJOIN #chan 12345
+ line.append(" + ,");
+ }
+ else
+ {
+ // Both TS and modes are present
+ // :22DAAAAAC IJOIN #chan 12345 ov
+ std::string::size_type e = line.find(' ', d + 1);
+ if (e != std::string::npos)
+ line.erase(e);
+
+ line.insert(d, " +");
+ line.push_back(',');
+ }
+ }
+
+ // Move the uuid to the end and replace the I with an F
+ line.append(line.substr(1, 9));
+ line.erase(4, 6);
+ line[5] = 'F';
}
- }
- else if (proto_version < 1202 && command == "ENCAP")
- {
- // :src ENCAP target command [args...]
- // A B C D
- // Therefore B and C cannot be npos in a valid command
- if (b == std::string::npos)
- return;
- std::string::size_type c = line.find(' ', b + 1);
- if (c == std::string::npos)
+ else if (command == "RESYNC")
return;
- std::string::size_type d = line.find(' ', c + 1);
- std::string subcmd = line.substr(c + 1, d - c - 1);
+ else if (command == "METADATA")
+ {
+ // Drop TS for channel METADATA, translate METADATA operquit into an OPERQUIT command
+ // :sid METADATA #target TS extname ...
+ // A B C D
+ if (b == std::string::npos)
+ return;
+
+ std::string::size_type c = line.find(' ', b + 1);
+ if (c == std::string::npos)
+ return;
+
+ std::string::size_type d = line.find(' ', c + 1);
+ if (d == std::string::npos)
+ return;
- if (subcmd == "CHGIDENT" && d != std::string::npos)
+ if (line[b + 1] == '#')
+ {
+ // We're sending channel metadata
+ line.erase(c, d-c);
+ }
+ else if (!line.compare(c, d-c, " operquit", 9))
+ {
+ // ":22D METADATA 22DAAAAAX operquit :message" -> ":22DAAAAAX OPERQUIT :message"
+ line = ":" + line.substr(b+1, c-b) + "OPERQUIT" + line.substr(d);
+ }
+ }
+ else if (command == "FTOPIC")
{
+ // Drop channel TS for FTOPIC
+ // :sid FTOPIC #target TS TopicTS setter :newtopic
+ // A B C D E F
+ // :uid FTOPIC #target TS TopicTS :newtopic
+ // A B C D E
+ if (b == std::string::npos)
+ return;
+
+ std::string::size_type c = line.find(' ', b + 1);
+ if (c == std::string::npos)
+ return;
+
+ std::string::size_type d = line.find(' ', c + 1);
+ if (d == std::string::npos)
+ return;
+
std::string::size_type e = line.find(' ', d + 1);
- if (e == std::string::npos)
- return; // not valid
- std::string target = line.substr(d + 1, e - d - 1);
+ if (line[e+1] == ':')
+ {
+ line.erase(c, e-c);
+ line.erase(a+1, 1);
+ }
+ else
+ line.erase(c, d-c);
+ }
+ else if ((command == "PING") || (command == "PONG"))
+ {
+ // :22D PING 20D
+ if (line.length() < 13)
+ return;
- ServerInstance->Logs->Log("m_spanningtree",DEBUG,"Forging acceptance of CHGIDENT from 1201-protocol server");
- recvq.insert(0, ":" + target + " FIDENT " + line.substr(e) + "\n");
+ // Insert the source SID (and a space) between the command and the first parameter
+ line.insert(10, line.substr(1, 4));
+ }
+ else if (command == "OPERTYPE")
+ {
+ std::string::size_type colon = line.find(':', b);
+ if (colon != std::string::npos)
+ {
+ for (std::string::iterator i = line.begin()+colon; i != line.end(); ++i)
+ {
+ if (*i == ' ')
+ *i = '_';
+ }
+ line.erase(colon, 1);
+ }
}
+ else if (command == "INVITE")
+ {
+ // :22D INVITE 22DAAAAAN #chan TS ExpirationTime
+ // A B C D E
+ if (b == std::string::npos)
+ return;
- Command* thiscmd = ServerInstance->Parser->GetHandler(subcmd);
- if (thiscmd && subcmd != "WHOISNOTICE")
+ std::string::size_type c = line.find(' ', b + 1);
+ if (c == std::string::npos)
+ return;
+
+ std::string::size_type d = line.find(' ', c + 1);
+ if (d == std::string::npos)
+ return;
+
+ std::string::size_type e = line.find(' ', d + 1);
+ // If there is no expiration time then everything will be erased from 'd'
+ line.erase(d, e-d);
+ }
+ else if (command == "FJOIN")
{
- Version ver = thiscmd->creator->GetVersion();
- if (ver.Flags & VF_OPTCOMMON)
+ // Strip membership ids
+ // :22D FJOIN #chan 1234 +f 4:3 :o,22DAAAAAB:15 o,22DAAAAAA:15
+ // :22D FJOIN #chan 1234 +f 4:3 o,22DAAAAAB:15
+ // :22D FJOIN #chan 1234 +Pf 4:3 :
+
+ // If the last parameter is prefixed by a colon then it's a userlist which may have 0 or more users;
+ // if it isn't, then it is a single member
+ std::string::size_type spcolon = line.find(" :");
+ if (spcolon != std::string::npos)
+ {
+ spcolon++;
+ // Loop while there is a ':' in the userlist, this is never true if the channel is empty
+ std::string::size_type pos = std::string::npos;
+ while ((pos = line.rfind(':', pos-1)) > spcolon)
+ {
+ // Find the next space after the ':'
+ std::string::size_type sp = line.find(' ', pos);
+ // Erase characters between the ':' and the next space after it, including the ':' but not the space;
+ // if there is no next space, everything will be erased between pos and the end of the line
+ line.erase(pos, sp-pos);
+ }
+ }
+ else
{
- ServerInstance->Logs->Log("m_spanningtree",DEBUG,"Removing ENCAP on '%s' for 1201-protocol server",
- subcmd.c_str());
- line.erase(a, c-a);
+ // Last parameter is a single member
+ std::string::size_type sp = line.rfind(' ');
+ std::string::size_type colon = line.find(':', sp);
+ line.erase(colon);
}
}
+ else if (command == "KICK")
+ {
+ // Strip membership id if the KICK has one
+ if (b == std::string::npos)
+ return;
+
+ std::string::size_type c = line.find(' ', b + 1);
+ if (c == std::string::npos)
+ return;
+
+ std::string::size_type d = line.find(' ', c + 1);
+ if ((d < line.size()-1) && (original_line[d+1] != ':'))
+ {
+ // There is a third parameter which doesn't begin with a colon, erase it
+ std::string::size_type e = line.find(' ', d + 1);
+ line.erase(d, e-d);
+ }
+ }
+ else if (command == "SINFO")
+ {
+ // :22D SINFO version :InspIRCd-2.2
+ // A B C
+ std::string::size_type c = line.find(' ', b + 1);
+ if (c == std::string::npos)
+ return;
+
+ // Only translating SINFO version, discard everything else
+ if (line.compare(b, 9, " version ", 9))
+ return;
+
+ line = line.substr(0, 5) + "VERSION" + line.substr(c);
+ }
}
+ ServerInstance->Logs->Log(MODNAME, LOG_RAWIO, "S[%d] O %s", this->GetFd(), line.c_str());
+ this->WriteData(line);
+ this->WriteData(newline);
+ return;
+ }
+ }
+
+ ServerInstance->Logs->Log(MODNAME, LOG_RAWIO, "S[%d] O %s", this->GetFd(), original_line.c_str());
+ this->WriteData(original_line);
+ this->WriteData(newline);
+}
+
+namespace
+{
+ bool InsertCurrentChannelTS(std::vector<std::string>& params, unsigned int chanindex = 0, unsigned int pos = 1)
+ {
+ Channel* chan = ServerInstance->FindChan(params[chanindex]);
+ if (!chan)
+ return false;
+
+ // Insert the current TS of the channel after the pos-th parameter
+ params.insert(params.begin()+pos, ConvToStr(chan->age));
+ return true;
+ }
+}
+
+bool TreeSocket::PreProcessOldProtocolMessage(User*& who, std::string& cmd, std::vector<std::string>& params)
+{
+ if ((cmd == "METADATA") && (params.size() >= 3) && (params[0][0] == '#'))
+ {
+ // :20D METADATA #channel extname :extdata
+ return InsertCurrentChannelTS(params);
+ }
+ else if ((cmd == "FTOPIC") && (params.size() >= 4))
+ {
+ // :20D FTOPIC #channel 100 Attila :topic text
+ return InsertCurrentChannelTS(params);
+ }
+ else if ((cmd == "PING") || (cmd == "PONG"))
+ {
+ if (params.size() == 1)
+ {
+ // If it's a PING with 1 parameter, reply with a PONG now, if it's a PONG with 1 parameter (weird), do nothing
+ if (cmd[1] == 'I')
+ this->WriteData(":" + ServerInstance->Config->GetSID() + " PONG " + params[0] + newline);
+
+ // Don't process this message further
+ return false;
+ }
+
+ // :20D PING 20D 22D
+ // :20D PONG 20D 22D
+ // Drop the first parameter
+ params.erase(params.begin());
+
+ // If the target is a server name, translate it to a SID
+ if (!InspIRCd::IsSID(params[0]))
+ {
+ TreeServer* server = Utils->FindServer(params[0]);
+ if (!server)
+ {
+ // We've no idea what this is, log and stop processing
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Received a " + cmd + " with an unknown target: \"" + params[0] + "\", command dropped");
+ return false;
+ }
+
+ params[0] = server->GetID();
+ }
+ }
+ else if ((cmd == "GLINE") || (cmd == "KLINE") || (cmd == "ELINE") || (cmd == "ZLINE") || (cmd == "QLINE"))
+ {
+ // Fix undocumented protocol usage: translate GLINE, ZLINE, etc. into ADDLINE or DELLINE
+ if ((params.size() != 1) && (params.size() != 3))
+ return false;
+
+ parameterlist p;
+ p.push_back(cmd.substr(0, 1));
+ p.push_back(params[0]);
+
+ if (params.size() == 3)
+ {
+ cmd = "ADDLINE";
+ p.push_back(who->nick);
+ p.push_back(ConvToStr(ServerInstance->Time()));
+ p.push_back(ConvToStr(InspIRCd::Duration(params[1])));
+ p.push_back(params[2]);
+ }
+ else
+ cmd = "DELLINE";
+
+ params.swap(p);
+ }
+ else if (cmd == "SVSMODE")
+ {
+ cmd = "MODE";
+ }
+ else if (cmd == "OPERQUIT")
+ {
+ // Translate OPERQUIT into METADATA
+ if (params.empty())
+ return false;
+
+ cmd = "METADATA";
+ params.insert(params.begin(), who->uuid);
+ params.insert(params.begin()+1, "operquit");
+ who = MyRoot->ServerUser;
+ }
+ else if ((cmd == "TOPIC") && (params.size() >= 2))
+ {
+ // :20DAAAAAC TOPIC #chan :new topic
+ cmd = "FTOPIC";
+ if (!InsertCurrentChannelTS(params))
+ return false;
+
+ params.insert(params.begin()+2, ConvToStr(ServerInstance->Time()));
+ }
+ else if (cmd == "MODENOTICE")
+ {
+ // MODENOTICE is always supported by 2.0 but it's optional in 2.2.
+ params.insert(params.begin(), "*");
+ params.insert(params.begin()+1, cmd);
+ cmd = "ENCAP";
+ }
+ else if (cmd == "RULES")
+ {
+ return false;
+ }
+ else if (cmd == "INVITE")
+ {
+ // :20D INVITE 22DAAABBB #chan
+ // :20D INVITE 22DAAABBB #chan 123456789
+ // Insert channel timestamp after the channel name; the 3rd parameter, if there, is the invite expiration time
+ return InsertCurrentChannelTS(params, 1, 2);
+ }
+ else if (cmd == "VERSION")
+ {
+ // :20D VERSION :InspIRCd-2.0
+ // change to
+ // :20D SINFO version :InspIRCd-2.0
+ cmd = "SINFO";
+ params.insert(params.begin(), "version");
+ }
+ else if (cmd == "JOIN")
+ {
+ // 2.0 allows and forwards legacy JOINs but we don't, so translate them to FJOINs before processing
+ if ((params.size() != 1) || (IS_SERVER(who)))
+ return false; // Huh?
+
+ cmd = "FJOIN";
+ Channel* chan = ServerInstance->FindChan(params[0]);
+ params.push_back(ConvToStr(chan ? chan->age : ServerInstance->Time()));
+ params.push_back("+");
+ params.push_back(",");
+ params.back().append(who->uuid);
+ who = TreeServer::Get(who)->ServerUser;
+ }
+ else if ((cmd == "FMODE") && (params.size() >= 2))
+ {
+ // Translate user mode changes with timestamp to MODE
+ if (params[0][0] != '#')
+ {
+ User* user = ServerInstance->FindUUID(params[0]);
+ if (!user)
+ return false;
+
+ // Emulate the old nonsensical behavior
+ if (user->age < ServerCommand::ExtractTS(params[1]))
+ return false;
+
+ cmd = "MODE";
+ params.erase(params.begin()+1);
}
}
- ServerInstance->Logs->Log("m_spanningtree", RAWIO, "S[%d] O %s", this->GetFd(), line.c_str());
- this->WriteData(line);
- if (proto_version < 1202)
- this->WriteData(wide_newline);
- else
- this->WriteData(newline);
+ return true; // Passthru
}
diff --git a/src/modules/m_spanningtree/delline.cpp b/src/modules/m_spanningtree/delline.cpp
index 540ca5079..c76af2fb7 100644
--- a/src/modules/m_spanningtree/delline.cpp
+++ b/src/modules/m_spanningtree/delline.cpp
@@ -20,38 +20,18 @@
#include "inspircd.h"
#include "xline.h"
-#include "treesocket.h"
-#include "treeserver.h"
-#include "utils.h"
+#include "commands.h"
-/* $ModDep: m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h */
-
-
-bool TreeSocket::DelLine(const std::string &prefix, parameterlist &params)
+CmdResult CommandDelLine::Handle(User* user, std::vector<std::string>& params)
{
- if (params.size() < 2)
- return true;
-
- std::string setter = "<unknown>";
-
- User* user = ServerInstance->FindNick(prefix);
- if (user)
- setter = user->nick;
- else
- {
- TreeServer* t = Utils->FindServer(prefix);
- if (t)
- setter = t->GetName();
- }
-
+ const std::string& setter = user->nick;
/* NOTE: No check needed on 'user', this function safely handles NULL */
if (ServerInstance->XLines->DelLine(params[1].c_str(), params[0], user))
{
ServerInstance->SNO->WriteToSnoMask('X',"%s removed %s%s on %s", setter.c_str(),
params[0].c_str(), params[0].length() == 1 ? "-line" : "", params[1].c_str());
- Utils->DoOneToAllButSender(prefix,"DELLINE", params, prefix);
+ return CMD_SUCCESS;
}
- return true;
+ return CMD_FAILURE;
}
-
diff --git a/src/modules/m_spanningtree/encap.cpp b/src/modules/m_spanningtree/encap.cpp
index dabfc086b..95f8f4e4a 100644
--- a/src/modules/m_spanningtree/encap.cpp
+++ b/src/modules/m_spanningtree/encap.cpp
@@ -18,32 +18,28 @@
#include "inspircd.h"
-#include "xline.h"
-#include "treesocket.h"
-#include "treeserver.h"
-#include "utils.h"
+#include "commands.h"
/** ENCAP */
-void TreeSocket::Encap(User* who, parameterlist &params)
+CmdResult CommandEncap::Handle(User* user, std::vector<std::string>& params)
{
- if (params.size() > 1)
+ if (ServerInstance->Config->GetSID() == params[0] || InspIRCd::Match(ServerInstance->Config->ServerName, params[0]))
{
- if (ServerInstance->Config->GetSID() == params[0] || InspIRCd::Match(ServerInstance->Config->ServerName, params[0]))
- {
- parameterlist plist(params.begin() + 2, params.end());
- ServerInstance->Parser->CallHandler(params[1], plist, who);
- // discard return value, ENCAP shall succeed even if the command does not exist
- }
-
- params[params.size() - 1] = ":" + params[params.size() - 1];
+ parameterlist plist(params.begin() + 2, params.end());
+ Command* cmd = NULL;
+ ServerInstance->Parser.CallHandler(params[1], plist, user, &cmd);
+ // Discard return value, ENCAP shall succeed even if the command does not exist
- if (params[0].find_first_of("*?") != std::string::npos)
- {
- Utils->DoOneToAllButSender(who->uuid, "ENCAP", params, who->server);
- }
- else
- Utils->DoOneToOne(who->uuid, "ENCAP", params, params[0]);
+ if ((cmd) && (cmd->force_manual_route))
+ return CMD_FAILURE;
}
+ return CMD_SUCCESS;
}
+RouteDescriptor CommandEncap::GetRouting(User* user, const std::vector<std::string>& params)
+{
+ if (params[0].find_first_of("*?") != std::string::npos)
+ return ROUTE_BROADCAST;
+ return ROUTE_UNICAST(params[0]);
+}
diff --git a/src/modules/m_spanningtree/fjoin.cpp b/src/modules/m_spanningtree/fjoin.cpp
index c8cd768aa..d5b80fcb1 100644
--- a/src/modules/m_spanningtree/fjoin.cpp
+++ b/src/modules/m_spanningtree/fjoin.cpp
@@ -26,10 +26,9 @@
#include "treesocket.h"
/** FJOIN, almost identical to TS6 SJOIN, except for nicklist handling. */
-CmdResult CommandFJoin::Handle(const std::vector<std::string>& params, User *srcuser)
+CmdResult CommandFJoin::Handle(User* srcuser, std::vector<std::string>& params)
{
- SpanningTreeUtilities* Utils = ((ModuleSpanningTree*)(Module*)creator)->Utils;
- /* 1.1 FJOIN works as follows:
+ /* 1.1+ FJOIN works as follows:
*
* Each FJOIN is sent along with a timestamp, and the side with the lowest
* timestamp 'wins'. From this point on we will refer to this side as the
@@ -54,72 +53,66 @@ CmdResult CommandFJoin::Handle(const std::vector<std::string>& params, User *src
* The winning side on the other hand will ignore all user modes from the
* losing side, so only its own modes get applied. Life is simple for those
* who succeed at internets. :-)
+ *
+ * Syntax:
+ * :<sid> FJOIN <chan> <TS> <modes> :[<member> [<member> ...]]
+ * The last parameter is a list consisting of zero or more channel members
+ * (permanent channels may have zero users). Each entry on the list is in the
+ * following format:
+ * [[<modes>,]<uuid>[:<membid>]
+ * <modes> is a concatenation of the mode letters the user has on the channel
+ * (e.g.: "ov" if the user is opped and voiced). The order of the mode letters
+ * are not important but if a server ecounters an unknown mode letter, it will
+ * drop the link to avoid desync.
+ *
+ * InspIRCd 2.0 and older required a comma before the uuid even if the user
+ * had no prefix modes on the channel, InspIRCd 2.2 and later does not require
+ * a comma in this case anymore.
+ *
+ * <membid> is a positive integer representing the id of the membership.
+ * If not present (in FJOINs coming from pre-1205 servers), 0 is assumed.
+ *
*/
- irc::modestacker modestack(true); /* Modes to apply from the users in the user list */
- User* who = NULL; /* User we are currently checking */
- std::string channel = params[0]; /* Channel name, as a string */
- time_t TS = atoi(params[1].c_str()); /* Timestamp given to us for remote side */
- irc::tokenstream users((params.size() > 3) ? params[params.size() - 1] : ""); /* users from the user list */
- bool apply_other_sides_modes = true; /* True if we are accepting the other side's modes */
- Channel* chan = ServerInstance->FindChan(channel); /* The channel we're sending joins to */
- bool created = !chan; /* True if the channel doesnt exist here yet */
- std::string item; /* One item in the list of nicks */
+ time_t TS = ServerCommand::ExtractTS(params[1]);
- TreeServer* src_server = Utils->FindServer(srcuser->server);
- TreeSocket* src_socket = src_server->GetRoute()->GetSocket();
+ const std::string& channel = params[0];
+ Channel* chan = ServerInstance->FindChan(channel);
+ bool apply_other_sides_modes = true;
- if (!TS)
- {
- ServerInstance->Logs->Log("m_spanningtree",DEFAULT,"*** BUG? *** TS of 0 sent to FJOIN. Are some services authors smoking craq, or is it 1970 again?. Dropped.");
- ServerInstance->SNO->WriteToSnoMask('d', "WARNING: The server %s is sending FJOIN with a TS of zero. Total craq. Command was dropped.", srcuser->server.c_str());
- return CMD_INVALID;
- }
-
- if (created)
+ if (!chan)
{
chan = new Channel(channel, TS);
- ServerInstance->SNO->WriteToSnoMask('d', "Creation FJOIN received for %s, timestamp: %lu", chan->name.c_str(), (unsigned long)TS);
}
else
{
time_t ourTS = chan->age;
-
if (TS != ourTS)
+ {
ServerInstance->SNO->WriteToSnoMask('d', "Merge FJOIN received for %s, ourTS: %lu, TS: %lu, difference: %lu",
chan->name.c_str(), (unsigned long)ourTS, (unsigned long)TS, (unsigned long)(ourTS - TS));
- /* If our TS is less than theirs, we dont accept their modes */
- if (ourTS < TS)
- {
- ServerInstance->SNO->WriteToSnoMask('d', "NOT Applying modes from other side");
- apply_other_sides_modes = false;
- }
- else if (ourTS > TS)
- {
- /* Our TS greater than theirs, clear all our modes from the channel, accept theirs. */
- ServerInstance->SNO->WriteToSnoMask('d', "Removing our modes, accepting remote");
- parameterlist param_list;
- if (Utils->AnnounceTSChange)
- chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :TS for %s changed from %lu to %lu", chan->name.c_str(), channel.c_str(), (unsigned long) ourTS, (unsigned long) TS);
- // while the name is equal in case-insensitive compare, it might differ in case; use the remote version
- chan->name = channel;
- chan->age = TS;
- chan->ClearInvites();
- param_list.push_back(channel);
- this->RemoveStatus(ServerInstance->FakeClient, param_list);
-
- // XXX: If the channel does not exist in the chan hash at this point, create it so the remote modes can be applied on it.
- // This happens to 0-user permanent channels on the losing side, because those are removed (from the chan hash, then
- // deleted later) as soon as the permchan mode is removed from them.
- if (ServerInstance->FindChan(channel) == NULL)
+ /* If our TS is less than theirs, we dont accept their modes */
+ if (ourTS < TS)
+ {
+ apply_other_sides_modes = false;
+ }
+ else if (ourTS > TS)
{
- chan = new Channel(channel, TS);
+ // Our TS is greater than theirs, remove all modes, extensions, etc. from the channel
+ LowerTS(chan, TS, channel);
+
+ // XXX: If the channel does not exist in the chan hash at this point, create it so the remote modes can be applied on it.
+ // This happens to 0-user permanent channels on the losing side, because those are removed (from the chan hash, then
+ // deleted later) as soon as the permchan mode is removed from them.
+ if (ServerInstance->FindChan(channel) == NULL)
+ {
+ chan = new Channel(channel, TS);
+ }
}
}
- // The silent case here is ourTS == TS, we don't need to remove modes here, just to merge them later on.
}
- /* First up, apply their modes if they won the TS war */
+ /* First up, apply their channel modes if they won the TS war */
if (apply_other_sides_modes)
{
// Need to use a modestacker here due to maxmodes
@@ -149,109 +142,167 @@ CmdResult CommandFJoin::Handle(const std::vector<std::string>& params, User *src
while (stack.GetStackedLine(modelist))
{
- ServerInstance->Modes->Process(modelist, srcuser, true);
+ ServerInstance->Modes->Process(modelist, srcuser, ModeParser::MODE_LOCALONLY | ModeParser::MODE_MERGE);
modelist.erase(modelist.begin() + 1, modelist.end());
}
-
- ServerInstance->Modes->Process(modelist, srcuser, true);
}
- /* Now, process every 'modes,nick' pair */
+ irc::modestacker modestack(true);
+ TreeServer* const sourceserver = TreeServer::Get(srcuser);
+
+ /* Now, process every 'modes,uuid' pair */
+ irc::tokenstream users(params.back());
+ std::string item;
+ irc::modestacker* modestackptr = (apply_other_sides_modes ? &modestack : NULL);
while (users.GetToken(item))
{
- const char* usr = item.c_str();
- if (usr && *usr)
- {
- const char* unparsedmodes = usr;
- std::string modes;
+ ProcessModeUUIDPair(item, sourceserver, chan, modestackptr);
+ }
+ /* Flush mode stacker if we lost the FJOIN or had equal TS */
+ if (apply_other_sides_modes)
+ CommandFJoin::ApplyModeStack(srcuser, chan, modestack);
- /* Iterate through all modes for this user and check they are valid. */
- while ((*unparsedmodes) && (*unparsedmodes != ','))
- {
- ModeHandler *mh = ServerInstance->Modes->FindMode(*unparsedmodes, MODETYPE_CHANNEL);
- if (!mh)
- {
- ServerInstance->Logs->Log("m_spanningtree", SPARSE, "Unrecognised mode %c, dropping link", *unparsedmodes);
- return CMD_INVALID;
- }
+ return CMD_SUCCESS;
+}
- modes += *unparsedmodes;
- usr++;
- unparsedmodes++;
- }
+void CommandFJoin::ProcessModeUUIDPair(const std::string& item, TreeServer* sourceserver, Channel* chan, irc::modestacker* modestack)
+{
+ std::string::size_type comma = item.find(',');
- /* Advance past the comma, to the nick */
- usr++;
+ // Comma not required anymore if the user has no modes
+ const std::string::size_type ubegin = (comma == std::string::npos ? 0 : comma+1);
+ std::string uuid(item, ubegin, UIDGenerator::UUID_LENGTH);
+ User* who = ServerInstance->FindUUID(uuid);
+ if (!who)
+ {
+ // Probably KILLed, ignore
+ return;
+ }
- /* Check the user actually exists */
- who = ServerInstance->FindUUID(usr);
- if (who)
- {
- /* Check that the user's 'direction' is correct */
- TreeServer* route_back_again = Utils->BestRouteTo(who->server);
- if ((!route_back_again) || (route_back_again->GetSocket() != src_socket))
- continue;
+ TreeSocket* src_socket = sourceserver->GetSocket();
+ /* Check that the user's 'direction' is correct */
+ TreeServer* route_back_again = TreeServer::Get(who);
+ if (route_back_again->GetSocket() != src_socket)
+ {
+ return;
+ }
- /* Add any modes this user had to the mode stack */
- for (std::string::iterator x = modes.begin(); x != modes.end(); ++x)
- modestack.Push(*x, who->nick);
+ /* Check if the user received at least one mode */
+ if ((modestack) && (comma > 0) && (comma != std::string::npos))
+ {
+ /* Iterate through the modes and see if they are valid here, if so, apply */
+ std::string::const_iterator commait = item.begin()+comma;
+ for (std::string::const_iterator i = item.begin(); i != commait; ++i)
+ {
+ if (!ServerInstance->Modes->FindMode(*i, MODETYPE_CHANNEL))
+ throw ProtocolException("Unrecognised mode '" + std::string(1, *i) + "'");
- Channel::JoinUser(who, channel.c_str(), true, "", src_server->bursting, TS);
- }
- else
- {
- ServerInstance->Logs->Log("m_spanningtree",SPARSE, "Ignored nonexistant user %s in fjoin to %s (probably quit?)", usr, channel.c_str());
- continue;
- }
+ /* Add any modes this user had to the mode stack */
+ modestack->Push(*i, who->nick);
}
}
- /* Flush mode stacker if we lost the FJOIN or had equal TS */
- if (apply_other_sides_modes)
+ Membership* memb = chan->ForceJoin(who, NULL, sourceserver->bursting);
+ if (!memb)
+ return;
+
+ // Assign the id to the new Membership
+ Membership::Id membid = 0;
+ const std::string::size_type colon = item.rfind(':');
+ if (colon != std::string::npos)
+ membid = Membership::IdFromString(item.substr(colon+1));
+ memb->id = membid;
+}
+
+void CommandFJoin::RemoveStatus(Channel* c)
+{
+ irc::modestacker stack(false);
+
+ const ModeParser::ModeHandlerMap& mhs = ServerInstance->Modes->GetModes(MODETYPE_CHANNEL);
+ for (ModeParser::ModeHandlerMap::const_iterator i = mhs.begin(); i != mhs.end(); ++i)
{
- parameterlist stackresult;
- stackresult.push_back(channel);
+ ModeHandler* mh = i->second;
- while (modestack.GetStackedLine(stackresult))
- {
- ServerInstance->SendMode(stackresult, srcuser);
- stackresult.erase(stackresult.begin() + 1, stackresult.end());
- }
+ /* Passing a pointer to a modestacker here causes the mode to be put onto the mode stack,
+ * rather than applied immediately. Module unloads require this to be done immediately,
+ * for this function we require tidyness instead. Fixes bug #493
+ */
+ mh->RemoveMode(c, stack);
}
- return CMD_SUCCESS;
+
+ ApplyModeStack(ServerInstance->FakeClient, c, stack);
}
-void CommandFJoin::RemoveStatus(User* srcuser, parameterlist &params)
+void CommandFJoin::ApplyModeStack(User* srcuser, Channel* c, irc::modestacker& stack)
{
- if (params.size() < 1)
- return;
+ parameterlist stackresult;
+ stackresult.push_back(c->name);
- Channel* c = ServerInstance->FindChan(params[0]);
-
- if (c)
+ while (stack.GetStackedLine(stackresult))
{
- irc::modestacker stack(false);
- parameterlist stackresult;
- stackresult.push_back(c->name);
+ ServerInstance->Modes->Process(stackresult, srcuser, ModeParser::MODE_LOCALONLY);
+ stackresult.erase(stackresult.begin() + 1, stackresult.end());
+ }
+}
- for (char modeletter = 'A'; modeletter <= 'z'; ++modeletter)
- {
- ModeHandler* mh = ServerInstance->Modes->FindMode(modeletter, MODETYPE_CHANNEL);
-
- /* Passing a pointer to a modestacker here causes the mode to be put onto the mode stack,
- * rather than applied immediately. Module unloads require this to be done immediately,
- * for this function we require tidyness instead. Fixes bug #493
- */
- if (mh)
- mh->RemoveMode(c, &stack);
- }
+void CommandFJoin::LowerTS(Channel* chan, time_t TS, const std::string& newname)
+{
+ if (Utils->AnnounceTSChange)
+ chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :TS for %s changed from %lu to %lu", chan->name.c_str(), newname.c_str(), (unsigned long) chan->age, (unsigned long) TS);
- while (stack.GetStackedLine(stackresult))
- {
- ServerInstance->SendMode(stackresult, srcuser);
- stackresult.erase(stackresult.begin() + 1, stackresult.end());
- }
+ // While the name is equal in case-insensitive compare, it might differ in case; use the remote version
+ chan->name = newname;
+ chan->age = TS;
+
+ // Remove all pending invites
+ chan->ClearInvites();
+
+ // Clear all modes
+ CommandFJoin::RemoveStatus(chan);
+
+ // Unset all extensions
+ chan->FreeAllExtItems();
+
+ // Clear the topic, if it isn't empty then send a topic change message to local users
+ if (!chan->topic.empty())
+ {
+ chan->topic.clear();
+ chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "TOPIC %s :", chan->name.c_str());
}
+ chan->setby.clear();
+ chan->topicset = 0;
+}
+
+CommandFJoin::Builder::Builder(Channel* chan)
+ : CmdBuilder("FJOIN")
+{
+ push(chan->name).push_int(chan->age).push_raw(" +");
+ pos = str().size();
+ push_raw(chan->ChanModes(true)).push_raw(" :");
+}
+
+void CommandFJoin::Builder::add(Membership* memb)
+{
+ push_raw(memb->modes).push_raw(',').push_raw(memb->user->uuid);
+ push_raw(':').push_raw_int(memb->id);
+ push_raw(' ');
+}
+
+bool CommandFJoin::Builder::has_room(Membership* memb) const
+{
+ return ((str().size() + memb->modes.size() + UIDGenerator::UUID_LENGTH + 2 + membid_max_digits + 1) <= maxline);
}
+void CommandFJoin::Builder::clear()
+{
+ content.erase(pos);
+ push_raw(" :");
+}
+
+const std::string& CommandFJoin::Builder::finalize()
+{
+ if (*content.rbegin() == ' ')
+ content.erase(content.size()-1);
+ return str();
+}
diff --git a/src/modules/m_spanningtree/fmode.cpp b/src/modules/m_spanningtree/fmode.cpp
index c1e452db6..56757a8b7 100644
--- a/src/modules/m_spanningtree/fmode.cpp
+++ b/src/modules/m_spanningtree/fmode.cpp
@@ -21,73 +21,36 @@
#include "inspircd.h"
#include "commands.h"
-#include "treesocket.h"
-#include "treeserver.h"
-#include "utils.h"
-
/** FMODE command - server mode with timestamp checks */
-CmdResult CommandFMode::Handle(const std::vector<std::string>& params, User *who)
+CmdResult CommandFMode::Handle(User* who, std::vector<std::string>& params)
{
- std::string sourceserv = who->server;
-
- std::vector<std::string> modelist;
- time_t TS = 0;
- for (unsigned int q = 0; (q < params.size()) && (q < 64); q++)
- {
- if (q == 1)
- {
- /* The timestamp is in this position.
- * We don't want to pass that up to the
- * server->client protocol!
- */
- TS = atoi(params[q].c_str());
- }
- else
- {
- /* Everything else is fine to append to the modelist */
- modelist.push_back(params[q]);
- }
+ time_t TS = ServerCommand::ExtractTS(params[1]);
- }
- /* Extract the TS value of the object, either User or Channel */
- User* dst = ServerInstance->FindNick(params[0]);
- Channel* chan = NULL;
- time_t ourTS = 0;
+ Channel* const chan = ServerInstance->FindChan(params[0]);
+ if (!chan)
+ // Channel doesn't exist
+ return CMD_FAILURE;
- if (dst)
- {
- ourTS = dst->age;
- }
- else
- {
- chan = ServerInstance->FindChan(params[0]);
- if (chan)
- {
- ourTS = chan->age;
- }
- else
- /* Oops, channel doesnt exist! */
- return CMD_FAILURE;
- }
+ // Extract the TS of the channel in question
+ time_t ourTS = chan->age;
- if (!TS)
- {
- ServerInstance->Logs->Log("m_spanningtree",DEFAULT,"*** BUG? *** TS of 0 sent to FMODE. Are some services authors smoking craq, or is it 1970 again?. Dropped.");
- ServerInstance->SNO->WriteToSnoMask('d', "WARNING: The server %s is sending FMODE with a TS of zero. Total craq. Mode was dropped.", sourceserv.c_str());
- return CMD_INVALID;
- }
+ /* If the TS is greater than ours, we drop the mode and don't pass it anywhere.
+ */
+ if (TS > ourTS)
+ return CMD_FAILURE;
/* TS is equal or less: Merge the mode changes into ours and pass on.
*/
- if (TS <= ourTS)
- {
- bool merge = (TS == ourTS) && IS_SERVER(who);
- ServerInstance->Modes->Process(modelist, who, merge);
- return CMD_SUCCESS;
- }
- /* If the TS is greater than ours, we drop the mode and dont pass it anywhere.
- */
- return CMD_FAILURE;
-}
+ std::vector<std::string> modelist;
+ modelist.reserve(params.size()-1);
+ /* Insert everything into modelist except the TS (params[1]) */
+ modelist.push_back(params[0]);
+ modelist.insert(modelist.end(), params.begin()+2, params.end());
+ ModeParser::ModeProcessFlag flags = ModeParser::MODE_LOCALONLY;
+ if ((TS == ourTS) && IS_SERVER(who))
+ flags |= ModeParser::MODE_MERGE;
+ ServerInstance->Modes->Process(modelist, who, flags);
+ return CMD_SUCCESS;
+}
diff --git a/src/modules/m_spanningtree/ftopic.cpp b/src/modules/m_spanningtree/ftopic.cpp
index d559c6ae5..3c76c928a 100644
--- a/src/modules/m_spanningtree/ftopic.cpp
+++ b/src/modules/m_spanningtree/ftopic.cpp
@@ -21,31 +21,81 @@
#include "inspircd.h"
#include "commands.h"
-#include "treesocket.h"
-#include "treeserver.h"
-#include "utils.h"
-
/** FTOPIC command */
-CmdResult CommandFTopic::Handle(const std::vector<std::string>& params, User *user)
+CmdResult CommandFTopic::Handle(User* user, std::vector<std::string>& params)
{
- time_t ts = atoi(params[1].c_str());
Channel* c = ServerInstance->FindChan(params[0]);
- if (c)
+ if (!c)
+ return CMD_FAILURE;
+
+ if (c->age < ServerCommand::ExtractTS(params[1]))
+ // Our channel TS is older, nothing to do
+ return CMD_FAILURE;
+
+ // Channel::topicset is initialized to 0 on channel creation, so their ts will always win if we never had a topic
+ time_t ts = ServerCommand::ExtractTS(params[2]);
+ if (ts < c->topicset)
+ return CMD_FAILURE;
+
+ // The topic text is always the last parameter
+ const std::string& newtopic = params.back();
+
+ // If there is a setter in the message use that, otherwise use the message source
+ const std::string& setter = ((params.size() > 4) ? params[3] : (ServerInstance->Config->FullHostInTopic ? user->GetFullHost() : user->nick));
+
+ /*
+ * If the topics were updated at the exact same second, accept
+ * the remote only when it's "bigger" than ours as defined by
+ * string comparision, so non-empty topics always overridde
+ * empty topics if their timestamps are equal
+ *
+ * Similarly, if the topic texts are equal too, keep one topic
+ * setter and discard the other
+ */
+ if (ts == c->topicset)
+ {
+ // Discard if their topic text is "smaller"
+ if (c->topic > newtopic)
+ return CMD_FAILURE;
+
+ // If the texts are equal in addition to the timestamps, decide which setter to keep
+ if ((c->topic == newtopic) && (c->setby >= setter))
+ return CMD_FAILURE;
+ }
+
+ if (c->topic != newtopic)
{
- if ((ts >= c->topicset) || (c->topic.empty()))
- {
- if (c->topic != params[3])
- {
- // Update topic only when it differs from current topic
- c->topic.assign(params[3], 0, ServerInstance->Config->Limits.MaxTopic);
- c->WriteChannel(user, "TOPIC %s :%s", c->name.c_str(), c->topic.c_str());
- }
-
- // Always update setter and settime.
- c->setby.assign(params[2], 0, 127);
- c->topicset = ts;
- }
+ // Update topic only when it differs from current topic
+ c->topic.assign(newtopic, 0, ServerInstance->Config->Limits.MaxTopic);
+ c->WriteChannel(user, "TOPIC %s :%s", c->name.c_str(), c->topic.c_str());
}
+
+ // Update setter and settime
+ c->setby.assign(setter, 0, 128);
+ c->topicset = ts;
+
+ FOREACH_MOD(OnPostTopicChange, (user, c, c->topic));
+
return CMD_SUCCESS;
}
+// Used when bursting and in reply to RESYNC, contains topic setter as the 4th parameter
+CommandFTopic::Builder::Builder(Channel* chan)
+ : CmdBuilder("FTOPIC")
+{
+ push(chan->name);
+ push_int(chan->age);
+ push_int(chan->topicset);
+ push(chan->setby);
+ push_last(chan->topic);
+}
+
+// Used when changing the topic, the setter is the message source
+CommandFTopic::Builder::Builder(User* user, Channel* chan)
+ : CmdBuilder(user, "FTOPIC")
+{
+ push(chan->name);
+ push_int(chan->age);
+ push_int(chan->topicset);
+ push_last(chan->topic);
+}
diff --git a/src/modules/m_spanningtree/hmac.cpp b/src/modules/m_spanningtree/hmac.cpp
index d990e1fbf..2001d560d 100644
--- a/src/modules/m_spanningtree/hmac.cpp
+++ b/src/modules/m_spanningtree/hmac.cpp
@@ -19,18 +19,12 @@
#include "inspircd.h"
-#include "socket.h"
-#include "xline.h"
-#include "../hash.h"
-#include "../ssl.h"
-#include "socketengine.h"
+#include "modules/hash.h"
+#include "modules/ssl.h"
#include "main.h"
-#include "utils.h"
-#include "treeserver.h"
#include "link.h"
#include "treesocket.h"
-#include "resolvers.h"
const std::string& TreeSocket::GetOurChallenge()
{
@@ -57,44 +51,15 @@ std::string TreeSocket::MakePass(const std::string &password, const std::string
/* This is a simple (maybe a bit hacky?) HMAC algorithm, thanks to jilles for
* suggesting the use of HMAC to secure the password against various attacks.
*
- * Note: If m_sha256.so is not loaded, we MUST fall back to plaintext with no
+ * Note: If an sha256 provider is not available, we MUST fall back to plaintext with no
* HMAC challenge/response.
*/
HashProvider* sha256 = ServerInstance->Modules->FindDataService<HashProvider>("hash/sha256");
- if (Utils->ChallengeResponse && sha256 && !challenge.empty())
- {
- if (proto_version < 1202)
- {
- /* This is how HMAC is done in InspIRCd 1.2:
- *
- * sha256( (pass xor 0x5c) + sha256((pass xor 0x36) + m) )
- *
- * 5c and 36 were chosen as part of the HMAC standard, because they
- * flip the bits in a way likely to strengthen the function.
- */
- std::string hmac1, hmac2;
-
- for (size_t n = 0; n < password.length(); n++)
- {
- hmac1.push_back(static_cast<char>(password[n] ^ 0x5C));
- hmac2.push_back(static_cast<char>(password[n] ^ 0x36));
- }
-
- hmac2.append(challenge);
- hmac2 = sha256->hexsum(hmac2);
-
- std::string hmac = hmac1 + hmac2;
- hmac = sha256->hexsum(hmac);
-
- return "HMAC-SHA256:"+ hmac;
- }
- else
- {
- return "AUTH:" + BinToBase64(sha256->hmac(password, challenge));
- }
- }
- else if (!challenge.empty() && !sha256)
- ServerInstance->Logs->Log("m_spanningtree",DEFAULT,"Not authenticating to server using SHA256/HMAC because we don't have m_sha256 loaded!");
+ if (sha256 && !challenge.empty())
+ return "AUTH:" + BinToBase64(sha256->hmac(password, challenge));
+
+ if (!challenge.empty() && !sha256)
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Not authenticating to server using SHA256/HMAC because we don't have an SHA256 provider (e.g. m_sha256) loaded!");
return password;
}
@@ -104,13 +69,16 @@ bool TreeSocket::ComparePass(const Link& link, const std::string &theirs)
capab->auth_fingerprint = !link.Fingerprint.empty();
capab->auth_challenge = !capab->ourchallenge.empty() && !capab->theirchallenge.empty();
- std::string fp;
- if (GetIOHook())
+ std::string fp = SSLClientCert::GetFingerprint(this);
+ if (capab->auth_fingerprint)
{
- SocketCertificateRequest req(this, Utils->Creator);
- if (req.cert)
+ /* Require fingerprint to exist and match */
+ if (link.Fingerprint != fp)
{
- fp = req.cert->GetFingerprint();
+ ServerInstance->SNO->WriteToSnoMask('l',"Invalid SSL certificate fingerprint on link %s: need \"%s\" got \"%s\"",
+ link.Name.c_str(), link.Fingerprint.c_str(), fp.c_str());
+ SendError("Invalid SSL certificate fingerprint " + fp + " - expected " + link.Fingerprint);
+ return false;
}
}
@@ -118,32 +86,24 @@ bool TreeSocket::ComparePass(const Link& link, const std::string &theirs)
{
std::string our_hmac = MakePass(link.RecvPass, capab->ourchallenge);
- /* Straight string compare of hashes */
- if (our_hmac != theirs)
+ // Use the timing-safe compare function to compare the hashes
+ if (!InspIRCd::TimingSafeCompare(our_hmac, theirs))
return false;
}
else
{
- /* Straight string compare of plaintext */
- if (link.RecvPass != theirs)
+ // Use the timing-safe compare function to compare the passwords
+ if (!InspIRCd::TimingSafeCompare(link.RecvPass, theirs))
return false;
}
- if (capab->auth_fingerprint)
+ // Tell opers to set up fingerprint verification if it's not already set up and the SSL mod gave us a fingerprint
+ // this time
+ if ((!capab->auth_fingerprint) && (!fp.empty()))
{
- /* Require fingerprint to exist and match */
- if (link.Fingerprint != fp)
- {
- ServerInstance->SNO->WriteToSnoMask('l',"Invalid SSL fingerprint on link %s: need \"%s\" got \"%s\"",
- link.Name.c_str(), link.Fingerprint.c_str(), fp.c_str());
- SendError("Provided invalid SSL fingerprint " + fp + " - expected " + link.Fingerprint);
- return false;
- }
- }
- else if (!fp.empty())
- {
- ServerInstance->SNO->WriteToSnoMask('l', "SSL fingerprint for link %s is \"%s\". "
+ ServerInstance->SNO->WriteToSnoMask('l', "SSL certificate fingerprint for link %s is \"%s\". "
"You can improve security by specifying this in <link:fingerprint>.", link.Name.c_str(), fp.c_str());
}
+
return true;
}
diff --git a/src/modules/m_spanningtree/idle.cpp b/src/modules/m_spanningtree/idle.cpp
index 0ea06a3cc..06af4d0fd 100644
--- a/src/modules/m_spanningtree/idle.cpp
+++ b/src/modules/m_spanningtree/idle.cpp
@@ -18,67 +18,53 @@
#include "inspircd.h"
-#include "socket.h"
-#include "xline.h"
-#include "socketengine.h"
-
-#include "main.h"
#include "utils.h"
-#include "treeserver.h"
-#include "treesocket.h"
+#include "commands.h"
-bool TreeSocket::Whois(const std::string &prefix, parameterlist &params)
+CmdResult CommandIdle::HandleRemote(RemoteUser* issuer, std::vector<std::string>& params)
{
- if (params.size() < 1)
- return true;
- User* u = ServerInstance->FindNick(prefix);
- if (u)
+ /**
+ * There are two forms of IDLE: request and reply. Requests have one parameter,
+ * replies have more than one.
+ *
+ * If this is a request, 'issuer' did a /whois and its server wants to learn the
+ * idle time of the user in params[0].
+ *
+ * If this is a reply, params[0] is the user who did the whois and params.back() is
+ * the number of seconds 'issuer' has been idle.
+ */
+
+ User* target = ServerInstance->FindUUID(params[0]);
+ if ((!target) || (IS_SERVER(target) || (target->registered != REG_ALL)))
+ return CMD_FAILURE;
+
+ LocalUser* localtarget = IS_LOCAL(target);
+ if (!localtarget)
{
- // an incoming request
- if (params.size() == 1)
- {
- User* x = ServerInstance->FindNick(params[0]);
- if ((x) && (IS_LOCAL(x)))
- {
- long idle = abs((long)((x->idle_lastmsg) - ServerInstance->Time()));
- parameterlist par;
- par.push_back(prefix);
- par.push_back(ConvToStr(x->signon));
- par.push_back(ConvToStr(idle));
- // ours, we're done, pass it BACK
- Utils->DoOneToOne(params[0], "IDLE", par, u->server);
- }
- else
- {
- // not ours pass it on
- if (x)
- Utils->DoOneToOne(prefix, "IDLE", params, x->server);
- }
- }
- else if (params.size() == 3)
- {
- std::string who_did_the_whois = params[0];
- User* who_to_send_to = ServerInstance->FindNick(who_did_the_whois);
- if ((who_to_send_to) && (IS_LOCAL(who_to_send_to)) && (who_to_send_to->registered == REG_ALL))
- {
- // an incoming reply to a whois we sent out
- std::string nick_whoised = prefix;
- unsigned long signon = atoi(params[1].c_str());
- unsigned long idle = atoi(params[2].c_str());
- if ((who_to_send_to) && (IS_LOCAL(who_to_send_to)))
- {
- ServerInstance->DoWhois(who_to_send_to, u, signon, idle, nick_whoised.c_str());
- }
- }
- else
- {
- // not ours, pass it on
- if (who_to_send_to)
- Utils->DoOneToOne(prefix, "IDLE", params, who_to_send_to->server);
- }
- }
+ // Forward to target's server
+ return CMD_SUCCESS;
}
- return true;
-}
+ if (params.size() >= 2)
+ {
+ ServerInstance->Parser.CallHandler("WHOIS", params, issuer);
+ }
+ else
+ {
+ // A server is asking us the idle time of our user
+ unsigned int idle;
+ if (localtarget->idle_lastmsg >= ServerInstance->Time())
+ // Possible case when our clock ticked backwards
+ idle = 0;
+ else
+ idle = ((unsigned int) (ServerInstance->Time() - localtarget->idle_lastmsg));
+
+ CmdBuilder reply(params[0], "IDLE");
+ reply.push_back(issuer->uuid);
+ reply.push_back(ConvToStr(target->signon));
+ reply.push_back(ConvToStr(idle));
+ reply.Unicast(issuer);
+ }
+ return CMD_SUCCESS;
+}
diff --git a/src/modules/m_spanningtree/ijoin.cpp b/src/modules/m_spanningtree/ijoin.cpp
new file mode 100644
index 000000000..78e05db93
--- /dev/null
+++ b/src/modules/m_spanningtree/ijoin.cpp
@@ -0,0 +1,77 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2012-2013 Attila Molnar <attilamolnar@hush.com>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "commands.h"
+#include "utils.h"
+#include "treeserver.h"
+#include "treesocket.h"
+
+CmdResult CommandIJoin::HandleRemote(RemoteUser* user, std::vector<std::string>& params)
+{
+ Channel* chan = ServerInstance->FindChan(params[0]);
+ if (!chan)
+ {
+ // Desync detected, recover
+ // Ignore the join and send RESYNC, this will result in the remote server sending all channel data to us
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Received IJOIN for non-existant channel: " + params[0]);
+
+ CmdBuilder("RESYNC").push(params[0]).Unicast(user);
+
+ return CMD_FAILURE;
+ }
+
+ bool apply_modes;
+ if (params.size() > 2)
+ {
+ time_t RemoteTS = ServerCommand::ExtractTS(params[2]);
+ if (RemoteTS < chan->age)
+ throw ProtocolException("Attempted to lower TS via IJOIN. LocalTS=" + ConvToStr(chan->age));
+ apply_modes = ((params.size() > 3) && (RemoteTS == chan->age));
+ }
+ else
+ apply_modes = false;
+
+ // Join the user and set the membership id to what they sent
+ Membership* memb = chan->ForceJoin(user, apply_modes ? &params[3] : NULL);
+ if (!memb)
+ return CMD_FAILURE;
+
+ memb->id = Membership::IdFromString(params[1]);
+ return CMD_SUCCESS;
+}
+
+CmdResult CommandResync::HandleServer(TreeServer* server, std::vector<std::string>& params)
+{
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Resyncing " + params[0]);
+ Channel* chan = ServerInstance->FindChan(params[0]);
+ if (!chan)
+ {
+ // This can happen for a number of reasons, safe to ignore
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Channel does not exist");
+ return CMD_FAILURE;
+ }
+
+ if (!server->IsLocal())
+ throw ProtocolException("RESYNC from a server that is not directly connected");
+
+ // Send all known information about the channel
+ server->GetSocket()->SyncChannel(chan);
+ return CMD_SUCCESS;
+}
diff --git a/src/modules/m_spanningtree/link.h b/src/modules/m_spanningtree/link.h
index 797f108d8..21213fb3e 100644
--- a/src/modules/m_spanningtree/link.h
+++ b/src/modules/m_spanningtree/link.h
@@ -18,8 +18,7 @@
*/
-#ifndef M_SPANNINGTREE_LINK_H
-#define M_SPANNINGTREE_LINK_H
+#pragma once
class Link : public refcountbase
{
@@ -31,7 +30,7 @@ class Link : public refcountbase
std::string SendPass;
std::string RecvPass;
std::string Fingerprint;
- std::string AllowMask;
+ std::vector<std::string> AllowMasks;
bool HiddenFromStats;
std::string Hook;
int Timeout;
@@ -51,5 +50,3 @@ class Autoconnect : public refcountbase
int position;
Autoconnect(ConfigTag* Tag) : tag(Tag) {}
};
-
-#endif
diff --git a/src/modules/m_spanningtree/main.cpp b/src/modules/m_spanningtree/main.cpp
index e7ff3789b..ee4c4bdd8 100644
--- a/src/modules/m_spanningtree/main.cpp
+++ b/src/modules/m_spanningtree/main.cpp
@@ -21,13 +21,11 @@
*/
-/* $ModDesc: Provides a spanning tree server link protocol */
-
#include "inspircd.h"
#include "socket.h"
#include "xline.h"
+#include "iohook.h"
-#include "cachetimer.h"
#include "resolvers.h"
#include "main.h"
#include "utils.h"
@@ -35,60 +33,67 @@
#include "link.h"
#include "treesocket.h"
#include "commands.h"
-#include "protocolinterface.h"
ModuleSpanningTree::ModuleSpanningTree()
- : KeepNickTS(false)
+ : rconnect(this), rsquit(this), map(this)
+ , commands(NULL)
+ , currmembid(0)
+ , DNS(this, "DNS")
+ , loopCall(false)
+ , SplitInProgress(false)
{
- Utils = new SpanningTreeUtilities(this);
- commands = new SpanningTreeCommands(this);
- RefreshTimer = NULL;
}
SpanningTreeCommands::SpanningTreeCommands(ModuleSpanningTree* module)
- : rconnect(module, module->Utils), rsquit(module, module->Utils),
- svsjoin(module), svspart(module), svsnick(module), metadata(module),
- uid(module), opertype(module), fjoin(module), fmode(module), ftopic(module),
- fhost(module), fident(module), fname(module)
+ : svsjoin(module), svspart(module), svsnick(module), metadata(module),
+ uid(module), opertype(module), fjoin(module), ijoin(module), resync(module),
+ fmode(module), ftopic(module), fhost(module), fident(module), fname(module),
+ away(module), addline(module), delline(module), encap(module), idle(module),
+ nick(module), ping(module), pong(module), push(module), save(module),
+ server(module), squit(module), snonotice(module),
+ burst(module), endburst(module), sinfo(module)
{
}
+namespace
+{
+ void SetLocalUsersServer(Server* newserver)
+ {
+ // Does not change the server of quitting users because those are not in the list
+
+ ServerInstance->FakeClient->server = newserver;
+ const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers();
+ for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i)
+ (*i)->server = newserver;
+ }
+
+ void ResetMembershipIds()
+ {
+ // Set all membership ids to 0
+ const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers();
+ for (UserManager::LocalList::iterator i = list.begin(); i != list.end(); ++i)
+ {
+ LocalUser* user = *i;
+ for (User::ChanList::iterator j = user->chans.begin(); j != user->chans.end(); ++j)
+ (*j)->id = 0;
+ }
+ }
+}
+
void ModuleSpanningTree::init()
{
- ServerInstance->Modules->AddService(commands->rconnect);
- ServerInstance->Modules->AddService(commands->rsquit);
- ServerInstance->Modules->AddService(commands->svsjoin);
- ServerInstance->Modules->AddService(commands->svspart);
- ServerInstance->Modules->AddService(commands->svsnick);
- ServerInstance->Modules->AddService(commands->metadata);
- ServerInstance->Modules->AddService(commands->uid);
- ServerInstance->Modules->AddService(commands->opertype);
- ServerInstance->Modules->AddService(commands->fjoin);
- ServerInstance->Modules->AddService(commands->fmode);
- ServerInstance->Modules->AddService(commands->ftopic);
- ServerInstance->Modules->AddService(commands->fhost);
- ServerInstance->Modules->AddService(commands->fident);
- ServerInstance->Modules->AddService(commands->fname);
- RefreshTimer = new CacheRefreshTimer(Utils);
- ServerInstance->Timers->AddTimer(RefreshTimer);
-
- Implementation eventlist[] =
- {
- I_OnPreCommand, I_OnGetServerDescription, I_OnUserInvite, I_OnPostTopicChange,
- I_OnWallops, I_OnUserNotice, I_OnUserMessage, I_OnBackgroundTimer, I_OnUserJoin,
- I_OnChangeHost, I_OnChangeName, I_OnChangeIdent, I_OnUserPart, I_OnUnloadModule,
- I_OnUserQuit, I_OnUserPostNick, I_OnUserKick, I_OnRemoteKill, I_OnRehash, I_OnPreRehash,
- I_OnOper, I_OnAddLine, I_OnDelLine, I_OnMode, I_OnLoadModule, I_OnStats,
- I_OnSetAway, I_OnPostCommand, I_OnUserConnect, I_OnAcceptConnection
- };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
-
- delete ServerInstance->PI;
- ServerInstance->PI = new SpanningTreeProtocolInterface(Utils);
- loopCall = false;
-
- // update our local user count
- Utils->TreeRoot->SetUserCount(ServerInstance->Users->local_users.size());
+ ServerInstance->SNO->EnableSnomask('l', "LINK");
+
+ ResetMembershipIds();
+
+ Utils = new SpanningTreeUtilities(this);
+ Utils->TreeRoot = new TreeServer;
+ commands = new SpanningTreeCommands(this);
+
+ ServerInstance->PI = &protocolinterface;
+
+ delete ServerInstance->FakeClient->server;
+ SetLocalUsersServer(Utils->TreeRoot);
}
void ModuleSpanningTree::ShowLinks(TreeServer* Current, User* user, int hops)
@@ -98,44 +103,40 @@ void ModuleSpanningTree::ShowLinks(TreeServer* Current, User* user, int hops)
{
Parent = Current->GetParent()->GetName();
}
- for (unsigned int q = 0; q < Current->ChildCount(); q++)
+
+ const TreeServer::ChildServers& children = Current->GetChildren();
+ for (TreeServer::ChildServers::const_iterator i = children.begin(); i != children.end(); ++i)
{
- if ((Current->GetChild(q)->Hidden) || ((Utils->HideULines) && (ServerInstance->ULine(Current->GetChild(q)->GetName()))))
+ TreeServer* server = *i;
+ if ((server->Hidden) || ((Utils->HideULines) && (server->IsULine())))
{
- if (IS_OPER(user))
+ if (user->IsOper())
{
- ShowLinks(Current->GetChild(q),user,hops+1);
+ ShowLinks(server, user, hops+1);
}
}
else
{
- ShowLinks(Current->GetChild(q),user,hops+1);
+ ShowLinks(server, user, hops+1);
}
}
/* Don't display the line if its a uline, hide ulines is on, and the user isnt an oper */
- if ((Utils->HideULines) && (ServerInstance->ULine(Current->GetName())) && (!IS_OPER(user)))
+ if ((Utils->HideULines) && (Current->IsULine()) && (!user->IsOper()))
return;
/* Or if the server is hidden and they're not an oper */
- else if ((Current->Hidden) && (!IS_OPER(user)))
+ else if ((Current->Hidden) && (!user->IsOper()))
return;
- std::string servername = Current->GetName();
- user->WriteNumeric(364, "%s %s %s :%d %s", user->nick.c_str(), servername.c_str(),
- (Utils->FlatLinks && (!IS_OPER(user))) ? ServerInstance->Config->ServerName.c_str() : Parent.c_str(),
- (Utils->FlatLinks && (!IS_OPER(user))) ? 0 : hops,
+ user->WriteNumeric(RPL_LINKS, "%s %s :%d %s", Current->GetName().c_str(),
+ (Utils->FlatLinks && (!user->IsOper())) ? ServerInstance->Config->ServerName.c_str() : Parent.c_str(),
+ (Utils->FlatLinks && (!user->IsOper())) ? 0 : hops,
Current->GetDesc().c_str());
}
-int ModuleSpanningTree::CountServs()
-{
- return Utils->serverlist.size();
-}
-
void ModuleSpanningTree::HandleLinks(const std::vector<std::string>& parameters, User* user)
{
ShowLinks(Utils->TreeRoot,user,0);
- user->WriteNumeric(365, "%s * :End of /LINKS list.",user->nick.c_str());
- return;
+ user->WriteNumeric(RPL_ENDOFLINKS, "* :End of /LINKS list.");
}
std::string ModuleSpanningTree::TimeToStr(time_t secs)
@@ -165,62 +166,53 @@ restart:
{
TreeServer *s = i->second;
- if (s->GetSocket() && s->GetSocket()->GetLinkState() == DYING)
+ // Skip myself
+ if (s->IsRoot())
+ continue;
+
+ if (s->GetSocket()->GetLinkState() == DYING)
{
s->GetSocket()->Close();
goto restart;
}
- // Fix for bug #792, do not ping servers that are not connected yet!
- // Remote servers have Socket == NULL and local connected servers have
- // Socket->LinkState == CONNECTED
- if (s->GetSocket() && s->GetSocket()->GetLinkState() != CONNECTED)
+ // Do not ping servers that are not fully connected yet!
+ // Servers which are connected to us have IsLocal() == true and if they're fully connected
+ // then Socket->LinkState == CONNECTED. Servers that are linked to another server are always fully connected.
+ if (s->IsLocal() && s->GetSocket()->GetLinkState() != CONNECTED)
continue;
// Now do PING checks on all servers
- TreeServer *mts = Utils->BestRouteTo(s->GetID());
-
- if (mts)
+ // Only ping if this server needs one
+ if (curtime >= s->NextPingTime())
{
- // Only ping if this server needs one
- if (curtime >= s->NextPingTime())
+ // And if they answered the last
+ if (s->AnsweredLastPing())
{
- // And if they answered the last
- if (s->AnsweredLastPing())
- {
- // They did, send a ping to them
- s->SetNextPingTime(curtime + Utils->PingFreq);
- TreeSocket *tsock = mts->GetSocket();
-
- // ... if we can find a proper route to them
- if (tsock)
- {
- tsock->WriteLine(":" + ServerInstance->Config->GetSID() + " PING " +
- ServerInstance->Config->GetSID() + " " + s->GetID());
- s->LastPingMsec = ts;
- }
- }
- else
+ // They did, send a ping to them
+ s->SetNextPingTime(curtime + Utils->PingFreq);
+ s->GetSocket()->WriteLine(CmdBuilder("PING").push(s->GetID()));
+ s->LastPingMsec = ts;
+ }
+ else
+ {
+ // They didn't answer the last ping, if they are locally connected, get rid of them.
+ if (s->IsLocal())
{
- // They didn't answer the last ping, if they are locally connected, get rid of them.
- TreeSocket *sock = s->GetSocket();
- if (sock)
- {
- sock->SendError("Ping timeout");
- sock->Close();
- goto restart;
- }
+ TreeSocket* sock = s->GetSocket();
+ sock->SendError("Ping timeout");
+ sock->Close();
+ goto restart;
}
}
+ }
- // If warn on ping enabled and not warned and the difference is sufficient and they didn't answer the last ping...
- if ((Utils->PingWarnTime) && (!s->Warned) && (curtime >= s->NextPingTime() - (Utils->PingFreq - Utils->PingWarnTime)) && (!s->AnsweredLastPing()))
- {
- /* The server hasnt responded, send a warning to opers */
- std::string servername = s->GetName();
- ServerInstance->SNO->WriteToSnoMask('l',"Server \002%s\002 has not responded to PING for %d seconds, high latency.", servername.c_str(), Utils->PingWarnTime);
- s->Warned = true;
- }
+ // If warn on ping enabled and not warned and the difference is sufficient and they didn't answer the last ping...
+ if ((Utils->PingWarnTime) && (!s->Warned) && (curtime >= s->NextPingTime() - (Utils->PingFreq - Utils->PingWarnTime)) && (!s->AnsweredLastPing()))
+ {
+ /* The server hasnt responded, send a warning to opers */
+ ServerInstance->SNO->WriteToSnoMask('l',"Server \002%s\002 has not responded to PING for %d seconds, high latency.", s->GetName().c_str(), Utils->PingWarnTime);
+ s->Warned = true;
}
}
}
@@ -272,7 +264,7 @@ void ModuleSpanningTree::ConnectServer(Link* x, Autoconnect* y)
return;
}
- QueryType start_type = DNS_QUERY_AAAA;
+ DNS::QueryType start_type = DNS::QUERY_AAAA;
if (strchr(x->IPAddr.c_str(),':'))
{
in6_addr n;
@@ -290,7 +282,7 @@ void ModuleSpanningTree::ConnectServer(Link* x, Autoconnect* y)
if (ipvalid)
{
/* Gave a hook, but it wasnt one we know */
- TreeSocket* newsocket = new TreeSocket(Utils, x, y, x->IPAddr);
+ TreeSocket* newsocket = new TreeSocket(x, y, x->IPAddr);
if (newsocket->GetFd() > -1)
{
/* Handled automatically on success */
@@ -302,17 +294,21 @@ void ModuleSpanningTree::ConnectServer(Link* x, Autoconnect* y)
ServerInstance->GlobalCulls.AddItem(newsocket);
}
}
+ else if (!DNS)
+ {
+ ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: Hostname given and m_dns.so is not loaded, unable to resolve.", x->Name.c_str());
+ }
else
{
+ ServernameResolver* snr = new ServernameResolver(*DNS, x->IPAddr, x, start_type, y);
try
{
- bool cached = false;
- ServernameResolver* snr = new ServernameResolver(Utils, x->IPAddr, x, cached, start_type, y);
- ServerInstance->AddResolver(snr, cached);
+ DNS->Process(snr);
}
- catch (ModuleException& e)
+ catch (DNS::Exception& e)
{
- ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: %s.",x->Name.c_str(), e.GetReason());
+ delete snr;
+ ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: %s.",x->Name.c_str(), e.GetReason().c_str());
ConnectServer(y, false);
}
}
@@ -360,16 +356,23 @@ ModResult ModuleSpanningTree::HandleVersion(const std::vector<std::string>& para
TreeServer* found = Utils->FindServerMask(parameters[0]);
if (found)
{
- std::string Version = found->GetVersion();
- user->WriteNumeric(351, "%s :%s",user->nick.c_str(),Version.c_str());
if (found == Utils->TreeRoot)
{
- ServerInstance->Config->Send005(user);
+ // Pass to default VERSION handler.
+ return MOD_RES_PASSTHRU;
}
+
+ // If an oper wants to see the version then show the full version string instead of the normal,
+ // but only if it is non-empty.
+ // If it's empty it might be that the server is still syncing (full version hasn't arrived yet)
+ // or the server is a 2.0 server and does not send a full version.
+ bool showfull = ((user->IsOper()) && (!found->GetFullVersion().empty()));
+ const std::string& Version = (showfull ? found->GetFullVersion() : found->GetVersion());
+ user->WriteNumeric(RPL_VERSION, ":%s", Version.c_str());
}
else
{
- user->WriteNumeric(402, "%s %s :No such server",user->nick.c_str(),parameters[0].c_str());
+ user->WriteNumeric(ERR_NOSUCHSERVER, "%s :No such server", parameters[0].c_str());
}
return MOD_RES_DENY;
}
@@ -378,15 +381,11 @@ ModResult ModuleSpanningTree::HandleVersion(const std::vector<std::string>& para
*/
void ModuleSpanningTree::RemoteMessage(User* user, const char* format, ...)
{
- char text[MAXBUF];
- va_list argsPtr;
-
- va_start(argsPtr, format);
- vsnprintf(text, MAXBUF, format, argsPtr);
- va_end(argsPtr);
+ std::string text;
+ VAFORMAT(text, format, format);
if (IS_LOCAL(user))
- user->WriteServ("NOTICE %s :%s", user->nick.c_str(), text);
+ user->WriteNotice(text);
else
ServerInstance->PI->SendUserNotice(user, text);
}
@@ -413,8 +412,7 @@ ModResult ModuleSpanningTree::HandleConnect(const std::vector<std::string>& para
}
else
{
- std::string servername = CheckDupe->GetParent()->GetName();
- RemoteMessage(user, "*** CONNECT: Server \002%s\002 already exists on the network and is connected via \002%s\002", x->Name.c_str(), servername.c_str());
+ RemoteMessage(user, "*** CONNECT: Server \002%s\002 already exists on the network and is connected via \002%s\002", x->Name.c_str(), CheckDupe->GetParent()->GetName().c_str());
return MOD_RES_DENY;
}
}
@@ -423,24 +421,16 @@ ModResult ModuleSpanningTree::HandleConnect(const std::vector<std::string>& para
return MOD_RES_DENY;
}
-void ModuleSpanningTree::OnGetServerDescription(const std::string &servername,std::string &description)
-{
- TreeServer* s = Utils->FindServer(servername);
- if (s)
- {
- description = s->GetDesc();
- }
-}
-
void ModuleSpanningTree::OnUserInvite(User* source,User* dest,Channel* channel, time_t expiry)
{
if (IS_LOCAL(source))
{
- parameterlist params;
+ CmdBuilder params(source, "INVITE");
params.push_back(dest->uuid);
params.push_back(channel->name);
+ params.push_int(channel->age);
params.push_back(ConvToStr(expiry));
- Utils->DoOneToMany(source->uuid,"INVITE",params);
+ params.Broadcast();
}
}
@@ -450,123 +440,37 @@ void ModuleSpanningTree::OnPostTopicChange(User* user, Channel* chan, const std:
if (!IS_LOCAL(user))
return;
- parameterlist params;
- params.push_back(chan->name);
- params.push_back(":"+topic);
- Utils->DoOneToMany(user->uuid,"TOPIC",params);
-}
-
-void ModuleSpanningTree::OnWallops(User* user, const std::string &text)
-{
- if (IS_LOCAL(user))
- {
- parameterlist params;
- params.push_back(":"+text);
- Utils->DoOneToMany(user->uuid,"WALLOPS",params);
- }
-}
-
-void ModuleSpanningTree::OnUserNotice(User* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list)
-{
- /* Server origin */
- if (user == NULL)
- return;
-
- if (target_type == TYPE_USER)
- {
- User* d = (User*)dest;
- if (!IS_LOCAL(d) && IS_LOCAL(user))
- {
- parameterlist params;
- params.push_back(d->uuid);
- params.push_back(":"+text);
- Utils->DoOneToOne(user->uuid,"NOTICE",params,d->server);
- }
- }
- else if (target_type == TYPE_CHANNEL)
- {
- if (IS_LOCAL(user))
- {
- Channel *c = (Channel*)dest;
- if (c)
- {
- std::string cname = c->name;
- if (status)
- cname = status + cname;
- TreeServerList list;
- Utils->GetListOfServersForChannel(c,list,status,exempt_list);
- for (TreeServerList::iterator i = list.begin(); i != list.end(); i++)
- {
- TreeSocket* Sock = i->second->GetSocket();
- if (Sock)
- Sock->WriteLine(":"+std::string(user->uuid)+" NOTICE "+cname+" :"+text);
- }
- }
- }
- }
- else if (target_type == TYPE_SERVER)
- {
- if (IS_LOCAL(user))
- {
- char* target = (char*)dest;
- parameterlist par;
- par.push_back(target);
- par.push_back(":"+text);
- Utils->DoOneToMany(user->uuid,"NOTICE",par);
- }
- }
+ CommandFTopic::Builder(user, chan).Broadcast();
}
-void ModuleSpanningTree::OnUserMessage(User* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list)
+void ModuleSpanningTree::OnUserMessage(User* user, void* dest, int target_type, const std::string& text, char status, const CUList& exempt_list, MessageType msgtype)
{
- /* Server origin */
- if (user == NULL)
+ if (!IS_LOCAL(user))
return;
+ const char* message_type = (msgtype == MSG_PRIVMSG ? "PRIVMSG" : "NOTICE");
if (target_type == TYPE_USER)
{
- // route private messages which are targetted at clients only to the server
- // which needs to receive them
- User* d = (User*)dest;
- if (!IS_LOCAL(d) && (IS_LOCAL(user)))
+ User* d = (User*) dest;
+ if (!IS_LOCAL(d))
{
- parameterlist params;
+ CmdBuilder params(user, message_type);
params.push_back(d->uuid);
- params.push_back(":"+text);
- Utils->DoOneToOne(user->uuid,"PRIVMSG",params,d->server);
+ params.push_last(text);
+ params.Unicast(d);
}
}
else if (target_type == TYPE_CHANNEL)
{
- if (IS_LOCAL(user))
- {
- Channel *c = (Channel*)dest;
- if (c)
- {
- std::string cname = c->name;
- if (status)
- cname = status + cname;
- TreeServerList list;
- Utils->GetListOfServersForChannel(c,list,status,exempt_list);
- for (TreeServerList::iterator i = list.begin(); i != list.end(); i++)
- {
- TreeSocket* Sock = i->second->GetSocket();
- if (Sock)
- Sock->WriteLine(":"+std::string(user->uuid)+" PRIVMSG "+cname+" :"+text);
- }
- }
- }
+ Utils->SendChannelMessage(user->uuid, (Channel*)dest, text, status, exempt_list, message_type);
}
else if (target_type == TYPE_SERVER)
{
- if (IS_LOCAL(user))
- {
- char* target = (char*)dest;
- parameterlist par;
- par.push_back(target);
- par.push_back(":"+text);
- Utils->DoOneToMany(user->uuid,"PRIVMSG",par);
- }
+ char* target = (char*) dest;
+ CmdBuilder par(user, message_type);
+ par.push_back(target);
+ par.push_last(text);
+ par.Broadcast();
}
}
@@ -582,25 +486,10 @@ void ModuleSpanningTree::OnUserConnect(LocalUser* user)
if (user->quitting)
return;
- parameterlist params;
- params.push_back(user->uuid);
- params.push_back(ConvToStr(user->age));
- params.push_back(user->nick);
- params.push_back(user->host);
- params.push_back(user->dhost);
- params.push_back(user->ident);
- params.push_back(user->GetIPString());
- params.push_back(ConvToStr(user->signon));
- params.push_back("+"+std::string(user->FormatModes(true)));
- params.push_back(":"+user->fullname);
- Utils->DoOneToMany(ServerInstance->Config->GetSID(), "UID", params);
+ CommandUID::Builder(user).Broadcast();
- if (IS_OPER(user))
- {
- params.clear();
- params.push_back(user->oper->name);
- Utils->DoOneToMany(user->uuid,"OPERTYPE",params);
- }
+ if (user->IsOper())
+ CommandOpertype::Builder(user).Broadcast();
for(Extensible::ExtensibleStore::const_iterator i = user->GetExtList().begin(); i != user->GetExtList().end(); i++)
{
@@ -610,23 +499,36 @@ void ModuleSpanningTree::OnUserConnect(LocalUser* user)
ServerInstance->PI->SendMetaData(user, item->name, value);
}
- Utils->TreeRoot->SetUserCount(1); // increment by 1
+ Utils->TreeRoot->UserCount++;
}
-void ModuleSpanningTree::OnUserJoin(Membership* memb, bool sync, bool created, CUList& excepts)
+void ModuleSpanningTree::OnUserJoin(Membership* memb, bool sync, bool created_by_local, CUList& excepts)
{
// Only do this for local users
- if (IS_LOCAL(memb->user))
+ if (!IS_LOCAL(memb->user))
+ return;
+
+ // Assign the current membership id to the new Membership and increase it
+ memb->id = currmembid++;
+
+ if (created_by_local)
{
- parameterlist params;
- // set up their permissions and the channel TS with FJOIN.
- // All users are FJOINed now, because a module may specify
- // new joining permissions for the user.
+ CommandFJoin::Builder params(memb->chan);
+ params.add(memb);
+ params.finalize();
+ params.Broadcast();
+ }
+ else
+ {
+ CmdBuilder params(memb->user, "IJOIN");
params.push_back(memb->chan->name);
- params.push_back(ConvToStr(memb->chan->age));
- params.push_back(std::string("+") + memb->chan->ChanModes(true));
- params.push_back(memb->modes+","+memb->user->uuid);
- Utils->DoOneToMany(ServerInstance->Config->GetSID(),"FJOIN",params);
+ params.push_int(memb->id);
+ if (!memb->modes.empty())
+ {
+ params.push_back(ConvToStr(memb->chan->age));
+ params.push_back(memb->modes);
+ }
+ params.Broadcast();
}
}
@@ -635,9 +537,7 @@ void ModuleSpanningTree::OnChangeHost(User* user, const std::string &newhost)
if (user->registered != REG_ALL || !IS_LOCAL(user))
return;
- parameterlist params;
- params.push_back(newhost);
- Utils->DoOneToMany(user->uuid,"FHOST",params);
+ CmdBuilder(user, "FHOST").push(newhost).Broadcast();
}
void ModuleSpanningTree::OnChangeName(User* user, const std::string &gecos)
@@ -645,9 +545,7 @@ void ModuleSpanningTree::OnChangeName(User* user, const std::string &gecos)
if (user->registered != REG_ALL || !IS_LOCAL(user))
return;
- parameterlist params;
- params.push_back(":" + gecos);
- Utils->DoOneToMany(user->uuid,"FNAME",params);
+ CmdBuilder(user, "FNAME").push_last(gecos).Broadcast();
}
void ModuleSpanningTree::OnChangeIdent(User* user, const std::string &ident)
@@ -655,101 +553,79 @@ void ModuleSpanningTree::OnChangeIdent(User* user, const std::string &ident)
if ((user->registered != REG_ALL) || (!IS_LOCAL(user)))
return;
- parameterlist params;
- params.push_back(ident);
- Utils->DoOneToMany(user->uuid,"FIDENT",params);
+ CmdBuilder(user, "FIDENT").push(ident).Broadcast();
}
void ModuleSpanningTree::OnUserPart(Membership* memb, std::string &partmessage, CUList& excepts)
{
if (IS_LOCAL(memb->user))
{
- parameterlist params;
+ CmdBuilder params(memb->user, "PART");
params.push_back(memb->chan->name);
if (!partmessage.empty())
- params.push_back(":"+partmessage);
- Utils->DoOneToMany(memb->user->uuid,"PART",params);
+ params.push_last(partmessage);
+ params.Broadcast();
}
}
void ModuleSpanningTree::OnUserQuit(User* user, const std::string &reason, const std::string &oper_message)
{
- if ((IS_LOCAL(user)) && (user->registered == REG_ALL))
+ if (IS_LOCAL(user))
{
- parameterlist params;
-
if (oper_message != reason)
+ ServerInstance->PI->SendMetaData(user, "operquit", oper_message);
+
+ CmdBuilder(user, "QUIT").push_last(reason).Broadcast();
+ }
+ else
+ {
+ // Hide the message if one of the following is true:
+ // - User is being quit due to a netsplit and quietbursts is on
+ // - Server is a silent uline
+ bool hide = (((this->SplitInProgress) && (Utils->quiet_bursts)) || (user->server->IsSilentULine()));
+ if (!hide)
{
- params.push_back(":"+oper_message);
- Utils->DoOneToMany(user->uuid,"OPERQUIT",params);
+ ServerInstance->SNO->WriteToSnoMask('Q', "Client exiting on server %s: %s (%s) [%s]",
+ user->server->GetName().c_str(), user->GetFullRealHost().c_str(), user->GetIPString().c_str(), oper_message.c_str());
}
- params.clear();
- params.push_back(":"+reason);
- Utils->DoOneToMany(user->uuid,"QUIT",params);
}
// Regardless, We need to modify the user Counts..
- TreeServer* SourceServer = Utils->FindServer(user->server);
- if (SourceServer)
- {
- SourceServer->SetUserCount(-1); // decrement by 1
- }
+ TreeServer::Get(user)->UserCount--;
}
void ModuleSpanningTree::OnUserPostNick(User* user, const std::string &oldnick)
{
if (IS_LOCAL(user))
{
- parameterlist params;
+ // The nick TS is updated by the core, we don't do it
+ CmdBuilder params(user, "NICK");
params.push_back(user->nick);
-
- /** IMPORTANT: We don't update the TS if the oldnick is just a case change of the newnick!
- */
- if ((irc::string(user->nick.c_str()) != assign(oldnick)) && (!this->KeepNickTS))
- user->age = ServerInstance->Time();
-
params.push_back(ConvToStr(user->age));
- Utils->DoOneToMany(user->uuid,"NICK",params);
- this->KeepNickTS = false;
+ params.Broadcast();
}
else if (!loopCall && user->nick == user->uuid)
{
- parameterlist params;
+ CmdBuilder params("SAVE");
params.push_back(user->uuid);
params.push_back(ConvToStr(user->age));
- Utils->DoOneToMany(ServerInstance->Config->GetSID(),"SAVE",params);
+ params.Broadcast();
}
}
void ModuleSpanningTree::OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& excepts)
{
- parameterlist params;
+ if ((!IS_LOCAL(source)) && (source != ServerInstance->FakeClient))
+ return;
+
+ CmdBuilder params(source, "KICK");
params.push_back(memb->chan->name);
params.push_back(memb->user->uuid);
- params.push_back(":"+reason);
- if (IS_LOCAL(source))
- {
- Utils->DoOneToMany(source->uuid,"KICK",params);
- }
- else if (source == ServerInstance->FakeClient)
- {
- Utils->DoOneToMany(ServerInstance->Config->GetSID(),"KICK",params);
- }
-}
-
-void ModuleSpanningTree::OnRemoteKill(User* source, User* dest, const std::string &reason, const std::string &operreason)
-{
- if (!IS_LOCAL(source))
- return; // Only start routing if we're origin.
-
- ServerInstance->OperQuit.set(dest, operreason);
- parameterlist params;
- params.push_back(":"+operreason);
- Utils->DoOneToMany(dest->uuid,"OPERQUIT",params);
- params.clear();
- params.push_back(dest->uuid);
- params.push_back(":"+reason);
- Utils->DoOneToMany(source->uuid,"KILL",params);
+ // If a remote user is being kicked by us then send the membership id in the kick too
+ if (!IS_LOCAL(memb->user))
+ params.push_int(memb->id);
+ params.push_last(reason);
+ params.Broadcast();
}
void ModuleSpanningTree::OnPreRehash(User* user, const std::string &parameter)
@@ -757,19 +633,29 @@ void ModuleSpanningTree::OnPreRehash(User* user, const std::string &parameter)
if (loopCall)
return; // Don't generate a REHASH here if we're in the middle of processing a message that generated this one
- ServerInstance->Logs->Log("remoterehash", DEBUG, "called with param %s", parameter.c_str());
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "OnPreRehash called with param %s", parameter.c_str());
// Send out to other servers
if (!parameter.empty() && parameter[0] != '-')
{
- parameterlist params;
+ CmdBuilder params((user ? user->uuid : ServerInstance->Config->GetSID()), "REHASH");
params.push_back(parameter);
- Utils->DoOneToAllButSender(user ? user->uuid : ServerInstance->Config->GetSID(), "REHASH", params, user ? user->server : ServerInstance->Config->ServerName);
+ params.Forward(user ? TreeServer::Get(user)->GetRoute() : NULL);
}
}
-void ModuleSpanningTree::OnRehash(User* user)
+void ModuleSpanningTree::ReadConfig(ConfigStatus& status)
{
+ // Did this rehash change the description of this server?
+ const std::string& newdesc = ServerInstance->Config->ServerDesc;
+ if (newdesc != Utils->TreeRoot->GetDesc())
+ {
+ // Broadcast a SINFO desc message to let the network know about the new description. This is the description
+ // string that is sent in the SERVER message initially and shown for example in WHOIS.
+ // We don't need to update the field itself in the Server object - the core does that.
+ CommandSInfo::Builder(Utils->TreeRoot, "desc", newdesc).Broadcast();
+ }
+
// Re-read config stuff
try
{
@@ -783,8 +669,8 @@ void ModuleSpanningTree::OnRehash(User* user)
std::string msg = "Error in configuration: ";
msg.append(e.GetReason());
ServerInstance->SNO->WriteToSnoMask('l', msg);
- if (user && !IS_LOCAL(user))
- ServerInstance->PI->SendSNONotice("L", msg);
+ if (status.srcuser && !IS_LOCAL(status.srcuser))
+ ServerInstance->PI->SendSNONotice('L', msg);
}
}
@@ -799,20 +685,22 @@ void ModuleSpanningTree::OnLoadModule(Module* mod)
data.push_back('=');
data.append(v.link_data);
}
- ServerInstance->PI->SendMetaData(NULL, "modules", data);
+ ServerInstance->PI->SendMetaData("modules", data);
}
void ModuleSpanningTree::OnUnloadModule(Module* mod)
{
- ServerInstance->PI->SendMetaData(NULL, "modules", "-" + mod->ModuleSourceFile);
+ if (!Utils)
+ return;
+ ServerInstance->PI->SendMetaData("modules", "-" + mod->ModuleSourceFile);
restart:
- unsigned int items = Utils->TreeRoot->ChildCount();
- for(unsigned int x = 0; x < items; x++)
+ // Close all connections which use an IO hook provided by this module
+ const TreeServer::ChildServers& list = Utils->TreeRoot->GetChildren();
+ for (TreeServer::ChildServers::const_iterator i = list.begin(); i != list.end(); ++i)
{
- TreeServer* srv = Utils->TreeRoot->GetChild(x);
- TreeSocket* sock = srv->GetSocket();
- if (sock && sock->GetIOHook() == mod)
+ TreeSocket* sock = (*i)->GetSocket();
+ if (sock->GetIOHook() && sock->GetIOHook()->prov->creator == mod)
{
sock->SendError("SSL module unloaded");
sock->Close();
@@ -824,7 +712,7 @@ restart:
for (SpanningTreeUtilities::TimeoutList::const_iterator i = Utils->timeoutlist.begin(); i != Utils->timeoutlist.end(); ++i)
{
TreeSocket* sock = i->first;
- if (sock->GetIOHook() == mod)
+ if (sock->GetIOHook() && sock->GetIOHook()->prov->creator == mod)
sock->Close();
}
}
@@ -836,146 +724,55 @@ void ModuleSpanningTree::OnOper(User* user, const std::string &opertype)
{
if (user->registered != REG_ALL || !IS_LOCAL(user))
return;
- parameterlist params;
- params.push_back(opertype);
- Utils->DoOneToMany(user->uuid,"OPERTYPE",params);
+ CommandOpertype::Builder(user).Broadcast();
}
void ModuleSpanningTree::OnAddLine(User* user, XLine *x)
{
- if (!x->IsBurstable() || loopCall)
+ if (!x->IsBurstable() || loopCall || (user && !IS_LOCAL(user)))
return;
- parameterlist params;
- params.push_back(x->type);
- params.push_back(x->Displayable());
- params.push_back(ServerInstance->Config->ServerName);
- params.push_back(ConvToStr(x->set_time));
- params.push_back(ConvToStr(x->duration));
- params.push_back(":" + x->reason);
-
if (!user)
- {
- /* Server-set lines */
- Utils->DoOneToMany(ServerInstance->Config->GetSID(), "ADDLINE", params);
- }
- else if (IS_LOCAL(user))
- {
- /* User-set lines */
- Utils->DoOneToMany(user->uuid, "ADDLINE", params);
- }
+ user = ServerInstance->FakeClient;
+
+ CommandAddLine::Builder(x, user).Broadcast();
}
void ModuleSpanningTree::OnDelLine(User* user, XLine *x)
{
- if (!x->IsBurstable() || loopCall)
+ if (!x->IsBurstable() || loopCall || (user && !IS_LOCAL(user)))
return;
- parameterlist params;
- params.push_back(x->type);
- params.push_back(x->Displayable());
-
if (!user)
- {
- /* Server-unset lines */
- Utils->DoOneToMany(ServerInstance->Config->GetSID(), "DELLINE", params);
- }
- else if (IS_LOCAL(user))
- {
- /* User-unset lines */
- Utils->DoOneToMany(user->uuid, "DELLINE", params);
- }
-}
+ user = ServerInstance->FakeClient;
-void ModuleSpanningTree::OnMode(User* user, void* dest, int target_type, const parameterlist &text, const std::vector<TranslateType> &translate)
-{
- if ((IS_LOCAL(user)) && (user->registered == REG_ALL))
- {
- parameterlist params;
- std::string output_text;
-
- ServerInstance->Parser->TranslateUIDs(translate, text, output_text);
-
- if (target_type == TYPE_USER)
- {
- User* u = (User*)dest;
- params.push_back(u->uuid);
- params.push_back(output_text);
- Utils->DoOneToMany(user->uuid, "MODE", params);
- }
- else
- {
- Channel* c = (Channel*)dest;
- params.push_back(c->name);
- params.push_back(ConvToStr(c->age));
- params.push_back(output_text);
- Utils->DoOneToMany(user->uuid, "FMODE", params);
- }
- }
+ CmdBuilder params(user, "DELLINE");
+ params.push_back(x->type);
+ params.push_back(x->Displayable());
+ params.Broadcast();
}
ModResult ModuleSpanningTree::OnSetAway(User* user, const std::string &awaymsg)
{
if (IS_LOCAL(user))
- {
- parameterlist params;
- if (!awaymsg.empty())
- {
- params.push_back(ConvToStr(ServerInstance->Time()));
- params.push_back(":" + awaymsg);
- }
- Utils->DoOneToMany(user->uuid, "AWAY", params);
- }
+ CommandAway::Builder(user, awaymsg).Broadcast();
return MOD_RES_PASSTHRU;
}
-void ModuleSpanningTree::ProtoSendMode(void* opaque, TargetTypeFlags target_type, void* target, const parameterlist &modeline, const std::vector<TranslateType> &translate)
-{
- TreeSocket* s = (TreeSocket*)opaque;
- std::string output_text;
-
- ServerInstance->Parser->TranslateUIDs(translate, modeline, output_text);
-
- if (target)
- {
- if (target_type == TYPE_USER)
- {
- User* u = (User*)target;
- s->WriteLine(":"+ServerInstance->Config->GetSID()+" MODE "+u->uuid+" "+output_text);
- }
- else if (target_type == TYPE_CHANNEL)
- {
- Channel* c = (Channel*)target;
- s->WriteLine(":"+ServerInstance->Config->GetSID()+" FMODE "+c->name+" "+ConvToStr(c->age)+" "+output_text);
- }
- }
-}
-
-void ModuleSpanningTree::ProtoSendMetaData(void* opaque, Extensible* target, const std::string &extname, const std::string &extdata)
-{
- TreeSocket* s = static_cast<TreeSocket*>(opaque);
- User* u = dynamic_cast<User*>(target);
- Channel* c = dynamic_cast<Channel*>(target);
- if (u)
- s->WriteLine(":"+ServerInstance->Config->GetSID()+" METADATA "+u->uuid+" "+extname+" :"+extdata);
- else if (c)
- s->WriteLine(":"+ServerInstance->Config->GetSID()+" METADATA "+c->name+" "+extname+" :"+extdata);
- else if (!target)
- s->WriteLine(":"+ServerInstance->Config->GetSID()+" METADATA * "+extname+" :"+extdata);
-}
-
CullResult ModuleSpanningTree::cull()
{
- Utils->cull();
- ServerInstance->Timers->DelTimer(RefreshTimer);
+ if (Utils)
+ Utils->cull();
return this->Module::cull();
}
ModuleSpanningTree::~ModuleSpanningTree()
{
- delete ServerInstance->PI;
- ServerInstance->PI = new ProtocolInterface;
+ ServerInstance->PI = &ServerInstance->DefaultProtocolInterface;
+
+ Server* newsrv = new Server(ServerInstance->Config->ServerName, ServerInstance->Config->ServerDesc);
+ SetLocalUsersServer(newsrv);
/* This will also free the listeners */
delete Utils;
diff --git a/src/modules/m_spanningtree/main.h b/src/modules/m_spanningtree/main.h
index eb17c4195..f25370b93 100644
--- a/src/modules/m_spanningtree/main.h
+++ b/src/modules/m_spanningtree/main.h
@@ -21,11 +21,13 @@
*/
-#ifndef M_SPANNINGTREE_MAIN_H
-#define M_SPANNINGTREE_MAIN_H
+#pragma once
#include "inspircd.h"
-#include <stdarg.h>
+#include "modules/dns.h"
+#include "servercommand.h"
+#include "commands.h"
+#include "protocolinterface.h"
/** If you make a change which breaks the protocol, increment this.
* If you completely change the protocol, completely change the number.
@@ -36,8 +38,8 @@
* Failure to document your protocol changes will result in a painfully
* painful death by pain. You have been warned.
*/
-const long ProtocolVersion = 1202;
-const long MinCompatProtocol = 1201;
+const long ProtocolVersion = 1205;
+const long MinCompatProtocol = 1202;
/** Forward declarations
*/
@@ -52,47 +54,51 @@ class Autoconnect;
*/
class ModuleSpanningTree : public Module
{
+ /** Client to server commands, registered in the core
+ */
+ CommandRConnect rconnect;
+ CommandRSQuit rsquit;
+ CommandMap map;
+
+ /** Server to server only commands, not registered in the core
+ */
SpanningTreeCommands* commands;
+ /** Next membership id assigned when a local user joins a channel
+ */
+ Membership::Id currmembid;
+
+ /** The specialized ProtocolInterface that is assigned to ServerInstance->PI on load
+ */
+ SpanningTreeProtocolInterface protocolinterface;
+
public:
- SpanningTreeUtilities* Utils;
+ dynamic_reference<DNS::Manager> DNS;
+
+ ServerCommandManager CmdManager;
- CacheRefreshTimer *RefreshTimer;
/** Set to true if inside a spanningtree call, to prevent sending
* xlines and other things back to their source
*/
bool loopCall;
- /** If true OnUserPostNick() won't update the nick TS before sending the NICK,
- * used when handling SVSNICK.
+ /** True if users are quitting due to a netsplit
*/
- bool KeepNickTS;
+ bool SplitInProgress;
/** Constructor
*/
ModuleSpanningTree();
- void init();
+ void init() CXX11_OVERRIDE;
/** Shows /LINKS
*/
void ShowLinks(TreeServer* Current, User* user, int hops);
- /** Counts local and remote servers
- */
- int CountServs();
-
/** Handle LINKS command
*/
void HandleLinks(const std::vector<std::string>& parameters, User* user);
- /** Show MAP output to a user (recursive)
- */
- void ShowMap(TreeServer* Current, User* user, int depth, int &line, char* names, int &maxnamew, char* stats);
-
- /** Handle MAP command
- */
- bool HandleMap(const std::vector<std::string>& parameters, User* user);
-
/** Handle SQUIT
*/
ModResult HandleSquit(const std::vector<std::string>& parameters, User* user);
@@ -133,55 +139,41 @@ class ModuleSpanningTree : public Module
*/
void RemoteMessage(User* user, const char* format, ...) CUSTOM_PRINTF(3, 4);
- /** Returns oper-specific MAP information
- */
- const std::string MapOperInfo(TreeServer* Current);
-
/** Display a time as a human readable string
*/
- std::string TimeToStr(time_t secs);
+ static std::string TimeToStr(time_t secs);
/**
** *** MODULE EVENTS ***
**/
- ModResult OnPreCommand(std::string &command, std::vector<std::string>& parameters, LocalUser *user, bool validated, const std::string &original_line);
- void OnPostCommand(const std::string &command, const std::vector<std::string>& parameters, LocalUser *user, CmdResult result, const std::string &original_line);
- void OnGetServerDescription(const std::string &servername,std::string &description);
- void OnUserConnect(LocalUser* source);
- void OnUserInvite(User* source,User* dest,Channel* channel, time_t);
- void OnPostTopicChange(User* user, Channel* chan, const std::string &topic);
- void OnWallops(User* user, const std::string &text);
- void OnUserNotice(User* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list);
- void OnUserMessage(User* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list);
- void OnBackgroundTimer(time_t curtime);
- void OnUserJoin(Membership* memb, bool sync, bool created, CUList& excepts);
- void OnChangeHost(User* user, const std::string &newhost);
- void OnChangeName(User* user, const std::string &gecos);
- void OnChangeIdent(User* user, const std::string &ident);
- void OnUserPart(Membership* memb, std::string &partmessage, CUList& excepts);
- void OnUserQuit(User* user, const std::string &reason, const std::string &oper_message);
- void OnUserPostNick(User* user, const std::string &oldnick);
- void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& excepts);
- void OnRemoteKill(User* source, User* dest, const std::string &reason, const std::string &operreason);
- void OnPreRehash(User* user, const std::string &parameter);
- void OnRehash(User* user);
- void OnOper(User* user, const std::string &opertype);
- void OnLine(User* source, const std::string &host, bool adding, char linetype, long duration, const std::string &reason);
- void OnAddLine(User *u, XLine *x);
- void OnDelLine(User *u, XLine *x);
- void OnMode(User* user, void* dest, int target_type, const std::vector<std::string> &text, const std::vector<TranslateType> &translate);
- ModResult OnStats(char statschar, User* user, string_list &results);
- ModResult OnSetAway(User* user, const std::string &awaymsg);
- void ProtoSendMode(void* opaque, TargetTypeFlags target_type, void* target, const std::vector<std::string> &modeline, const std::vector<TranslateType> &translate);
- void ProtoSendMetaData(void* opaque, Extensible* target, const std::string &extname, const std::string &extdata);
- void OnLoadModule(Module* mod);
- void OnUnloadModule(Module* mod);
- ModResult OnAcceptConnection(int newsock, ListenSocket* from, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server);
+ ModResult OnPreCommand(std::string &command, std::vector<std::string>& parameters, LocalUser *user, bool validated, const std::string &original_line) CXX11_OVERRIDE;
+ void OnPostCommand(Command*, const std::vector<std::string>& parameters, LocalUser* user, CmdResult result, const std::string& original_line) CXX11_OVERRIDE;
+ void OnUserConnect(LocalUser* source) CXX11_OVERRIDE;
+ void OnUserInvite(User* source,User* dest,Channel* channel, time_t) CXX11_OVERRIDE;
+ void OnPostTopicChange(User* user, Channel* chan, const std::string &topic) CXX11_OVERRIDE;
+ void OnUserMessage(User* user, void* dest, int target_type, const std::string& text, char status, const CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE;
+ void OnBackgroundTimer(time_t curtime) CXX11_OVERRIDE;
+ void OnUserJoin(Membership* memb, bool sync, bool created, CUList& excepts) CXX11_OVERRIDE;
+ void OnChangeHost(User* user, const std::string &newhost) CXX11_OVERRIDE;
+ void OnChangeName(User* user, const std::string &gecos) CXX11_OVERRIDE;
+ void OnChangeIdent(User* user, const std::string &ident) CXX11_OVERRIDE;
+ void OnUserPart(Membership* memb, std::string &partmessage, CUList& excepts) CXX11_OVERRIDE;
+ void OnUserQuit(User* user, const std::string &reason, const std::string &oper_message) CXX11_OVERRIDE;
+ void OnUserPostNick(User* user, const std::string &oldnick) CXX11_OVERRIDE;
+ void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& excepts) CXX11_OVERRIDE;
+ void OnPreRehash(User* user, const std::string &parameter) CXX11_OVERRIDE;
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE;
+ void OnOper(User* user, const std::string &opertype) CXX11_OVERRIDE;
+ void OnAddLine(User *u, XLine *x) CXX11_OVERRIDE;
+ void OnDelLine(User *u, XLine *x) CXX11_OVERRIDE;
+ ModResult OnStats(char statschar, User* user, string_list &results) CXX11_OVERRIDE;
+ ModResult OnSetAway(User* user, const std::string &awaymsg) CXX11_OVERRIDE;
+ void OnLoadModule(Module* mod) CXX11_OVERRIDE;
+ void OnUnloadModule(Module* mod) CXX11_OVERRIDE;
+ ModResult OnAcceptConnection(int newsock, ListenSocket* from, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) CXX11_OVERRIDE;
CullResult cull();
~ModuleSpanningTree();
- Version GetVersion();
+ Version GetVersion() CXX11_OVERRIDE;
void Prioritize();
};
-
-#endif
diff --git a/src/modules/m_spanningtree/metadata.cpp b/src/modules/m_spanningtree/metadata.cpp
index a584f8fa8..13ccabc35 100644
--- a/src/modules/m_spanningtree/metadata.cpp
+++ b/src/modules/m_spanningtree/metadata.cpp
@@ -21,39 +21,76 @@
#include "inspircd.h"
#include "commands.h"
-#include "treesocket.h"
-#include "treeserver.h"
-#include "utils.h"
-
-CmdResult CommandMetadata::Handle(const std::vector<std::string>& params, User *srcuser)
+CmdResult CommandMetadata::Handle(User* srcuser, std::vector<std::string>& params)
{
- std::string value = params.size() < 3 ? "" : params[2];
- ExtensionItem* item = ServerInstance->Extensions.GetItem(params[1]);
if (params[0] == "*")
{
- FOREACH_MOD(I_OnDecodeMetaData,OnDecodeMetaData(NULL,params[1],value));
+ std::string value = params.size() < 3 ? "" : params[2];
+ FOREACH_MOD(OnDecodeMetaData, (NULL,params[1],value));
+ return CMD_SUCCESS;
}
- else if (*(params[0].c_str()) == '#')
+
+ if (params[0][0] == '#')
{
+ // Channel METADATA has an additional parameter: the channel TS
+ // :22D METADATA #channel 12345 extname :extdata
+ if (params.size() < 3)
+ throw ProtocolException("Insufficient parameters for channel METADATA");
+
Channel* c = ServerInstance->FindChan(params[0]);
- if (c)
- {
- if (item)
- item->unserialize(FORMAT_NETWORK, c, value);
- FOREACH_MOD(I_OnDecodeMetaData,OnDecodeMetaData(c,params[1],value));
- }
+ if (!c)
+ return CMD_FAILURE;
+
+ time_t ChanTS = ServerCommand::ExtractTS(params[1]);
+ if (c->age < ChanTS)
+ // Their TS is newer than ours, discard this command and do not propagate
+ return CMD_FAILURE;
+
+ std::string value = params.size() < 4 ? "" : params[3];
+
+ ExtensionItem* item = ServerInstance->Extensions.GetItem(params[2]);
+ if (item)
+ item->unserialize(FORMAT_NETWORK, c, value);
+ FOREACH_MOD(OnDecodeMetaData, (c,params[2],value));
}
- else if (*(params[0].c_str()) != '#')
+ else
{
User* u = ServerInstance->FindUUID(params[0]);
if ((u) && (!IS_SERVER(u)))
{
+ ExtensionItem* item = ServerInstance->Extensions.GetItem(params[1]);
+ std::string value = params.size() < 3 ? "" : params[2];
+
if (item)
item->unserialize(FORMAT_NETWORK, u, value);
- FOREACH_MOD(I_OnDecodeMetaData,OnDecodeMetaData(u,params[1],value));
+ FOREACH_MOD(OnDecodeMetaData, (u,params[1],value));
}
}
return CMD_SUCCESS;
}
+CommandMetadata::Builder::Builder(User* user, const std::string& key, const std::string& val)
+ : CmdBuilder("METADATA")
+{
+ push(user->uuid);
+ push(key);
+ push_last(val);
+}
+
+CommandMetadata::Builder::Builder(Channel* chan, const std::string& key, const std::string& val)
+ : CmdBuilder("METADATA")
+{
+ push(chan->name);
+ push_int(chan->age);
+ push(key);
+ push_last(val);
+}
+
+CommandMetadata::Builder::Builder(const std::string& key, const std::string& val)
+ : CmdBuilder("METADATA")
+{
+ push("*");
+ push(key);
+ push_last(val);
+}
diff --git a/src/modules/m_spanningtree/misccommands.cpp b/src/modules/m_spanningtree/misccommands.cpp
new file mode 100644
index 000000000..5b04c73bc
--- /dev/null
+++ b/src/modules/m_spanningtree/misccommands.cpp
@@ -0,0 +1,48 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2013 Attila Molnar <attilamolnar@hush.com>
+ * Copyright (C) 2007-2008, 2012 Robin Burchell <robin+git@viroteck.net>
+ * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc>
+ * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com>
+ * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
+ * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+
+#include "main.h"
+#include "commands.h"
+#include "treeserver.h"
+
+CmdResult CommandSNONotice::Handle(User* user, std::vector<std::string>& params)
+{
+ ServerInstance->SNO->WriteToSnoMask(params[0][0], "From " + user->nick + ": " + params[1]);
+ return CMD_SUCCESS;
+}
+
+CmdResult CommandBurst::HandleServer(TreeServer* server, std::vector<std::string>& params)
+{
+ server->bursting = true;
+ return CMD_SUCCESS;
+}
+
+CmdResult CommandEndBurst::HandleServer(TreeServer* server, std::vector<std::string>& params)
+{
+ server->FinishBurst();
+ return CMD_SUCCESS;
+}
diff --git a/src/modules/m_spanningtree/netburst.cpp b/src/modules/m_spanningtree/netburst.cpp
index d508c092d..e42ab5e67 100644
--- a/src/modules/m_spanningtree/netburst.cpp
+++ b/src/modules/m_spanningtree/netburst.cpp
@@ -21,11 +21,79 @@
#include "inspircd.h"
#include "xline.h"
+#include "listmode.h"
#include "treesocket.h"
#include "treeserver.h"
-#include "utils.h"
#include "main.h"
+#include "commands.h"
+
+/**
+ * Creates FMODE messages, used only when syncing channels
+ */
+class FModeBuilder : public CmdBuilder
+{
+ static const size_t maxline = 480;
+ std::string params;
+ unsigned int modes;
+ std::string::size_type startpos;
+
+ public:
+ FModeBuilder(Channel* chan)
+ : CmdBuilder("FMODE"), modes(0)
+ {
+ push(chan->name).push_int(chan->age).push_raw(" +");
+ startpos = str().size();
+ }
+
+ /** Add a mode to the message
+ */
+ void push_mode(const char modeletter, const std::string& mask)
+ {
+ push_raw(modeletter);
+ params.push_back(' ');
+ params.append(mask);
+ modes++;
+ }
+
+ /** Remove all modes from the message
+ */
+ void clear()
+ {
+ content.erase(startpos);
+ params.clear();
+ modes = 0;
+ }
+
+ /** Prepare the message for sending, next mode can only be added after clear()
+ */
+ const std::string& finalize()
+ {
+ return push_raw(params);
+ }
+
+ /** Returns true if the given mask can be added to the message, false if the message
+ * has no room for the mask
+ */
+ bool has_room(const std::string& mask) const
+ {
+ return ((str().size() + params.size() + mask.size() + 2 <= maxline) &&
+ (modes < ServerInstance->Config->Limits.MaxModes));
+ }
+
+ /** Returns true if this message is empty (has no modes)
+ */
+ bool empty() const
+ {
+ return (modes == 0);
+ }
+};
+
+struct TreeSocket::BurstState
+{
+ SpanningTreeProtocolInterface::Server server;
+ BurstState(TreeSocket* sock) : server(sock) { }
+};
/** This function is called when we want to send a netburst to a local
* server. There is a set order we must do this, because for example
@@ -34,52 +102,58 @@
*/
void TreeSocket::DoBurst(TreeServer* s)
{
- std::string servername = s->GetName();
ServerInstance->SNO->WriteToSnoMask('l',"Bursting to \2%s\2 (Authentication: %s%s).",
- servername.c_str(),
- capab->auth_fingerprint ? "SSL Fingerprint and " : "",
+ s->GetName().c_str(),
+ capab->auth_fingerprint ? "SSL certificate fingerprint and " : "",
capab->auth_challenge ? "challenge-response" : "plaintext password");
this->CleanNegotiationInfo();
- this->WriteLine(":" + ServerInstance->Config->GetSID() + " BURST " + ConvToStr(ServerInstance->Time()));
- /* send our version string */
- this->WriteLine(":" + ServerInstance->Config->GetSID() + " VERSION :"+ServerInstance->GetVersionString());
+ this->WriteLine(CmdBuilder("BURST").push_int(ServerInstance->Time()));
/* Send server tree */
- this->SendServers(Utils->TreeRoot,s,1);
+ this->SendServers(Utils->TreeRoot, s);
+
+ BurstState bs(this);
/* Send users and their oper status */
- this->SendUsers();
- /* Send everything else (channel modes, xlines etc) */
- this->SendChannelModes();
+ this->SendUsers(bs);
+
+ const chan_hash& chans = ServerInstance->GetChans();
+ for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); ++i)
+ SyncChannel(i->second, bs);
+
this->SendXLines();
- FOREACH_MOD(I_OnSyncNetwork,OnSyncNetwork(Utils->Creator,(void*)this));
- this->WriteLine(":" + ServerInstance->Config->GetSID() + " ENDBURST");
+ FOREACH_MOD(OnSyncNetwork, (bs.server));
+ this->WriteLine(CmdBuilder("ENDBURST"));
ServerInstance->SNO->WriteToSnoMask('l',"Finished bursting to \2"+ s->GetName()+"\2.");
}
-/** Recursively send the server tree with distances as hops.
+void TreeSocket::SendServerInfo(TreeServer* from)
+{
+ // Send public version string
+ this->WriteLine(CommandSInfo::Builder(from, "version", from->GetVersion()));
+
+ // Send full version string that contains more information and is shown to opers
+ this->WriteLine(CommandSInfo::Builder(from, "fullversion", from->GetFullVersion()));
+}
+
+/** Recursively send the server tree.
* This is used during network burst to inform the other server
* (and any of ITS servers too) of what servers we know about.
* If at any point any of these servers already exist on the other
- * end, our connection may be terminated. The hopcounts given
- * by this function are relative, this doesn't matter so long as
- * they are all >1, as all the remote servers re-calculate them
- * to be relative too, with themselves as hop 0.
+ * end, our connection may be terminated.
+ * The hopcount parameter (3rd) is deprecated, and is always 0.
*/
-void TreeSocket::SendServers(TreeServer* Current, TreeServer* s, int hops)
+void TreeSocket::SendServers(TreeServer* Current, TreeServer* s)
{
- char command[MAXBUF];
- for (unsigned int q = 0; q < Current->ChildCount(); q++)
+ SendServerInfo(Current);
+
+ const TreeServer::ChildServers& children = Current->GetChildren();
+ for (TreeServer::ChildServers::const_iterator i = children.begin(); i != children.end(); ++i)
{
- TreeServer* recursive_server = Current->GetChild(q);
+ TreeServer* recursive_server = *i;
if (recursive_server != s)
{
- std::string recursive_servername = recursive_server->GetName();
- snprintf(command, MAXBUF, ":%s SERVER %s * %d %s :%s", Current->GetID().c_str(), recursive_servername.c_str(), hops,
- recursive_server->GetID().c_str(),
- recursive_server->GetDesc().c_str());
- this->WriteLine(command);
- this->WriteLine(":"+recursive_server->GetID()+" VERSION :"+recursive_server->GetVersion());
+ this->WriteLine(CommandServer::Builder(recursive_server));
/* down to next level */
- this->SendServers(recursive_server, s, hops+1);
+ this->SendServers(recursive_server, s);
}
}
}
@@ -87,101 +161,39 @@ void TreeSocket::SendServers(TreeServer* Current, TreeServer* s, int hops)
/** Send one or more FJOINs for a channel of users.
* If the length of a single line is more than 480-NICKMAX
* in length, it is split over multiple lines.
+ * Send one or more FMODEs for a channel with the
+ * channel bans, if there's any.
*/
void TreeSocket::SendFJoins(Channel* c)
{
- std::string buffer;
- char list[MAXBUF];
-
- size_t curlen, headlen;
- curlen = headlen = snprintf(list,MAXBUF,":%s FJOIN %s %lu +%s :",
- ServerInstance->Config->GetSID().c_str(), c->name.c_str(), (unsigned long)c->age, c->ChanModes(true));
- int numusers = 0;
- char* ptr = list + curlen;
- bool looped_once = false;
-
- const UserMembList *ulist = c->GetUsers();
- std::string modes;
- std::string params;
+ CommandFJoin::Builder fjoin(c);
- for (UserMembCIter i = ulist->begin(); i != ulist->end(); i++)
+ const Channel::MemberMap& ulist = c->GetUsers();
+ for (Channel::MemberMap::const_iterator i = ulist.begin(); i != ulist.end(); ++i)
{
- size_t ptrlen = 0;
- std::string modestr = i->second->modes;
-
- if ((curlen + modestr.length() + i->first->uuid.length() + 4) > 480)
+ Membership* memb = i->second;
+ if (!fjoin.has_room(memb))
{
- // remove the final space
- if (ptr[-1] == ' ')
- ptr[-1] = '\0';
- buffer.append(list).append("\r\n");
- curlen = headlen;
- ptr = list + headlen;
- numusers = 0;
+ // No room for this user, send the line and prepare a new one
+ this->WriteLine(fjoin.finalize());
+ fjoin.clear();
}
-
- ptrlen = snprintf(ptr, MAXBUF-curlen, "%s,%s ", modestr.c_str(), i->first->uuid.c_str());
-
- looped_once = true;
-
- curlen += ptrlen;
- ptr += ptrlen;
-
- numusers++;
+ fjoin.add(memb);
}
-
- // Okay, permanent channels will (of course) need this \r\n anyway, numusers check is if there
- // actually were people in the channel (looped_once == true)
- if (!looped_once || numusers > 0)
- {
- // remove the final space
- if (ptr[-1] == ' ')
- ptr[-1] = '\0';
- buffer.append(list).append("\r\n");
- }
-
- int linesize = 1;
- for (BanList::iterator b = c->bans.begin(); b != c->bans.end(); b++)
- {
- int size = b->data.length() + 2;
- int currsize = linesize + size;
- if (currsize <= 350)
- {
- modes.append("b");
- params.append(" ").append(b->data);
- linesize += size;
- }
- if ((modes.length() >= ServerInstance->Config->Limits.MaxModes) || (currsize > 350))
- {
- /* Wrap at MAXMODES */
- buffer.append(":").append(ServerInstance->Config->GetSID()).append(" FMODE ").append(c->name).append(" ").append(ConvToStr(c->age)).append(" +").append(modes).append(params).append("\r\n");
- modes.clear();
- params.clear();
- linesize = 1;
- }
- }
-
- /* Only send these if there are any */
- if (!modes.empty())
- buffer.append(":").append(ServerInstance->Config->GetSID()).append(" FMODE ").append(c->name).append(" ").append(ConvToStr(c->age)).append(" +").append(modes).append(params);
-
- this->WriteLine(buffer);
+ this->WriteLine(fjoin.finalize());
}
/** Send all XLines we know about */
void TreeSocket::SendXLines()
{
- char data[MAXBUF];
- std::string n = ServerInstance->Config->GetSID();
- const char* sn = n.c_str();
-
std::vector<std::string> types = ServerInstance->XLines->GetAllTypes();
- time_t current = ServerInstance->Time();
- for (std::vector<std::string>::iterator it = types.begin(); it != types.end(); ++it)
+ for (std::vector<std::string>::const_iterator it = types.begin(); it != types.end(); ++it)
{
+ /* Expired lines are removed in XLineManager::GetAll() */
XLineLookup* lookup = ServerInstance->XLines->GetAll(*it);
+ /* lookup cannot be NULL in this case but a check won't hurt */
if (lookup)
{
for (LookupIter i = lookup->begin(); i != lookup->end(); ++i)
@@ -192,96 +204,101 @@ void TreeSocket::SendXLines()
if (!i->second->IsBurstable())
break;
- /* If it's expired, don't bother to burst it
- */
- if (i->second->duration && current > i->second->expiry)
- continue;
-
- snprintf(data,MAXBUF,":%s ADDLINE %s %s %s %lu %lu :%s",sn, it->c_str(), i->second->Displayable(),
- i->second->source.c_str(),
- (unsigned long)i->second->set_time,
- (unsigned long)i->second->duration,
- i->second->reason.c_str());
- this->WriteLine(data);
+ this->WriteLine(CommandAddLine::Builder(i->second));
}
}
}
}
-/** Send channel topic, modes and metadata */
-void TreeSocket::SendChannelModes()
+void TreeSocket::SendListModes(Channel* chan)
{
- char data[MAXBUF];
- std::string n = ServerInstance->Config->GetSID();
- const char* sn = n.c_str();
-
- for (chan_hash::iterator c = ServerInstance->chanlist->begin(); c != ServerInstance->chanlist->end(); c++)
+ FModeBuilder fmode(chan);
+ const ModeParser::ListModeList& listmodes = ServerInstance->Modes->GetListModes();
+ for (ModeParser::ListModeList::const_iterator i = listmodes.begin(); i != listmodes.end(); ++i)
{
- SendFJoins(c->second);
- if (!c->second->topic.empty())
+ ListModeBase* mh = *i;
+ ListModeBase::ModeList* list = mh->GetList(chan);
+ if (!list)
+ continue;
+
+ // Add all items on the list to the FMODE, send it whenever it becomes too long
+ const char modeletter = mh->GetModeChar();
+ for (ListModeBase::ModeList::const_iterator j = list->begin(); j != list->end(); ++j)
{
- snprintf(data,MAXBUF,":%s FTOPIC %s %lu %s :%s", sn, c->second->name.c_str(), (unsigned long)c->second->topicset, c->second->setby.c_str(), c->second->topic.c_str());
- this->WriteLine(data);
+ const std::string& mask = j->mask;
+ if (!fmode.has_room(mask))
+ {
+ // No room for this mask, send the current line as-is then add the mask to a
+ // new, empty FMODE message
+ this->WriteLine(fmode.finalize());
+ fmode.clear();
+ }
+ fmode.push_mode(modeletter, mask);
}
+ }
- for(Extensible::ExtensibleStore::const_iterator i = c->second->GetExtList().begin(); i != c->second->GetExtList().end(); i++)
- {
- ExtensionItem* item = i->first;
- std::string value = item->serialize(FORMAT_NETWORK, c->second, i->second);
- if (!value.empty())
- Utils->Creator->ProtoSendMetaData(this, c->second, item->name, value);
- }
+ if (!fmode.empty())
+ this->WriteLine(fmode.finalize());
+}
+
+/** Send channel topic, modes and metadata */
+void TreeSocket::SyncChannel(Channel* chan, BurstState& bs)
+{
+ SendFJoins(chan);
+
+ // If the topic was ever set, send it, even if it's empty now
+ // because a new empty topic should override an old non-empty topic
+ if (chan->topicset != 0)
+ this->WriteLine(CommandFTopic::Builder(chan));
+
+ SendListModes(chan);
- FOREACH_MOD(I_OnSyncChannel,OnSyncChannel(c->second,Utils->Creator,this));
+ for (Extensible::ExtensibleStore::const_iterator i = chan->GetExtList().begin(); i != chan->GetExtList().end(); i++)
+ {
+ ExtensionItem* item = i->first;
+ std::string value = item->serialize(FORMAT_NETWORK, chan, i->second);
+ if (!value.empty())
+ this->WriteLine(CommandMetadata::Builder(chan, item->name, value));
}
+
+ FOREACH_MOD(OnSyncChannel, (chan, bs.server));
+}
+
+void TreeSocket::SyncChannel(Channel* chan)
+{
+ BurstState bs(this);
+ SyncChannel(chan, bs);
}
/** send all users and their oper state/modes */
-void TreeSocket::SendUsers()
+void TreeSocket::SendUsers(BurstState& bs)
{
- char data[MAXBUF];
- for (user_hash::iterator u = ServerInstance->Users->clientlist->begin(); u != ServerInstance->Users->clientlist->end(); u++)
+ ProtocolInterface::Server& piserver = bs.server;
+
+ const user_hash& users = ServerInstance->Users->GetUsers();
+ for (user_hash::const_iterator u = users.begin(); u != users.end(); ++u)
{
- if (u->second->registered == REG_ALL)
- {
- TreeServer* theirserver = Utils->FindServer(u->second->server);
- if (theirserver)
- {
- snprintf(data,MAXBUF,":%s UID %s %lu %s %s %s %s %s %lu +%s :%s",
- theirserver->GetID().c_str(), /* Prefix: SID */
- u->second->uuid.c_str(), /* 0: UUID */
- (unsigned long)u->second->age, /* 1: TS */
- u->second->nick.c_str(), /* 2: Nick */
- u->second->host.c_str(), /* 3: Displayed Host */
- u->second->dhost.c_str(), /* 4: Real host */
- u->second->ident.c_str(), /* 5: Ident */
- u->second->GetIPString(), /* 6: IP string */
- (unsigned long)u->second->signon, /* 7: Signon time for WHOWAS */
- u->second->FormatModes(true), /* 8...n: Modes and params */
- u->second->fullname.c_str()); /* size-1: GECOS */
- this->WriteLine(data);
- if (IS_OPER(u->second))
- {
- snprintf(data,MAXBUF,":%s OPERTYPE %s", u->second->uuid.c_str(), u->second->oper->name.c_str());
- this->WriteLine(data);
- }
- if (IS_AWAY(u->second))
- {
- snprintf(data,MAXBUF,":%s AWAY %ld :%s", u->second->uuid.c_str(), (long)u->second->awaytime, u->second->awaymsg.c_str());
- this->WriteLine(data);
- }
- }
+ User* user = u->second;
+ if (user->registered != REG_ALL)
+ continue;
- for(Extensible::ExtensibleStore::const_iterator i = u->second->GetExtList().begin(); i != u->second->GetExtList().end(); i++)
- {
- ExtensionItem* item = i->first;
- std::string value = item->serialize(FORMAT_NETWORK, u->second, i->second);
- if (!value.empty())
- Utils->Creator->ProtoSendMetaData(this, u->second, item->name, value);
- }
+ this->WriteLine(CommandUID::Builder(user));
+
+ if (user->IsOper())
+ this->WriteLine(CommandOpertype::Builder(user));
+
+ if (user->IsAway())
+ this->WriteLine(CommandAway::Builder(user));
- FOREACH_MOD(I_OnSyncUser,OnSyncUser(u->second,Utils->Creator,this));
+ const Extensible::ExtensibleStore& exts = user->GetExtList();
+ for (Extensible::ExtensibleStore::const_iterator i = exts.begin(); i != exts.end(); ++i)
+ {
+ ExtensionItem* item = i->first;
+ std::string value = item->serialize(FORMAT_NETWORK, u->second, i->second);
+ if (!value.empty())
+ this->WriteLine(CommandMetadata::Builder(user, item->name, value));
}
+
+ FOREACH_MOD(OnSyncUser, (user, piserver));
}
}
-
diff --git a/src/modules/m_spanningtree/nick.cpp b/src/modules/m_spanningtree/nick.cpp
new file mode 100644
index 000000000..686a2cc4c
--- /dev/null
+++ b/src/modules/m_spanningtree/nick.cpp
@@ -0,0 +1,63 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2013 Attila Molnar <attilamolnar@hush.com>
+ * Copyright (C) 2007-2008, 2012 Robin Burchell <robin+git@viroteck.net>
+ * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc>
+ * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com>
+ * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
+ * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+
+#include "main.h"
+#include "utils.h"
+#include "commands.h"
+#include "treeserver.h"
+
+CmdResult CommandNick::HandleRemote(RemoteUser* user, std::vector<std::string>& params)
+{
+ if ((isdigit(params[0][0])) && (params[0] != user->uuid))
+ throw ProtocolException("Attempted to change nick to an invalid or non-matching UUID");
+
+ /* Update timestamp on user when they change nicks */
+ const time_t newts = ConvToInt(params[1]);
+
+ /*
+ * On nick messages, check that the nick doesn't already exist here.
+ * If it does, perform collision logic.
+ */
+ bool callfnc = true;
+ User* x = ServerInstance->FindNickOnly(params[0]);
+ if ((x) && (x != user) && (x->registered == REG_ALL))
+ {
+ /* x is local, who is remote */
+ int collideret = Utils->DoCollision(x, TreeServer::Get(user), newts, user->ident, user->GetIPString(), user->uuid);
+ if (collideret != 1)
+ {
+ // Remote client lost, or both lost, rewrite this nick change as a change to uuid before
+ // forwarding and don't call ChangeNick() because DoCollision() has done it already
+ params[0] = user->uuid;
+ callfnc = false;
+ }
+ }
+ if (callfnc)
+ user->ChangeNick(params[0], newts);
+
+ return CMD_SUCCESS;
+}
diff --git a/src/modules/m_spanningtree/nickcollide.cpp b/src/modules/m_spanningtree/nickcollide.cpp
index 38d59affb..e6bcb21b2 100644
--- a/src/modules/m_spanningtree/nickcollide.cpp
+++ b/src/modules/m_spanningtree/nickcollide.cpp
@@ -19,14 +19,11 @@
#include "inspircd.h"
-#include "xline.h"
#include "treesocket.h"
#include "treeserver.h"
#include "utils.h"
-
-/* $ModDep: m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h */
-
+#include "commandbuilder.h"
/*
* Yes, this function looks a little ugly.
@@ -34,8 +31,11 @@
* Returns 1 if colliding local client, 2 if colliding remote, 3 if colliding both.
* Sends SAVEs as appropriate and forces nickchanges too.
*/
-int TreeSocket::DoCollision(User *u, time_t remotets, const std::string &remoteident, const std::string &remoteip, const std::string &remoteuid)
+int SpanningTreeUtilities::DoCollision(User* u, TreeServer* server, time_t remotets, const std::string& remoteident, const std::string& remoteip, const std::string& remoteuid)
{
+ // At this point we're sure that a collision happened, increment the counter regardless of who wins
+ ServerInstance->stats.Collisions++;
+
/*
* Under old protocol rules, we would have had to kill both clients.
* Really, this sucks.
@@ -109,12 +109,12 @@ int TreeSocket::DoCollision(User *u, time_t remotets, const std::string &remotei
* Local-side nick needs to change. Just in case we are hub, and
* this "local" nick is actually behind us, send an SAVE out.
*/
- parameterlist params;
+ CmdBuilder params("SAVE");
params.push_back(u->uuid);
params.push_back(ConvToStr(u->age));
- Utils->DoOneToMany(ServerInstance->Config->GetSID(),"SAVE",params);
+ params.Broadcast();
- u->ForceNickChange(u->uuid.c_str());
+ u->ChangeNick(u->uuid);
if (!bChangeRemote)
return 1;
@@ -127,12 +127,13 @@ int TreeSocket::DoCollision(User *u, time_t remotets, const std::string &remotei
* the UID or halt the propagation of the nick change command,
* so other servers don't need to see the SAVE
*/
- WriteLine(":"+ServerInstance->Config->GetSID()+" SAVE "+remoteuid+" "+ ConvToStr(remotets));
+ TreeSocket* sock = server->GetSocket();
+ sock->WriteLine(CmdBuilder("SAVE").push(remoteuid).push_int(remotets));
if (remote)
{
/* nick change collide. Force change their nick. */
- remote->ForceNickChange(remoteuid.c_str());
+ remote->ChangeNick(remoteuid);
}
if (!bChangeLocal)
@@ -141,4 +142,3 @@ int TreeSocket::DoCollision(User *u, time_t remotets, const std::string &remotei
return 3;
}
-
diff --git a/src/modules/m_spanningtree/operquit.cpp b/src/modules/m_spanningtree/operquit.cpp
deleted file mode 100644
index af2e04ebc..000000000
--- a/src/modules/m_spanningtree/operquit.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-#include "xline.h"
-
-#include "treesocket.h"
-#include "treeserver.h"
-#include "utils.h"
-
-/* $ModDep: m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h */
-
-
-bool TreeSocket::OperQuit(const std::string &prefix, parameterlist &params)
-{
- if (params.size() < 1)
- return true;
-
- User* u = ServerInstance->FindUUID(prefix);
-
- if ((u) && (!IS_SERVER(u)))
- {
- ServerInstance->OperQuit.set(u, params[0]);
- params[0] = ":" + params[0];
- Utils->DoOneToAllButSender(prefix,"OPERQUIT",params,prefix);
- }
- return true;
-}
-
diff --git a/src/modules/m_spanningtree/opertype.cpp b/src/modules/m_spanningtree/opertype.cpp
index 97a4de8c2..16d752966 100644
--- a/src/modules/m_spanningtree/opertype.cpp
+++ b/src/modules/m_spanningtree/opertype.cpp
@@ -26,15 +26,17 @@
/** Because the core won't let users or even SERVERS set +o,
* we use the OPERTYPE command to do this.
*/
-CmdResult CommandOpertype::Handle(const std::vector<std::string>& params, User *u)
+CmdResult CommandOpertype::HandleRemote(RemoteUser* u, std::vector<std::string>& params)
{
- SpanningTreeUtilities* Utils = ((ModuleSpanningTree*)(Module*)creator)->Utils;
- std::string opertype = params[0];
- if (!IS_OPER(u))
+ const std::string& opertype = params[0];
+ if (!u->IsOper())
ServerInstance->Users->all_opers.push_back(u);
- u->modes[UM_OPERATOR] = 1;
- OperIndex::iterator iter = ServerInstance->Config->oper_blocks.find(" " + opertype);
- if (iter != ServerInstance->Config->oper_blocks.end())
+
+ ModeHandler* opermh = ServerInstance->Modes->FindMode('o', MODETYPE_USER);
+ u->SetMode(opermh, true);
+
+ ServerConfig::OperIndex::const_iterator iter = ServerInstance->Config->OperTypes.find(opertype);
+ if (iter != ServerInstance->Config->OperTypes.end())
u->oper = iter->second;
else
{
@@ -48,12 +50,17 @@ CmdResult CommandOpertype::Handle(const std::vector<std::string>& params, User *
* If quiet bursts are enabled, and server is bursting or silent uline (i.e. services),
* then do nothing. -- w00t
*/
- TreeServer* remoteserver = Utils->FindServer(u->server);
- if (remoteserver->bursting || ServerInstance->SilentULine(u->server))
+ TreeServer* remoteserver = TreeServer::Get(u);
+ if (remoteserver->bursting || remoteserver->IsSilentULine())
return CMD_SUCCESS;
}
- ServerInstance->SNO->WriteToSnoMask('O',"From %s: User %s (%s@%s) is now an IRC operator of type %s",u->server.c_str(), u->nick.c_str(),u->ident.c_str(), u->host.c_str(), irc::Spacify(opertype.c_str()));
+ ServerInstance->SNO->WriteToSnoMask('O',"From %s: User %s (%s@%s) is now an IRC operator of type %s",u->server->GetName().c_str(), u->nick.c_str(),u->ident.c_str(), u->host.c_str(), opertype.c_str());
return CMD_SUCCESS;
}
+CommandOpertype::Builder::Builder(User* user)
+ : CmdBuilder(user, "OPERTYPE")
+{
+ push_last(user->oper->name);
+}
diff --git a/src/modules/m_spanningtree/override_map.cpp b/src/modules/m_spanningtree/override_map.cpp
index 04fa4bcab..68551e84f 100644
--- a/src/modules/m_spanningtree/override_map.cpp
+++ b/src/modules/m_spanningtree/override_map.cpp
@@ -1,6 +1,7 @@
/*
* InspIRCd -- Internet Relay Chat Daemon
*
+ * Copyright (C) 2014 Adam <Adam@anope.org>
* Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
* Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc>
* Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net>
@@ -19,178 +20,203 @@
*/
-/* $ModDesc: Provides a spanning tree server link protocol */
-
#include "inspircd.h"
#include "main.h"
#include "utils.h"
#include "treeserver.h"
-#include "treesocket.h"
-
-/* $ModDep: m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h */
+#include "commands.h"
-const std::string ModuleSpanningTree::MapOperInfo(TreeServer* Current)
+CommandMap::CommandMap(Module* Creator)
+ : Command(Creator, "MAP", 0, 1)
{
- time_t secs_up = ServerInstance->Time() - Current->age;
- return " [Up: " + TimeToStr(secs_up) + (Current->rtt == 0 ? "]" : " Lag: " + ConvToStr(Current->rtt) + "ms]");
+ Penalty = 2;
}
-void ModuleSpanningTree::ShowMap(TreeServer* Current, User* user, int depth, int &line, char* names, int &maxnamew, char* stats)
+static inline bool IsHidden(User* user, TreeServer* server)
{
- ServerInstance->Logs->Log("map",DEBUG,"ShowMap depth %d on line %d", depth, line);
- float percent;
-
- if (ServerInstance->Users->clientlist->size() == 0)
+ if (!user->IsOper())
{
- // If there are no users, WHO THE HELL DID THE /MAP?!?!?!
- percent = 0;
+ if (server->Hidden)
+ return true;
+ if (Utils->HideULines && server->IsULine())
+ return true;
}
- else
+
+ return false;
+}
+
+// Calculate the map depth the servers go, and the longest server name
+static void GetDepthAndLen(TreeServer* current, unsigned int depth, unsigned int& max_depth, unsigned int& max_len)
+{
+ if (depth > max_depth)
+ max_depth = depth;
+ if (current->GetName().length() > max_len)
+ max_len = current->GetName().length();
+
+ const TreeServer::ChildServers& servers = current->GetChildren();
+ for (TreeServer::ChildServers::const_iterator i = servers.begin(); i != servers.end(); ++i)
{
- percent = Current->GetUserCount() * 100.0 / ServerInstance->Users->clientlist->size();
+ TreeServer* child = *i;
+ GetDepthAndLen(child, depth + 1, max_depth, max_len);
}
+}
- const std::string operdata = IS_OPER(user) ? MapOperInfo(Current) : "";
-
- char* myname = names + 100 * line;
- char* mystat = stats + 50 * line;
- memset(myname, ' ', depth);
- int w = depth;
+static std::vector<std::string> GetMap(User* user, TreeServer* current, unsigned int max_len, unsigned int depth)
+{
+ float percent = 0;
- std::string servername = Current->GetName();
- if (IS_OPER(user))
+ const user_hash& users = ServerInstance->Users->GetUsers();
+ if (!users.empty())
{
- w += snprintf(myname + depth, 99 - depth, "%s (%s)", servername.c_str(), Current->GetID().c_str());
+ // If there are no users, WHO THE HELL DID THE /MAP?!?!?!
+ percent = current->UserCount * 100.0 / users.size();
}
- else
+
+ std::string buffer = current->GetName();
+ if (user->IsOper())
{
- w += snprintf(myname + depth, 99 - depth, "%s", servername.c_str());
+ buffer += " (" + current->GetID() + ")";
}
- memset(myname + w, ' ', 100 - w);
- if (w > maxnamew)
- maxnamew = w;
- snprintf(mystat, 49, "%5d [%5.2f%%]%s", Current->GetUserCount(), percent, operdata.c_str());
- line++;
+ // Pad with spaces until its at max len, max_len must always be >= my names length
+ buffer.append(max_len - current->GetName().length(), ' ');
- if (IS_OPER(user) || !Utils->FlatLinks)
- depth = depth + 2;
- for (unsigned int q = 0; q < Current->ChildCount(); q++)
+ char buf[16];
+ snprintf(buf, sizeof(buf), "%5d [%5.2f%%]", current->UserCount, percent);
+ buffer += buf;
+
+ if (user->IsOper())
{
- TreeServer* child = Current->GetChild(q);
- if (!IS_OPER(user)) {
- if (child->Hidden)
- continue;
- if ((Utils->HideULines) && (ServerInstance->ULine(child->GetName())))
- continue;
- }
- ShowMap(child, user, depth, line, names, maxnamew, stats);
+ time_t secs_up = ServerInstance->Time() - current->age;
+ buffer += " [Up: " + ModuleSpanningTree::TimeToStr(secs_up) + (current->rtt == 0 ? "]" : " Lag: " + ConvToStr(current->rtt) + "ms]");
}
-}
+ std::vector<std::string> map;
+ map.push_back(buffer);
-// Ok, prepare to be confused.
-// After much mulling over how to approach this, it struck me that
-// the 'usual' way of doing a /MAP isnt the best way. Instead of
-// keeping track of a ton of ascii characters, and line by line
-// under recursion working out where to place them using multiplications
-// and divisons, we instead render the map onto a backplane of characters
-// (a character matrix), then draw the branches as a series of "L" shapes
-// from the nodes. This is not only friendlier on CPU it uses less stack.
-bool ModuleSpanningTree::HandleMap(const std::vector<std::string>& parameters, User* user)
-{
- if (parameters.size() > 0)
+ const TreeServer::ChildServers& servers = current->GetChildren();
+ for (TreeServer::ChildServers::const_iterator i = servers.begin(); i != servers.end(); ++i)
{
- /* Remote MAP, the server is within the 1st parameter */
- TreeServer* s = Utils->FindServerMask(parameters[0]);
- bool ret = false;
- if (!s)
+ TreeServer* child = *i;
+
+ if (IsHidden(user, child))
+ continue;
+
+ bool last = true;
+ for (TreeServer::ChildServers::const_iterator j = i + 1; last && j != servers.end(); ++j)
+ if (!IsHidden(user, *j))
+ last = false;
+
+ unsigned int next_len;
+
+ if (user->IsOper() || !Utils->FlatLinks)
{
- user->WriteNumeric(ERR_NOSUCHSERVER, "%s %s :No such server", user->nick.c_str(), parameters[0].c_str());
- ret = true;
+ // This child is indented by us, so remove the depth from the max length to align the users properly
+ next_len = max_len - 2;
}
- else if (s && s != Utils->TreeRoot)
+ else
{
- parameterlist params;
- params.push_back(parameters[0]);
-
- params[0] = s->GetName();
- Utils->DoOneToOne(user->uuid, "MAP", params, s->GetName());
- ret = true;
+ // This user can not see depth, so max_len remains constant
+ next_len = max_len;
}
- // Don't return if s == Utils->TreeRoot (us)
- if (ret)
- return true;
- }
+ // Build the map for this child
+ std::vector<std::string> child_map = GetMap(user, child, next_len, depth + 1);
- // These arrays represent a virtual screen which we will
- // "scratch" draw to, as the console device of an irc
- // client does not provide for a proper terminal.
- int totusers = ServerInstance->Users->clientlist->size();
- int totservers = this->CountServs();
- int maxnamew = 0;
- int line = 0;
- char* names = new char[totservers * 100];
- char* stats = new char[totservers * 50];
-
- // The only recursive bit is called here.
- ShowMap(Utils->TreeRoot,user,0,line,names,maxnamew,stats);
-
- // Process each line one by one.
- for (int l = 1; l < line; l++)
- {
- char* myname = names + 100 * l;
- // scan across the line looking for the start of the
- // servername (the recursive part of the algorithm has placed
- // the servers at indented positions depending on what they
- // are related to)
- int first_nonspace = 0;
-
- while (myname[first_nonspace] == ' ')
+ for (std::vector<std::string>::const_iterator j = child_map.begin(); j != child_map.end(); ++j)
{
- first_nonspace++;
+ const char* prefix;
+
+ if (user->IsOper() || !Utils->FlatLinks)
+ {
+ // If this server is not the root child
+ if (j != child_map.begin())
+ {
+ // If this child is not my last child, then add |
+ // to be able to "link" the next server in my list to me, and to indent this childs servers
+ if (!last)
+ prefix = "| ";
+ // Otherwise this is my last child, so just use a space as theres nothing else linked to me below this
+ else
+ prefix = " ";
+ }
+ // If we get here, this server must be the root child
+ else
+ {
+ // If this is the last child, it gets a `-
+ if (last)
+ prefix = "`-";
+ // Otherwise this isn't the last child, so it gets |-
+ else
+ prefix = "|-";
+ }
+ }
+ else
+ // User can't see depth, so use no prefix
+ prefix = "";
+
+ // Add line to the map
+ map.push_back(prefix + *j);
}
+ }
- first_nonspace--;
-
- // Draw the `- (corner) section: this may be overwritten by
- // another L shape passing along the same vertical pane, becoming
- // a |- (branch) section instead.
-
- myname[first_nonspace] = '-';
- myname[first_nonspace-1] = '`';
- int l2 = l - 1;
+ return map;
+}
- // Draw upwards until we hit the parent server, causing possibly
- // other corners (`-) to become branches (|-)
- while ((names[l2 * 100 + first_nonspace-1] == ' ') || (names[l2 * 100 + first_nonspace-1] == '`'))
+CmdResult CommandMap::Handle(const std::vector<std::string>& parameters, User* user)
+{
+ if (parameters.size() > 0)
+ {
+ /* Remote MAP, the server is within the 1st parameter */
+ TreeServer* s = Utils->FindServerMask(parameters[0]);
+ if (!s)
{
- names[l2 * 100 + first_nonspace-1] = '|';
- l2--;
+ user->WriteNumeric(ERR_NOSUCHSERVER, "%s :No such server", parameters[0].c_str());
+ return CMD_FAILURE;
}
+
+ if (!s->IsRoot())
+ return CMD_SUCCESS;
}
- float avg_users = totusers * 1.0 / line;
+ // Max depth and max server name length
+ unsigned int max_depth = 0;
+ unsigned int max_len = 0;
+ GetDepthAndLen(Utils->TreeRoot, 0, max_depth, max_len);
- ServerInstance->Logs->Log("map",DEBUG,"local");
- for (int t = 0; t < line; t++)
+ unsigned int max;
+ if (user->IsOper() || !Utils->FlatLinks)
+ {
+ // Each level of the map is indented by 2 characters, making the max possible line (max_depth * 2) + max_len
+ max = (max_depth * 2) + max_len;
+ }
+ else
{
- // terminate the string at maxnamew characters
- names[100 * t + maxnamew] = '\0';
- user->SendText(":%s %03d %s :%s %s", ServerInstance->Config->ServerName.c_str(),
- RPL_MAP, user->nick.c_str(), names + 100 * t, stats + 50 * t);
+ // This user can't see any depth
+ max = max_len;
}
- user->SendText(":%s %03d %s :%d server%s and %d user%s, average %.2f users per server",
+
+ std::vector<std::string> map = GetMap(user, Utils->TreeRoot, max, 0);
+ for (std::vector<std::string>::const_iterator i = map.begin(); i != map.end(); ++i)
+ user->SendText(":%s %03d %s :%s", ServerInstance->Config->ServerName.c_str(),
+ RPL_MAP, user->nick.c_str(), i->c_str());
+
+ size_t totusers = ServerInstance->Users->GetUsers().size();
+ float avg_users = (float) totusers / Utils->serverlist.size();
+
+ user->SendText(":%s %03d %s :%u server%s and %u user%s, average %.2f users per server",
ServerInstance->Config->ServerName.c_str(), RPL_MAPUSERS, user->nick.c_str(),
- line, (line > 1 ? "s" : ""), totusers, (totusers > 1 ? "s" : ""), avg_users);
+ (unsigned int)Utils->serverlist.size(), (Utils->serverlist.size() > 1 ? "s" : ""), (unsigned int)totusers, (totusers > 1 ? "s" : ""), avg_users);
user->SendText(":%s %03d %s :End of /MAP", ServerInstance->Config->ServerName.c_str(),
RPL_ENDMAP, user->nick.c_str());
- delete[] names;
- delete[] stats;
-
- return true;
+ return CMD_SUCCESS;
}
+RouteDescriptor CommandMap::GetRouting(User* user, const std::vector<std::string>& parameters)
+{
+ if (!parameters.empty())
+ return ROUTE_UNICAST(parameters[0]);
+ return ROUTE_LOCALONLY;
+}
diff --git a/src/modules/m_spanningtree/override_squit.cpp b/src/modules/m_spanningtree/override_squit.cpp
index 7d01c8149..84cb01f50 100644
--- a/src/modules/m_spanningtree/override_squit.cpp
+++ b/src/modules/m_spanningtree/override_squit.cpp
@@ -17,48 +17,41 @@
*/
-/* $ModDesc: Provides a spanning tree server link protocol */
-
#include "inspircd.h"
#include "socket.h"
-#include "xline.h"
#include "main.h"
#include "utils.h"
#include "treeserver.h"
#include "treesocket.h"
-/* $ModDep: m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h */
-
ModResult ModuleSpanningTree::HandleSquit(const std::vector<std::string>& parameters, User* user)
{
TreeServer* s = Utils->FindServerMask(parameters[0]);
if (s)
{
- if (s == Utils->TreeRoot)
+ if (s->IsRoot())
{
- user->WriteServ("NOTICE %s :*** SQUIT: Foolish mortal, you cannot make a server SQUIT itself! (%s matches local server name)",user->nick.c_str(),parameters[0].c_str());
+ user->WriteNotice("*** SQUIT: Foolish mortal, you cannot make a server SQUIT itself! (" + parameters[0] + " matches local server name)");
return MOD_RES_DENY;
}
TreeSocket* sock = s->GetSocket();
- if (sock)
+ if (s->IsLocal())
{
ServerInstance->SNO->WriteToSnoMask('l',"SQUIT: Server \002%s\002 removed from network by %s",parameters[0].c_str(),user->nick.c_str());
sock->Squit(s,"Server quit by " + user->GetFullRealHost());
- ServerInstance->SE->DelFd(sock);
sock->Close();
}
else
{
- user->WriteServ("NOTICE %s :*** SQUIT may not be used to remove remote servers. Please use RSQUIT instead.",user->nick.c_str());
+ user->WriteNotice("*** SQUIT may not be used to remove remote servers. Please use RSQUIT instead.");
}
}
else
{
- user->WriteServ("NOTICE %s :*** SQUIT: The server \002%s\002 does not exist on the network.",user->nick.c_str(),parameters[0].c_str());
+ user->WriteNotice("*** SQUIT: The server \002" + parameters[0] + "\002 does not exist on the network.");
}
return MOD_RES_DENY;
}
-
diff --git a/src/modules/m_spanningtree/override_stats.cpp b/src/modules/m_spanningtree/override_stats.cpp
index 688661b80..14b3f5ef7 100644
--- a/src/modules/m_spanningtree/override_stats.cpp
+++ b/src/modules/m_spanningtree/override_stats.cpp
@@ -18,16 +18,11 @@
*/
-/* $ModDesc: Provides a spanning tree server link protocol */
-
#include "inspircd.h"
-#include "socket.h"
#include "main.h"
#include "utils.h"
-#include "treeserver.h"
#include "link.h"
-#include "treesocket.h"
ModResult ModuleSpanningTree::OnStats(char statschar, User* user, string_list &results)
{
@@ -36,12 +31,22 @@ ModResult ModuleSpanningTree::OnStats(char statschar, User* user, string_list &r
for (std::vector<reference<Link> >::iterator i = Utils->LinkBlocks.begin(); i != Utils->LinkBlocks.end(); ++i)
{
Link* L = *i;
- results.push_back(std::string(ServerInstance->Config->ServerName)+" 213 "+user->nick+" "+statschar+" *@"+(L->HiddenFromStats ? "<hidden>" : L->IPAddr)+" * "+(*i)->Name.c_str()+" "+ConvToStr(L->Port)+" "+(L->Hook.empty() ? "plaintext" : L->Hook));
+ results.push_back("213 "+user->nick+" "+statschar+" *@"+(L->HiddenFromStats ? "<hidden>" : L->IPAddr)+" * "+(*i)->Name.c_str()+" "+ConvToStr(L->Port)+" "+(L->Hook.empty() ? "plaintext" : L->Hook));
if (statschar == 'c')
- results.push_back(std::string(ServerInstance->Config->ServerName)+" 244 "+user->nick+" H * * "+L->Name.c_str());
+ results.push_back("244 "+user->nick+" H * * "+L->Name.c_str());
+ }
+ return MOD_RES_DENY;
+ }
+ else if (statschar == 'U')
+ {
+ ConfigTagList tags = ServerInstance->Config->ConfTags("uline");
+ for (ConfigIter i = tags.first; i != tags.second; ++i)
+ {
+ std::string name = i->second->getString("server");
+ if (!name.empty())
+ results.push_back("248 "+user->nick+" U "+name);
}
return MOD_RES_DENY;
}
return MOD_RES_PASSTHRU;
}
-
diff --git a/src/modules/m_spanningtree/override_whois.cpp b/src/modules/m_spanningtree/override_whois.cpp
index ad8c6a6ef..d7030e30a 100644
--- a/src/modules/m_spanningtree/override_whois.cpp
+++ b/src/modules/m_spanningtree/override_whois.cpp
@@ -16,19 +16,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
-/* $ModDesc: Provides a spanning tree server link protocol */
-
#include "inspircd.h"
-#include "socket.h"
-#include "xline.h"
#include "main.h"
-#include "utils.h"
-#include "treeserver.h"
-#include "treesocket.h"
-
-/* $ModDep: m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h */
+#include "commandbuilder.h"
ModResult ModuleSpanningTree::HandleRemoteWhois(const std::vector<std::string>& parameters, User* user)
{
@@ -37,18 +28,15 @@ ModResult ModuleSpanningTree::HandleRemoteWhois(const std::vector<std::string>&
User* remote = ServerInstance->FindNickOnly(parameters[1]);
if (remote && !IS_LOCAL(remote))
{
- parameterlist params;
- params.push_back(remote->uuid);
- Utils->DoOneToOne(user->uuid,"IDLE",params,remote->server);
+ CmdBuilder(user, "IDLE").push(remote->uuid).Unicast(remote);
return MOD_RES_DENY;
}
else if (!remote)
{
- user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[1].c_str());
- user->WriteNumeric(318, "%s %s :End of /WHOIS list.",user->nick.c_str(), parameters[1].c_str());
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", parameters[1].c_str());
+ user->WriteNumeric(RPL_ENDOFWHOIS, "%s :End of /WHOIS list.", parameters[1].c_str());
return MOD_RES_DENY;
}
}
return MOD_RES_PASSTHRU;
}
-
diff --git a/src/modules/m_spanningtree/ping.cpp b/src/modules/m_spanningtree/ping.cpp
index aec680b23..878f8af3a 100644
--- a/src/modules/m_spanningtree/ping.cpp
+++ b/src/modules/m_spanningtree/ping.cpp
@@ -18,44 +18,24 @@
#include "inspircd.h"
-#include "socket.h"
-#include "xline.h"
-#include "socketengine.h"
-#include "main.h"
#include "utils.h"
#include "treeserver.h"
-#include "treesocket.h"
-
-/* $ModDep: m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h */
+#include "commands.h"
+#include "utils.h"
-bool TreeSocket::LocalPing(const std::string &prefix, parameterlist &params)
+CmdResult CommandPing::Handle(User* user, std::vector<std::string>& params)
{
- if (params.size() < 1)
- return true;
- if (params.size() == 1)
- {
- std::string stufftobounce = params[0];
- this->WriteLine(":"+ServerInstance->Config->GetSID()+" PONG "+stufftobounce);
- return true;
- }
- else
+ if (params[0] == ServerInstance->Config->GetSID())
{
- std::string forwardto = params[1];
- if (forwardto == ServerInstance->Config->ServerName || forwardto == ServerInstance->Config->GetSID())
- {
- // this is a ping for us, send back PONG to the requesting server
- params[1] = params[0];
- params[0] = forwardto;
- Utils->DoOneToOne(ServerInstance->Config->GetSID(),"PONG",params,params[1]);
- }
- else
- {
- // not for us, pass it on :)
- Utils->DoOneToOne(prefix,"PING",params,forwardto);
- }
- return true;
+ // PING for us, reply with a PONG
+ CmdBuilder reply("PONG");
+ reply.push_back(user->uuid);
+ if (params.size() >= 2)
+ // If there is a second parameter, append it
+ reply.push_back(params[1]);
+
+ reply.Unicast(user);
}
+ return CMD_SUCCESS;
}
-
-
diff --git a/src/modules/m_spanningtree/pong.cpp b/src/modules/m_spanningtree/pong.cpp
index 5966d05d9..6a29163e4 100644
--- a/src/modules/m_spanningtree/pong.cpp
+++ b/src/modules/m_spanningtree/pong.cpp
@@ -18,65 +18,26 @@
#include "inspircd.h"
-#include "socket.h"
-#include "xline.h"
-#include "socketengine.h"
-#include "main.h"
#include "utils.h"
#include "treeserver.h"
-#include "treesocket.h"
-
-/* $ModDep: m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h */
+#include "commands.h"
+#include "utils.h"
-bool TreeSocket::LocalPong(const std::string &prefix, parameterlist &params)
+CmdResult CommandPong::HandleServer(TreeServer* server, std::vector<std::string>& params)
{
- if (params.size() < 1)
- return true;
-
- if (params.size() == 1)
+ if (server->bursting)
{
- TreeServer* ServerSource = Utils->FindServer(prefix);
- if (ServerSource)
- {
- ServerSource->SetPingFlag();
- long ts = ServerInstance->Time() * 1000 + (ServerInstance->Time_ns() / 1000000);
- ServerSource->rtt = ts - ServerSource->LastPingMsec;
- }
+ ServerInstance->SNO->WriteGlobalSno('l', "Server \002%s\002 has not finished burst, forcing end of burst (send ENDBURST!)", server->GetName().c_str());
+ server->FinishBurst();
}
- else
- {
- std::string forwardto = params[1];
- if (forwardto == ServerInstance->Config->GetSID() || forwardto == ServerInstance->Config->ServerName)
- {
- /*
- * this is a PONG for us
- * if the prefix is a user, check theyre local, and if they are,
- * dump the PONG reply back to their fd. If its a server, do nowt.
- * Services might want to send these s->s, but we dont need to yet.
- */
- User* u = ServerInstance->FindNick(prefix);
- if (u)
- {
- u->WriteServ("PONG %s %s",params[0].c_str(),params[1].c_str());
- }
- TreeServer *ServerSource = Utils->FindServer(params[0]);
-
- if (ServerSource)
- {
- long ts = ServerInstance->Time() * 1000 + (ServerInstance->Time_ns() / 1000000);
- ServerSource->rtt = ts - ServerSource->LastPingMsec;
- ServerSource->SetPingFlag();
- }
- }
- else
- {
- // not for us, pass it on :)
- Utils->DoOneToOne(prefix,"PONG",params,forwardto);
- }
+ if (params[0] == ServerInstance->Config->GetSID())
+ {
+ // PONG for us
+ long ts = ServerInstance->Time() * 1000 + (ServerInstance->Time_ns() / 1000000);
+ server->rtt = ts - server->LastPingMsec;
+ server->SetPingFlag();
}
-
- return true;
+ return CMD_SUCCESS;
}
-
diff --git a/src/modules/m_spanningtree/postcommand.cpp b/src/modules/m_spanningtree/postcommand.cpp
index 471bbfcb9..0695ce632 100644
--- a/src/modules/m_spanningtree/postcommand.cpp
+++ b/src/modules/m_spanningtree/postcommand.cpp
@@ -17,69 +17,53 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
-/* $ModDesc: Provides a spanning tree server link protocol */
-
#include "inspircd.h"
-#include "socket.h"
-#include "xline.h"
#include "main.h"
#include "utils.h"
#include "treeserver.h"
-#include "treesocket.h"
+#include "commandbuilder.h"
-/* $ModDep: m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h */
-
-void ModuleSpanningTree::OnPostCommand(const std::string &command, const std::vector<std::string>& parameters, LocalUser *user, CmdResult result, const std::string &original_line)
+void ModuleSpanningTree::OnPostCommand(Command* command, const std::vector<std::string>& parameters, LocalUser* user, CmdResult result, const std::string& original_line)
{
if (result == CMD_SUCCESS)
Utils->RouteCommand(NULL, command, parameters, user);
}
-void SpanningTreeUtilities::RouteCommand(TreeServer* origin, const std::string &command, const parameterlist& parameters, User *user)
+void SpanningTreeUtilities::RouteCommand(TreeServer* origin, CommandBase* thiscmd, const parameterlist& parameters, User* user)
{
- if (!ServerInstance->Parser->IsValidCommand(command, parameters.size(), user))
- return;
-
- /* We know it's non-null because IsValidCommand returned true */
- Command* thiscmd = ServerInstance->Parser->GetHandler(command);
-
+ const std::string& command = thiscmd->name;
RouteDescriptor routing = thiscmd->GetRouting(user, parameters);
-
- std::string sent_cmd = command;
- parameterlist params;
-
if (routing.type == ROUTE_TYPE_LOCALONLY)
- {
- /* Broadcast when it's a core command with the default route descriptor and the source is a
- * remote user or a remote server
- */
+ return;
- Version ver = thiscmd->creator->GetVersion();
- if ((!(ver.Flags & VF_CORE)) || (IS_LOCAL(user)) || (IS_SERVER(user) == ServerInstance->FakeClient))
- return;
+ const bool encap = ((routing.type == ROUTE_TYPE_OPT_BCAST) || (routing.type == ROUTE_TYPE_OPT_UCAST));
+ CmdBuilder params(user, encap ? "ENCAP" : command.c_str());
+ TreeServer* sdest = NULL;
- routing = ROUTE_BROADCAST;
- }
- else if (routing.type == ROUTE_TYPE_OPT_BCAST)
+ if (routing.type == ROUTE_TYPE_OPT_BCAST)
{
- params.push_back("*");
+ params.push('*');
params.push_back(command);
- sent_cmd = "ENCAP";
}
- else if (routing.type == ROUTE_TYPE_OPT_UCAST)
+ else if (routing.type == ROUTE_TYPE_UNICAST || routing.type == ROUTE_TYPE_OPT_UCAST)
{
- TreeServer* sdest = FindServer(routing.serverdest);
+ sdest = static_cast<TreeServer*>(routing.server);
if (!sdest)
{
- ServerInstance->Logs->Log("m_spanningtree",DEFAULT,"Trying to route ENCAP to nonexistant server %s",
- routing.serverdest.c_str());
- return;
+ sdest = FindServer(routing.serverdest);
+ if (!sdest)
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Trying to route %s%s to nonexistant server %s", (encap ? "ENCAP " : ""), command.c_str(), routing.serverdest.c_str());
+ return;
+ }
+ }
+
+ if (encap)
+ {
+ params.push_back(sdest->GetID());
+ params.push_back(command);
}
- params.push_back(sdest->GetID());
- params.push_back(command);
- sent_cmd = "ENCAP";
}
else
{
@@ -88,14 +72,13 @@ void SpanningTreeUtilities::RouteCommand(TreeServer* origin, const std::string &
if (!(ver.Flags & (VF_COMMON | VF_CORE)) && srcmodule != Creator)
{
- ServerInstance->Logs->Log("m_spanningtree",DEFAULT,"Routed command %s from non-VF_COMMON module %s",
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Routed command %s from non-VF_COMMON module %s",
command.c_str(), srcmodule->ModuleSourceFile.c_str());
return;
}
}
- std::string output_text;
- ServerInstance->Parser->TranslateUIDs(thiscmd->translation, parameters, output_text, true, thiscmd);
+ std::string output_text = CommandParser::TranslateUIDs(thiscmd->translation, parameters, true, thiscmd);
params.push_back(output_text);
@@ -113,52 +96,33 @@ void SpanningTreeUtilities::RouteCommand(TreeServer* origin, const std::string &
Channel* c = ServerInstance->FindChan(dest);
if (!c)
return;
- TreeServerList list;
// TODO OnBuildExemptList hook was here
- GetListOfServersForChannel(c,list,pfx, CUList());
- std::string data = ":" + user->uuid + " " + sent_cmd;
- for (unsigned int x = 0; x < params.size(); x++)
- data += " " + params[x];
- for (TreeServerList::iterator i = list.begin(); i != list.end(); i++)
- {
- TreeSocket* Sock = i->second->GetSocket();
- if (origin && origin->GetSocket() == Sock)
- continue;
- if (Sock)
- Sock->WriteLine(data);
- }
+ CUList exempts;
+ SendChannelMessage(user->uuid, c, parameters[1], pfx, exempts, command.c_str(), origin ? origin->GetSocket() : NULL);
}
else if (dest[0] == '$')
{
- if (origin)
- DoOneToAllButSender(user->uuid, sent_cmd, params, origin->GetName());
- else
- DoOneToMany(user->uuid, sent_cmd, params);
+ params.Forward(origin);
}
else
{
// user target?
User* d = ServerInstance->FindNick(dest);
- if (!d)
+ if (!d || IS_LOCAL(d))
return;
- TreeServer* tsd = BestRouteTo(d->server);
+ TreeServer* tsd = TreeServer::Get(d)->GetRoute();
if (tsd == origin)
// huh? no routing stuff around in a circle, please.
return;
- DoOneToOne(user->uuid, sent_cmd, params, d->server);
+ params.Unicast(d);
}
}
else if (routing.type == ROUTE_TYPE_BROADCAST || routing.type == ROUTE_TYPE_OPT_BCAST)
{
- if (origin)
- DoOneToAllButSender(user->uuid, sent_cmd, params, origin->GetName());
- else
- DoOneToMany(user->uuid, sent_cmd, params);
+ params.Forward(origin);
}
else if (routing.type == ROUTE_TYPE_UNICAST || routing.type == ROUTE_TYPE_OPT_UCAST)
{
- if (origin && routing.serverdest == origin->GetName())
- return;
- DoOneToOne(user->uuid, sent_cmd, params, routing.serverdest);
+ params.Unicast(sdest->ServerUser);
}
}
diff --git a/src/modules/m_spanningtree/precommand.cpp b/src/modules/m_spanningtree/precommand.cpp
index b331571ca..4733d0071 100644
--- a/src/modules/m_spanningtree/precommand.cpp
+++ b/src/modules/m_spanningtree/precommand.cpp
@@ -18,18 +18,9 @@
*/
-/* $ModDesc: Provides a spanning tree server link protocol */
-
#include "inspircd.h"
-#include "socket.h"
-#include "xline.h"
#include "main.h"
-#include "utils.h"
-#include "treeserver.h"
-#include "treesocket.h"
-
-/* $ModDep: m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h */
ModResult ModuleSpanningTree::OnPreCommand(std::string &command, std::vector<std::string>& parameters, LocalUser *user, bool validated, const std::string &original_line)
{
@@ -45,10 +36,6 @@ ModResult ModuleSpanningTree::OnPreCommand(std::string &command, std::vector<std
{
return this->HandleSquit(parameters,user);
}
- else if (command == "MAP")
- {
- return this->HandleMap(parameters,user) ? MOD_RES_DENY : MOD_RES_PASSTHRU;
- }
else if (command == "LINKS")
{
this->HandleLinks(parameters,user);
@@ -64,9 +51,7 @@ ModResult ModuleSpanningTree::OnPreCommand(std::string &command, std::vector<std
}
else if ((command == "VERSION") && (parameters.size() > 0))
{
- this->HandleVersion(parameters,user);
- return MOD_RES_DENY;
+ return this->HandleVersion(parameters,user);
}
return MOD_RES_PASSTHRU;
}
-
diff --git a/src/modules/m_spanningtree/protocolinterface.cpp b/src/modules/m_spanningtree/protocolinterface.cpp
index 3ab5dae9d..192f7cff2 100644
--- a/src/modules/m_spanningtree/protocolinterface.cpp
+++ b/src/modules/m_spanningtree/protocolinterface.cpp
@@ -19,161 +19,137 @@
#include "inspircd.h"
-#include "main.h"
#include "utils.h"
#include "treeserver.h"
-#include "treesocket.h"
#include "protocolinterface.h"
+#include "commands.h"
/*
* For documentation on this class, see include/protocol.h.
*/
-void SpanningTreeProtocolInterface::GetServerList(ProtoServerList &sl)
+void SpanningTreeProtocolInterface::GetServerList(ServerList& sl)
{
- sl.clear();
for (server_hash::iterator i = Utils->serverlist.begin(); i != Utils->serverlist.end(); i++)
{
- ProtoServer ps;
+ ServerInfo ps;
ps.servername = i->second->GetName();
TreeServer* s = i->second->GetParent();
ps.parentname = s ? s->GetName() : "";
- ps.usercount = i->second->GetUserCount();
- ps.opercount = i->second->GetOperCount();
+ ps.usercount = i->second->UserCount;
+ ps.opercount = i->second->OperCount;
ps.gecos = i->second->GetDesc();
ps.latencyms = i->second->rtt;
sl.push_back(ps);
}
}
-bool SpanningTreeProtocolInterface::SendEncapsulatedData(const parameterlist &encap)
+bool SpanningTreeProtocolInterface::SendEncapsulatedData(const std::string& targetmask, const std::string& cmd, const parameterlist& params, User* source)
{
- if (encap[0].find_first_of("*?") != std::string::npos)
- {
- Utils->DoOneToMany(ServerInstance->Config->GetSID(), "ENCAP", encap);
- return true;
- }
- return Utils->DoOneToOne(ServerInstance->Config->GetSID(), "ENCAP", encap, encap[0]);
-}
+ if (!source)
+ source = ServerInstance->FakeClient;
-void SpanningTreeProtocolInterface::SendMetaData(Extensible* target, const std::string &key, const std::string &data)
-{
- parameterlist params;
+ CmdBuilder encap(source, "ENCAP");
- User* u = dynamic_cast<User*>(target);
- Channel* c = dynamic_cast<Channel*>(target);
- if (u)
- params.push_back(u->uuid);
- else if (c)
- params.push_back(c->name);
+ // Are there any wildcards in the target string?
+ if (targetmask.find_first_of("*?") != std::string::npos)
+ {
+ // Yes, send the target string as-is; servers will decide whether or not it matches them
+ encap.push(targetmask).push(cmd).insert(params).Broadcast();
+ }
else
- params.push_back("*");
+ {
+ // No wildcards which means the target string has to be the name of a known server
+ TreeServer* server = Utils->FindServer(targetmask);
+ if (!server)
+ return false;
- params.push_back(key);
- params.push_back(":" + data);
+ // Use the SID of the target in the message instead of the server name
+ encap.push(server->GetID()).push(cmd).insert(params).Unicast(server->ServerUser);
+ }
- Utils->DoOneToMany(ServerInstance->Config->GetSID(),"METADATA",params);
+ return true;
}
-void SpanningTreeProtocolInterface::SendTopic(Channel* channel, std::string &topic)
+void SpanningTreeProtocolInterface::BroadcastEncap(const std::string& cmd, const parameterlist& params, User* source, User* omit)
{
- parameterlist params;
-
- params.push_back(channel->name);
- params.push_back(ConvToStr(ServerInstance->Time()));
- params.push_back(ServerInstance->Config->ServerName);
- params.push_back(":" + topic);
+ if (!source)
+ source = ServerInstance->FakeClient;
- Utils->DoOneToMany(ServerInstance->Config->GetSID(),"FTOPIC", params);
+ // If omit is non-NULL we pass the route belonging to the user to Forward(),
+ // otherwise we pass NULL, which is equivalent to Broadcast()
+ TreeServer* server = (omit ? TreeServer::Get(omit)->GetRoute() : NULL);
+ CmdBuilder(source, "ENCAP * ").push_raw(cmd).insert(params).Forward(server);
}
-void SpanningTreeProtocolInterface::SendMode(const std::string &target, const parameterlist &modedata, const std::vector<TranslateType> &translate)
+void SpanningTreeProtocolInterface::SendMetaData(User* u, const std::string& key, const std::string& data)
{
- if (modedata.empty())
- return;
-
- std::string outdata;
- ServerInstance->Parser->TranslateUIDs(translate, modedata, outdata);
-
- std::string uidtarget;
- ServerInstance->Parser->TranslateUIDs(TR_NICK, target, uidtarget);
+ CommandMetadata::Builder(u, key, data).Broadcast();
+}
- parameterlist outlist;
- outlist.push_back(uidtarget);
- outlist.push_back(outdata);
+void SpanningTreeProtocolInterface::SendMetaData(Channel* c, const std::string& key, const std::string& data)
+{
+ CommandMetadata::Builder(c, key, data).Broadcast();
+}
- User* a = ServerInstance->FindNick(uidtarget);
- if (a)
- {
- Utils->DoOneToMany(ServerInstance->Config->GetSID(),"MODE",outlist);
- return;
- }
- else
- {
- Channel* c = ServerInstance->FindChan(target);
- if (c)
- {
- outlist.insert(outlist.begin() + 1, ConvToStr(c->age));
- Utils->DoOneToMany(ServerInstance->Config->GetSID(),"FMODE",outlist);
- }
- }
+void SpanningTreeProtocolInterface::SendMetaData(const std::string& key, const std::string& data)
+{
+ CommandMetadata::Builder(key, data).Broadcast();
}
-void SpanningTreeProtocolInterface::SendSNONotice(const std::string &snomask, const std::string &text)
+void SpanningTreeProtocolInterface::Server::SendMetaData(const std::string& key, const std::string& data)
{
- parameterlist p;
- p.push_back(snomask);
- p.push_back(":" + text);
- Utils->DoOneToMany(ServerInstance->Config->GetSID(), "SNONOTICE", p);
+ sock->WriteLine(CommandMetadata::Builder(key, data));
}
-void SpanningTreeProtocolInterface::PushToClient(User* target, const std::string &rawline)
+void SpanningTreeProtocolInterface::SendTopic(Channel* channel, std::string &topic)
{
- parameterlist p;
- p.push_back(target->uuid);
- p.push_back(":" + rawline);
- Utils->DoOneToOne(ServerInstance->Config->GetSID(), "PUSH", p, target->server);
+ CommandFTopic::Builder(ServerInstance->FakeClient, channel).Broadcast();
}
-void SpanningTreeProtocolInterface::SendChannel(Channel* target, char status, const std::string &text)
+void SpanningTreeProtocolInterface::SendMode(User* source, User* u, Channel* c, const std::vector<std::string>& modedata, const std::vector<TranslateType>& translate)
{
- std::string cname = target->name;
- if (status)
- cname = status + cname;
- TreeServerList list;
- CUList exempt_list;
- Utils->GetListOfServersForChannel(target,list,status,exempt_list);
- for (TreeServerList::iterator i = list.begin(); i != list.end(); i++)
+ if (u)
{
- TreeSocket* Sock = i->second->GetSocket();
- if (Sock)
- Sock->WriteLine(text);
+ if (u->registered != REG_ALL)
+ return;
+
+ CmdBuilder params(source, "MODE");
+ params.push_back(u->uuid);
+ params.insert(modedata);
+ params.Broadcast();
+ }
+ else
+ {
+ CmdBuilder params(source, "FMODE");
+ params.push_back(c->name);
+ params.push_back(ConvToStr(c->age));
+ params.push_back(CommandParser::TranslateUIDs(translate, modedata));
+ params.Broadcast();
}
}
-
-void SpanningTreeProtocolInterface::SendChannelPrivmsg(Channel* target, char status, const std::string &text)
+void SpanningTreeProtocolInterface::SendSNONotice(char snomask, const std::string &text)
{
- SendChannel(target, status, ":" + ServerInstance->Config->GetSID()+" PRIVMSG "+target->name+" :"+text);
+ CmdBuilder("SNONOTICE").push(snomask).push_last(text).Broadcast();
}
-void SpanningTreeProtocolInterface::SendChannelNotice(Channel* target, char status, const std::string &text)
+void SpanningTreeProtocolInterface::PushToClient(User* target, const std::string &rawline)
{
- SendChannel(target, status, ":" + ServerInstance->Config->GetSID()+" NOTICE "+target->name+" :"+text);
+ CmdBuilder("PUSH").push(target->uuid).push_last(rawline).Unicast(target);
}
-void SpanningTreeProtocolInterface::SendUserPrivmsg(User* target, const std::string &text)
+void SpanningTreeProtocolInterface::SendMessage(Channel* target, char status, const std::string& text, MessageType msgtype)
{
- parameterlist p;
- p.push_back(target->uuid);
- p.push_back(":" + text);
- Utils->DoOneToOne(ServerInstance->Config->GetSID(), "PRIVMSG", p, target->server);
+ const char* cmd = (msgtype == MSG_PRIVMSG ? "PRIVMSG" : "NOTICE");
+ CUList exempt_list;
+ Utils->SendChannelMessage(ServerInstance->Config->GetSID(), target, text, status, exempt_list, cmd);
}
-void SpanningTreeProtocolInterface::SendUserNotice(User* target, const std::string &text)
+void SpanningTreeProtocolInterface::SendMessage(User* target, const std::string& text, MessageType msgtype)
{
- parameterlist p;
+ CmdBuilder p(msgtype == MSG_PRIVMSG ? "PRIVMSG" : "NOTICE");
p.push_back(target->uuid);
- p.push_back(":" + text);
- Utils->DoOneToOne(ServerInstance->Config->GetSID(), "NOTICE", p, target->server);
+ p.push_last(text);
+ p.Unicast(target);
}
diff --git a/src/modules/m_spanningtree/protocolinterface.h b/src/modules/m_spanningtree/protocolinterface.h
index 297366893..97648f4b4 100644
--- a/src/modules/m_spanningtree/protocolinterface.h
+++ b/src/modules/m_spanningtree/protocolinterface.h
@@ -17,32 +17,30 @@
*/
-#ifndef M_SPANNINGTREE_PROTOCOLINTERFACE_H
-#define M_SPANNINGTREE_PROTOCOLINTERFACE_H
-
-class SpanningTreeUtilities;
-class ModuleSpanningTree;
+#pragma once
class SpanningTreeProtocolInterface : public ProtocolInterface
{
- SpanningTreeUtilities* Utils;
- void SendChannel(Channel* target, char status, const std::string &text);
public:
- SpanningTreeProtocolInterface(SpanningTreeUtilities* util) : Utils(util) { }
- virtual ~SpanningTreeProtocolInterface() { }
-
- virtual bool SendEncapsulatedData(const parameterlist &encap);
- virtual void SendMetaData(Extensible* target, const std::string &key, const std::string &data);
- virtual void SendTopic(Channel* channel, std::string &topic);
- virtual void SendMode(const std::string &target, const parameterlist &modedata, const std::vector<TranslateType> &types);
- virtual void SendSNONotice(const std::string &snomask, const std::string &text);
- virtual void PushToClient(User* target, const std::string &rawline);
- virtual void SendChannelPrivmsg(Channel* target, char status, const std::string &text);
- virtual void SendChannelNotice(Channel* target, char status, const std::string &text);
- virtual void SendUserPrivmsg(User* target, const std::string &text);
- virtual void SendUserNotice(User* target, const std::string &text);
- virtual void GetServerList(ProtoServerList &sl);
-};
+ class Server : public ProtocolInterface::Server
+ {
+ TreeSocket* const sock;
-#endif
+ public:
+ Server(TreeSocket* s) : sock(s) { }
+ void SendMetaData(const std::string& key, const std::string& data) CXX11_OVERRIDE;
+ };
+ bool SendEncapsulatedData(const std::string& targetmask, const std::string& cmd, const parameterlist& params, User* source) CXX11_OVERRIDE;
+ void BroadcastEncap(const std::string& cmd, const parameterlist& params, User* source, User* omit) CXX11_OVERRIDE;
+ void SendMetaData(User* user, const std::string& key, const std::string& data) CXX11_OVERRIDE;
+ void SendMetaData(Channel* chan, const std::string& key, const std::string& data) CXX11_OVERRIDE;
+ void SendMetaData(const std::string& key, const std::string& data) CXX11_OVERRIDE;
+ void SendTopic(Channel* channel, std::string &topic);
+ void SendMode(User* source, User* usertarget, Channel* chantarget, const parameterlist& modedata, const std::vector<TranslateType>& types);
+ void SendSNONotice(char snomask, const std::string& text) CXX11_OVERRIDE;
+ void PushToClient(User* target, const std::string &rawline);
+ void SendMessage(Channel* target, char status, const std::string& text, MessageType msgtype);
+ void SendMessage(User* target, const std::string& text, MessageType msgtype);
+ void GetServerList(ServerList& sl);
+};
diff --git a/src/modules/m_spanningtree/push.cpp b/src/modules/m_spanningtree/push.cpp
index b791376ea..b29b780c8 100644
--- a/src/modules/m_spanningtree/push.cpp
+++ b/src/modules/m_spanningtree/push.cpp
@@ -18,34 +18,18 @@
#include "inspircd.h"
-#include "socket.h"
-#include "xline.h"
-#include "socketengine.h"
-#include "main.h"
#include "utils.h"
-#include "treeserver.h"
-#include "treesocket.h"
+#include "commands.h"
-/* $ModDep: m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h */
-
-bool TreeSocket::Push(const std::string &prefix, parameterlist &params)
+CmdResult CommandPush::Handle(User* user, std::vector<std::string>& params)
{
- if (params.size() < 2)
- return true;
User* u = ServerInstance->FindNick(params[0]);
if (!u)
- return true;
+ return CMD_FAILURE;
if (IS_LOCAL(u))
{
u->Write(params[1]);
}
- else
- {
- // continue the raw onwards
- params[1] = ":" + params[1];
- Utils->DoOneToOne(prefix,"PUSH",params,u->server);
- }
- return true;
+ return CMD_SUCCESS;
}
-
diff --git a/src/modules/m_spanningtree/rconnect.cpp b/src/modules/m_spanningtree/rconnect.cpp
index d4254cac6..c5d3a5b52 100644
--- a/src/modules/m_spanningtree/rconnect.cpp
+++ b/src/modules/m_spanningtree/rconnect.cpp
@@ -19,19 +19,13 @@
#include "inspircd.h"
-#include "socket.h"
-#include "xline.h"
-#include "resolvers.h"
#include "main.h"
#include "utils.h"
-#include "treeserver.h"
-#include "link.h"
-#include "treesocket.h"
#include "commands.h"
-CommandRConnect::CommandRConnect (Module* Creator, SpanningTreeUtilities* Util)
- : Command(Creator, "RCONNECT", 2), Utils(Util)
+CommandRConnect::CommandRConnect (Module* Creator)
+ : Command(Creator, "RCONNECT", 2)
{
flags_needed = 'o';
syntax = "<remote-server-mask> <target-server-mask>";
@@ -39,14 +33,11 @@ CommandRConnect::CommandRConnect (Module* Creator, SpanningTreeUtilities* Util)
CmdResult CommandRConnect::Handle (const std::vector<std::string>& parameters, User *user)
{
- if (IS_LOCAL(user))
+ /* First see if the server which is being asked to connect to another server in fact exists */
+ if (!Utils->FindServerMask(parameters[0]))
{
- if (!Utils->FindServerMask(parameters[0]))
- {
- user->WriteServ("NOTICE %s :*** RCONNECT: Server \002%s\002 isn't connected to the network!", user->nick.c_str(), parameters[0].c_str());
- return CMD_FAILURE;
- }
- user->WriteServ("NOTICE %s :*** RCONNECT: Sending remote connect to \002%s\002 to connect server \002%s\002.",user->nick.c_str(),parameters[0].c_str(),parameters[1].c_str());
+ ((ModuleSpanningTree*)(Module*)creator)->RemoteMessage(user, "*** RCONNECT: Server \002%s\002 isn't connected to the network!", parameters[0].c_str());
+ return CMD_FAILURE;
}
/* Is this aimed at our server? */
@@ -58,6 +49,21 @@ CmdResult CommandRConnect::Handle (const std::vector<std::string>& parameters, U
para.push_back(parameters[1]);
((ModuleSpanningTree*)(Module*)creator)->HandleConnect(para, user);
}
+ else
+ {
+ /* It's not aimed at our server, but if the request originates from our user
+ * acknowledge that we sent the request.
+ *
+ * It's possible that we're asking a server for something that makes no sense
+ * (e.g. connect to itself or to an already connected server), but we don't check
+ * for those conditions here, as ModuleSpanningTree::HandleConnect() (which will run
+ * on the target) does all the checking and error reporting.
+ */
+ if (IS_LOCAL(user))
+ {
+ user->WriteNotice("*** RCONNECT: Sending remote connect to \002 " + parameters[0] + "\002 to connect server \002" + parameters[1] + "\002.");
+ }
+ }
return CMD_SUCCESS;
}
diff --git a/src/modules/m_spanningtree/resolvers.cpp b/src/modules/m_spanningtree/resolvers.cpp
index d7c4c5227..3d04a5085 100644
--- a/src/modules/m_spanningtree/resolvers.cpp
+++ b/src/modules/m_spanningtree/resolvers.cpp
@@ -19,9 +19,8 @@
#include "inspircd.h"
-#include "socket.h"
-#include "xline.h"
+#include "cachetimer.h"
#include "resolvers.h"
#include "main.h"
#include "utils.h"
@@ -29,21 +28,22 @@
#include "link.h"
#include "treesocket.h"
-/* $ModDep: m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h */
-
/** This class is used to resolve server hostnames during /connect and autoconnect.
* As of 1.1, the resolver system is seperated out from BufferedSocket, so we must do this
* resolver step first ourselves if we need it. This is totally nonblocking, and will
* callback to OnLookupComplete or OnError when completed. Once it has completed we
* will have an IP address which we can then use to continue our connection.
*/
-ServernameResolver::ServernameResolver(SpanningTreeUtilities* Util, const std::string &hostname, Link* x, bool &cached, QueryType qt, Autoconnect* myac)
- : Resolver(hostname, qt, cached, Util->Creator), Utils(Util), query(qt), host(hostname), MyLink(x), myautoconnect(myac)
+ServernameResolver::ServernameResolver(DNS::Manager* mgr, const std::string& hostname, Link* x, DNS::QueryType qt, Autoconnect* myac)
+ : DNS::Request(mgr, Utils->Creator, hostname, qt)
+ , query(qt), host(hostname), MyLink(x), myautoconnect(myac)
{
}
-void ServernameResolver::OnLookupComplete(const std::string &result, unsigned int ttl, bool cached)
+void ServernameResolver::OnLookupComplete(const DNS::Query *r)
{
+ const DNS::ResourceRecord &ans_record = r->answers[0];
+
/* Initiate the connection, now that we have an IP to use.
* Passing a hostname directly to BufferedSocket causes it to
* just bail and set its FD to -1.
@@ -51,7 +51,7 @@ void ServernameResolver::OnLookupComplete(const std::string &result, unsigned in
TreeServer* CheckDupe = Utils->FindServer(MyLink->Name.c_str());
if (!CheckDupe) /* Check that nobody tried to connect it successfully while we were resolving */
{
- TreeSocket* newsocket = new TreeSocket(Utils, MyLink, myautoconnect, result);
+ TreeSocket* newsocket = new TreeSocket(MyLink, myautoconnect, ans_record.rdata);
if (newsocket->GetFd() > -1)
{
/* We're all OK */
@@ -66,47 +66,74 @@ void ServernameResolver::OnLookupComplete(const std::string &result, unsigned in
}
}
-void ServernameResolver::OnError(ResolverError e, const std::string &errormessage)
+void ServernameResolver::OnError(const DNS::Query *r)
{
/* Ooops! */
- if (query == DNS_QUERY_AAAA)
+ if (query == DNS::QUERY_AAAA)
{
- bool cached = false;
- ServernameResolver* snr = new ServernameResolver(Utils, host, MyLink, cached, DNS_QUERY_A, myautoconnect);
- ServerInstance->AddResolver(snr, cached);
- return;
+ ServernameResolver* snr = new ServernameResolver(this->manager, host, MyLink, DNS::QUERY_A, myautoconnect);
+ try
+ {
+ this->manager->Process(snr);
+ return;
+ }
+ catch (DNS::Exception &)
+ {
+ delete snr;
+ }
}
- ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: Unable to resolve hostname - %s", MyLink->Name.c_str(), errormessage.c_str() );
+
+ ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: Unable to resolve hostname - %s", MyLink->Name.c_str(), this->manager->GetErrorStr(r->error).c_str());
Utils->Creator->ConnectServer(myautoconnect, false);
}
-SecurityIPResolver::SecurityIPResolver(Module* me, SpanningTreeUtilities* U, const std::string &hostname, Link* x, bool &cached, QueryType qt)
- : Resolver(hostname, qt, cached, me), MyLink(x), Utils(U), mine(me), host(hostname), query(qt)
+SecurityIPResolver::SecurityIPResolver(Module* me, DNS::Manager* mgr, const std::string& hostname, Link* x, DNS::QueryType qt)
+ : DNS::Request(mgr, me, hostname, qt)
+ , MyLink(x), mine(me), host(hostname), query(qt)
{
}
-void SecurityIPResolver::OnLookupComplete(const std::string &result, unsigned int ttl, bool cached)
+void SecurityIPResolver::OnLookupComplete(const DNS::Query *r)
{
+ const DNS::ResourceRecord &ans_record = r->answers[0];
+
for (std::vector<reference<Link> >::iterator i = Utils->LinkBlocks.begin(); i != Utils->LinkBlocks.end(); ++i)
{
Link* L = *i;
if (L->IPAddr == host)
{
- Utils->ValidIPs.push_back(result);
+ Utils->ValidIPs.push_back(ans_record.rdata);
break;
}
}
}
-void SecurityIPResolver::OnError(ResolverError e, const std::string &errormessage)
+void SecurityIPResolver::OnError(const DNS::Query *r)
{
- if (query == DNS_QUERY_AAAA)
+ if (query == DNS::QUERY_AAAA)
{
- bool cached = false;
- SecurityIPResolver* res = new SecurityIPResolver(mine, Utils, host, MyLink, cached, DNS_QUERY_A);
- ServerInstance->AddResolver(res, cached);
- return;
+ SecurityIPResolver* res = new SecurityIPResolver(mine, this->manager, host, MyLink, DNS::QUERY_A);
+ try
+ {
+ this->manager->Process(res);
+ return;
+ }
+ catch (DNS::Exception &)
+ {
+ delete res;
+ }
}
- ServerInstance->Logs->Log("m_spanningtree",DEFAULT,"Could not resolve IP associated with Link '%s': %s",
- MyLink->Name.c_str(),errormessage.c_str());
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Could not resolve IP associated with Link '%s': %s",
+ MyLink->Name.c_str(), this->manager->GetErrorStr(r->error).c_str());
+}
+
+CacheRefreshTimer::CacheRefreshTimer()
+ : Timer(3600, true)
+{
+}
+
+bool CacheRefreshTimer::Tick(time_t TIME)
+{
+ Utils->RefreshIPCache();
+ return true;
}
diff --git a/src/modules/m_spanningtree/resolvers.h b/src/modules/m_spanningtree/resolvers.h
index 65b9e7249..782ac86ef 100644
--- a/src/modules/m_spanningtree/resolvers.h
+++ b/src/modules/m_spanningtree/resolvers.h
@@ -18,30 +18,27 @@
*/
-#ifndef M_SPANNINGTREE_RESOLVERS_H
-#define M_SPANNINGTREE_RESOLVERS_H
+#pragma once
-#include "socket.h"
#include "inspircd.h"
-#include "xline.h"
+#include "modules/dns.h"
#include "utils.h"
#include "link.h"
/** Handle resolving of server IPs for the cache
*/
-class SecurityIPResolver : public Resolver
+class SecurityIPResolver : public DNS::Request
{
private:
reference<Link> MyLink;
- SpanningTreeUtilities* Utils;
Module* mine;
std::string host;
- QueryType query;
+ DNS::QueryType query;
public:
- SecurityIPResolver(Module* me, SpanningTreeUtilities* U, const std::string &hostname, Link* x, bool &cached, QueryType qt);
- void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached);
- void OnError(ResolverError e, const std::string &errormessage);
+ SecurityIPResolver(Module* me, DNS::Manager* mgr, const std::string& hostname, Link* x, DNS::QueryType qt);
+ void OnLookupComplete(const DNS::Query *r) CXX11_OVERRIDE;
+ void OnError(const DNS::Query *q) CXX11_OVERRIDE;
};
/** This class is used to resolve server hostnames during /connect and autoconnect.
@@ -50,18 +47,15 @@ class SecurityIPResolver : public Resolver
* callback to OnLookupComplete or OnError when completed. Once it has completed we
* will have an IP address which we can then use to continue our connection.
*/
-class ServernameResolver : public Resolver
+class ServernameResolver : public DNS::Request
{
private:
- SpanningTreeUtilities* Utils;
- QueryType query;
+ DNS::QueryType query;
std::string host;
reference<Link> MyLink;
reference<Autoconnect> myautoconnect;
public:
- ServernameResolver(SpanningTreeUtilities* Util, const std::string &hostname, Link* x, bool &cached, QueryType qt, Autoconnect* myac);
- void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached);
- void OnError(ResolverError e, const std::string &errormessage);
+ ServernameResolver(DNS::Manager* mgr, const std::string& hostname, Link* x, DNS::QueryType qt, Autoconnect* myac);
+ void OnLookupComplete(const DNS::Query *r) CXX11_OVERRIDE;
+ void OnError(const DNS::Query *q) CXX11_OVERRIDE;
};
-
-#endif
diff --git a/src/modules/m_spanningtree/rsquit.cpp b/src/modules/m_spanningtree/rsquit.cpp
index 027ae02ab..988918c3f 100644
--- a/src/modules/m_spanningtree/rsquit.cpp
+++ b/src/modules/m_spanningtree/rsquit.cpp
@@ -19,17 +19,14 @@
#include "inspircd.h"
-#include "socket.h"
-#include "xline.h"
#include "main.h"
#include "utils.h"
#include "treeserver.h"
-#include "treesocket.h"
#include "commands.h"
-CommandRSQuit::CommandRSQuit (Module* Creator, SpanningTreeUtilities* Util)
- : Command(Creator, "RSQUIT", 1), Utils(Util)
+CommandRSQuit::CommandRSQuit(Module* Creator)
+ : Command(Creator, "RSQUIT", 1)
{
flags_needed = 'o';
syntax = "<target-server-mask> [reason]";
@@ -38,34 +35,28 @@ CommandRSQuit::CommandRSQuit (Module* Creator, SpanningTreeUtilities* Util)
CmdResult CommandRSQuit::Handle (const std::vector<std::string>& parameters, User *user)
{
TreeServer *server_target; // Server to squit
- TreeServer *server_linked; // Server target is linked to
server_target = Utils->FindServerMask(parameters[0]);
if (!server_target)
{
- user->WriteServ("NOTICE %s :*** RSQUIT: Server \002%s\002 isn't connected to the network!", user->nick.c_str(), parameters[0].c_str());
+ ((ModuleSpanningTree*)(Module*)creator)->RemoteMessage(user, "*** RSQUIT: Server \002%s\002 isn't connected to the network!", parameters[0].c_str());
return CMD_FAILURE;
}
- if (server_target == Utils->TreeRoot)
+ if (server_target->IsRoot())
{
- NoticeUser(user, "*** RSQUIT: Foolish mortal, you cannot make a server SQUIT itself! ("+parameters[0]+" matches local server name)");
+ ((ModuleSpanningTree*)(Module*)creator)->RemoteMessage(user, "*** RSQUIT: Foolish mortal, you cannot make a server SQUIT itself! (%s matches local server name)", parameters[0].c_str());
return CMD_FAILURE;
}
- server_linked = server_target->GetParent();
-
- if (server_linked == Utils->TreeRoot)
+ if (server_target->IsLocal())
{
// We have been asked to remove server_target.
TreeSocket* sock = server_target->GetSocket();
- if (sock)
- {
- const char *reason = parameters.size() == 2 ? parameters[1].c_str() : "No reason";
- ServerInstance->SNO->WriteToSnoMask('l',"RSQUIT: Server \002%s\002 removed from network by %s (%s)", parameters[0].c_str(), user->nick.c_str(), reason);
- sock->Squit(server_target, "Server quit by " + user->GetFullRealHost() + " (" + reason + ")");
- sock->Close();
- }
+ const char* reason = parameters.size() == 2 ? parameters[1].c_str() : "No reason";
+ ServerInstance->SNO->WriteToSnoMask('l',"RSQUIT: Server \002%s\002 removed from network by %s (%s)", parameters[0].c_str(), user->nick.c_str(), reason);
+ sock->Squit(server_target, "Server quit by " + user->GetFullRealHost() + " (" + reason + ")");
+ sock->Close();
}
return CMD_SUCCESS;
@@ -75,20 +66,3 @@ RouteDescriptor CommandRSQuit::GetRouting(User* user, const std::vector<std::str
{
return ROUTE_UNICAST(parameters[0]);
}
-
-// XXX use protocol interface instead of rolling our own :)
-void CommandRSQuit::NoticeUser(User* user, const std::string &msg)
-{
- if (IS_LOCAL(user))
- {
- user->WriteServ("NOTICE %s :%s",user->nick.c_str(),msg.c_str());
- }
- else
- {
- parameterlist params;
- params.push_back(user->nick);
- params.push_back("NOTICE "+ConvToStr(user->nick)+" :"+msg);
- Utils->DoOneToOne(ServerInstance->Config->GetSID(), "PUSH", params, user->server);
- }
-}
-
diff --git a/src/modules/m_spanningtree/save.cpp b/src/modules/m_spanningtree/save.cpp
index 92999b422..75fdd478c 100644
--- a/src/modules/m_spanningtree/save.cpp
+++ b/src/modules/m_spanningtree/save.cpp
@@ -18,38 +18,24 @@
#include "inspircd.h"
-#include "socket.h"
-#include "xline.h"
-#include "socketengine.h"
-#include "main.h"
#include "utils.h"
-#include "treeserver.h"
#include "treesocket.h"
-
-/* $ModDep: m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h */
+#include "commands.h"
/**
* SAVE command - force nick change to UID on timestamp match
*/
-bool TreeSocket::ForceNick(const std::string &prefix, parameterlist &params)
+CmdResult CommandSave::Handle(User* user, std::vector<std::string>& params)
{
- if (params.size() < 2)
- return true;
-
User* u = ServerInstance->FindNick(params[0]);
- time_t ts = atol(params[1].c_str());
+ if ((!u) || (IS_SERVER(u)))
+ return CMD_FAILURE;
- if ((u) && (!IS_SERVER(u)) && (u->age == ts))
- {
- Utils->DoOneToAllButSender(prefix,"SAVE",params,prefix);
+ time_t ts = atol(params[1].c_str());
- if (!u->ForceNickChange(u->uuid.c_str()))
- {
- ServerInstance->Users->QuitUser(u, "Nickname collision");
- }
- }
+ if (u->age == ts)
+ u->ChangeNick(u->uuid);
- return true;
+ return CMD_SUCCESS;
}
-
diff --git a/src/modules/m_spanningtree/server.cpp b/src/modules/m_spanningtree/server.cpp
index d3033799e..f232d57d6 100644
--- a/src/modules/m_spanningtree/server.cpp
+++ b/src/modules/m_spanningtree/server.cpp
@@ -19,72 +19,55 @@
#include "inspircd.h"
-#include "socket.h"
-#include "xline.h"
-#include "socketengine.h"
#include "main.h"
#include "utils.h"
#include "link.h"
#include "treeserver.h"
#include "treesocket.h"
-
-/* $ModDep: m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h m_spanningtree/link.h */
+#include "commands.h"
/*
* Some server somewhere in the network introducing another server.
* -- w
*/
-bool TreeSocket::RemoteServer(const std::string &prefix, parameterlist &params)
+CmdResult CommandServer::HandleServer(TreeServer* ParentOfThis, std::vector<std::string>& params)
{
- if (params.size() < 5)
- {
- SendError("Protocol error - Not enough parameters for SERVER command");
- return false;
- }
-
std::string servername = params[0];
// password is not used for a remote server
// hopcount is not used (ever)
std::string sid = params[3];
std::string description = params[4];
- TreeServer* ParentOfThis = Utils->FindServer(prefix);
+ TreeSocket* socket = ParentOfThis->GetSocket();
- if (!ParentOfThis)
+ if (!InspIRCd::IsSID(sid))
{
- this->SendError("Protocol error - Introduced remote server from unknown server "+prefix);
- return false;
- }
- if (!ServerInstance->IsSID(sid))
- {
- this->SendError("Invalid format server ID: "+sid+"!");
- return false;
+ socket->SendError("Invalid format server ID: "+sid+"!");
+ return CMD_FAILURE;
}
TreeServer* CheckDupe = Utils->FindServer(servername);
if (CheckDupe)
{
- this->SendError("Server "+servername+" already exists!");
+ socket->SendError("Server "+servername+" already exists!");
ServerInstance->SNO->WriteToSnoMask('L', "Server \2"+CheckDupe->GetName()+"\2 being introduced from \2" + ParentOfThis->GetName() + "\2 denied, already exists. Closing link with " + ParentOfThis->GetName());
- return false;
+ return CMD_FAILURE;
}
CheckDupe = Utils->FindServer(sid);
if (CheckDupe)
{
- this->SendError("Server ID "+sid+" already exists! You may want to specify the server ID for the server manually with <server:id> so they do not conflict.");
+ socket->SendError("Server ID "+sid+" already exists! You may want to specify the server ID for the server manually with <server:id> so they do not conflict.");
ServerInstance->SNO->WriteToSnoMask('L', "Server \2"+servername+"\2 being introduced from \2" + ParentOfThis->GetName() + "\2 denied, server ID already exists on the network. Closing link with " + ParentOfThis->GetName());
- return false;
+ return CMD_FAILURE;
}
Link* lnk = Utils->FindLink(servername);
- TreeServer *Node = new TreeServer(Utils, servername, description, sid, ParentOfThis,NULL, lnk ? lnk->Hidden : false);
+ TreeServer* Node = new TreeServer(servername, description, sid, ParentOfThis, ParentOfThis->GetSocket(), lnk ? lnk->Hidden : false);
ParentOfThis->AddChild(Node);
- params[4] = ":" + params[4];
- Utils->DoOneToAllButSender(prefix,"SERVER",params,prefix);
ServerInstance->SNO->WriteToSnoMask('L', "Server \002"+ParentOfThis->GetName()+"\002 introduced server \002"+servername+"\002 ("+description+")");
- return true;
+ return CMD_SUCCESS;
}
@@ -105,17 +88,9 @@ bool TreeSocket::Outbound_Reply_Server(parameterlist &params)
std::string password = params[1];
std::string sid = params[3];
std::string description = params[4];
- int hops = atoi(params[2].c_str());
this->SendCapabilities(2);
- if (hops)
- {
- this->SendError("Server too far away for authentication");
- ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server is too far away for authentication");
- return false;
- }
-
if (!ServerInstance->IsSID(sid))
{
this->SendError("Invalid format server ID: "+sid+"!");
@@ -163,15 +138,12 @@ bool TreeSocket::Outbound_Reply_Server(parameterlist &params)
Utils->timeoutlist.erase(this);
linkID = sname;
- MyRoot = new TreeServer(Utils, sname, description, sid, Utils->TreeRoot, this, x->Hidden);
+ MyRoot = new TreeServer(sname, description, sid, Utils->TreeRoot, this, x->Hidden);
Utils->TreeRoot->AddChild(MyRoot);
this->DoBurst(MyRoot);
- params[4] = ":" + params[4];
-
- /* IMPORTANT: Take password/hmac hash OUT of here before we broadcast the introduction! */
- params[1] = "*";
- Utils->DoOneToAllButSender(ServerInstance->Config->GetSID(),"SERVER",params,sname);
+ // This will send a * in place of the password/hmac
+ CommandServer::Builder(MyRoot).Forward(MyRoot);
return true;
}
@@ -194,7 +166,7 @@ bool TreeSocket::CheckDuplicate(const std::string& sname, const std::string& sid
}
/* Check for fully initialized instances of the server by id */
- ServerInstance->Logs->Log("m_spanningtree",DEBUG,"Looking for dupe SID %s", sid.c_str());
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Looking for dupe SID %s", sid.c_str());
CheckDupe = Utils->FindServerID(sid);
if (CheckDupe)
@@ -225,17 +197,9 @@ bool TreeSocket::Inbound_Server(parameterlist &params)
std::string password = params[1];
std::string sid = params[3];
std::string description = params[4];
- int hops = atoi(params[2].c_str());
this->SendCapabilities(2);
- if (hops)
- {
- this->SendError("Server too far away for authentication");
- ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server is too far away for authentication");
- return false;
- }
-
if (!ServerInstance->IsSID(sid))
{
this->SendError("Invalid format server ID: "+sid+"!");
@@ -281,3 +245,11 @@ bool TreeSocket::Inbound_Server(parameterlist &params)
return false;
}
+CommandServer::Builder::Builder(TreeServer* server)
+ : CmdBuilder(server->GetParent()->GetID(), "SERVER")
+{
+ push(server->GetName());
+ push_raw(" * 0 ");
+ push_raw(server->GetID());
+ push_last(server->GetDesc());
+}
diff --git a/src/modules/m_spanningtree/servercommand.cpp b/src/modules/m_spanningtree/servercommand.cpp
new file mode 100644
index 000000000..3034eee7a
--- /dev/null
+++ b/src/modules/m_spanningtree/servercommand.cpp
@@ -0,0 +1,57 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2013 Attila Molnar <attilamolnar@hush.com>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "main.h"
+#include "servercommand.h"
+
+ServerCommand::ServerCommand(Module* Creator, const std::string& Name, unsigned int MinParams, unsigned int MaxParams)
+ : CommandBase(Creator, Name, MinParams, MaxParams)
+{
+ this->ServiceProvider::DisableAutoRegister();
+ ModuleSpanningTree* st = static_cast<ModuleSpanningTree*>(Creator);
+ st->CmdManager.AddCommand(this);
+}
+
+RouteDescriptor ServerCommand::GetRouting(User* user, const std::vector<std::string>& parameters)
+{
+ // Broadcast server-to-server commands unless overridden
+ return ROUTE_BROADCAST;
+}
+
+time_t ServerCommand::ExtractTS(const std::string& tsstr)
+{
+ time_t TS = ConvToInt(tsstr);
+ if (!TS)
+ throw ProtocolException("Invalid TS");
+ return TS;
+}
+
+ServerCommand* ServerCommandManager::GetHandler(const std::string& command) const
+{
+ ServerCommandMap::const_iterator it = commands.find(command);
+ if (it != commands.end())
+ return it->second;
+ return NULL;
+}
+
+bool ServerCommandManager::AddCommand(ServerCommand* cmd)
+{
+ return commands.insert(std::make_pair(cmd->name, cmd)).second;
+}
diff --git a/src/modules/m_spanningtree/servercommand.h b/src/modules/m_spanningtree/servercommand.h
new file mode 100644
index 000000000..524520a88
--- /dev/null
+++ b/src/modules/m_spanningtree/servercommand.h
@@ -0,0 +1,100 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2013 Attila Molnar <attilamolnar@hush.com>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#pragma once
+
+#include "utils.h"
+#include "treeserver.h"
+
+class ProtocolException : public ModuleException
+{
+ public:
+ ProtocolException(const std::string& msg)
+ : ModuleException("Protocol violation: " + msg)
+ {
+ }
+};
+
+/** Base class for server-to-server commands that may have a (remote) user source or server source.
+ */
+class ServerCommand : public CommandBase
+{
+ public:
+ ServerCommand(Module* Creator, const std::string& Name, unsigned int MinPara = 0, unsigned int MaxPara = 0);
+
+ virtual CmdResult Handle(User* user, std::vector<std::string>& parameters) = 0;
+ virtual RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters);
+
+ /**
+ * Extract the TS from a string.
+ * @param tsstr The string containing the TS.
+ * @return The raw timestamp value.
+ * This function throws a ProtocolException if it considers the TS invalid. Note that the detection of
+ * invalid timestamps is not designed to be bulletproof, only some cases - like "0" - trigger an exception.
+ */
+ static time_t ExtractTS(const std::string& tsstr);
+};
+
+/** Base class for server-to-server command handlers which are only valid if their source is a user.
+ * When a server sends a command of this type and the source is a server (sid), the link is aborted.
+ */
+template <class T>
+class UserOnlyServerCommand : public ServerCommand
+{
+ public:
+ UserOnlyServerCommand(Module* Creator, const std::string& Name, unsigned int MinPara = 0, unsigned int MaxPara = 0)
+ : ServerCommand(Creator, Name, MinPara, MaxPara) { }
+
+ CmdResult Handle(User* user, std::vector<std::string>& parameters)
+ {
+ RemoteUser* remoteuser = IS_REMOTE(user);
+ if (!remoteuser)
+ throw ProtocolException("Invalid source");
+ return static_cast<T*>(this)->HandleRemote(remoteuser, parameters);
+ }
+};
+
+/** Base class for server-to-server command handlers which are only valid if their source is a server.
+ * When a server sends a command of this type and the source is a user (uuid), the link is aborted.
+ */
+template <class T>
+class ServerOnlyServerCommand : public ServerCommand
+{
+ public:
+ ServerOnlyServerCommand(Module* Creator, const std::string& Name, unsigned int MinPara = 0, unsigned int MaxPara = 0)
+ : ServerCommand(Creator, Name, MinPara, MaxPara) { }
+
+ CmdResult Handle(User* user, std::vector<std::string>& parameters)
+ {
+ if (!IS_SERVER(user))
+ throw ProtocolException("Invalid source");
+ TreeServer* server = TreeServer::Get(user);
+ return static_cast<T*>(this)->HandleServer(server, parameters);
+ }
+};
+
+class ServerCommandManager
+{
+ typedef TR1NS::unordered_map<std::string, ServerCommand*> ServerCommandMap;
+ ServerCommandMap commands;
+
+ public:
+ ServerCommand* GetHandler(const std::string& command) const;
+ bool AddCommand(ServerCommand* cmd);
+};
diff --git a/src/modules/m_spanningtree/sinfo.cpp b/src/modules/m_spanningtree/sinfo.cpp
new file mode 100644
index 000000000..0989ea9a5
--- /dev/null
+++ b/src/modules/m_spanningtree/sinfo.cpp
@@ -0,0 +1,51 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "inspircd.h"
+
+#include "treeserver.h"
+#include "commands.h"
+
+CmdResult CommandSInfo::HandleServer(TreeServer* server, std::vector<std::string>& params)
+{
+ const std::string& key = params.front();
+ const std::string& value = params.back();
+
+ if (key == "fullversion")
+ {
+ server->SetFullVersion(value);
+ }
+ else if (key == "version")
+ {
+ server->SetVersion(value);
+ }
+ else if (key == "desc")
+ {
+ // Only sent when the description of a server changes because of a rehash; not sent on burst
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Server description of " + server->GetName() + " changed: " + value);
+ server->SetDesc(value);
+ }
+
+ return CMD_SUCCESS;
+}
+
+CommandSInfo::Builder::Builder(TreeServer* server, const char* key, const std::string& val)
+ : CmdBuilder(server->GetID(), "SINFO")
+{
+ push(key).push_last(val);
+}
diff --git a/src/modules/m_spanningtree/svsjoin.cpp b/src/modules/m_spanningtree/svsjoin.cpp
index 416502369..552e08dd3 100644
--- a/src/modules/m_spanningtree/svsjoin.cpp
+++ b/src/modules/m_spanningtree/svsjoin.cpp
@@ -19,19 +19,13 @@
#include "inspircd.h"
-#include "socket.h"
-#include "xline.h"
-#include "socketengine.h"
-#include "main.h"
-#include "utils.h"
-#include "treeserver.h"
#include "commands.h"
-CmdResult CommandSVSJoin::Handle(const std::vector<std::string>& parameters, User *user)
+CmdResult CommandSVSJoin::Handle(User* user, std::vector<std::string>& parameters)
{
// Check for valid channel name
- if (!ServerInstance->IsChannel(parameters[1].c_str(), ServerInstance->Config->Limits.ChanMax))
+ if (!ServerInstance->IsChannel(parameters[1]))
return CMD_FAILURE;
// Check target exists
@@ -40,8 +34,9 @@ CmdResult CommandSVSJoin::Handle(const std::vector<std::string>& parameters, Use
return CMD_FAILURE;
/* only join if it's local, otherwise just pass it on! */
- if (IS_LOCAL(u))
- Channel::JoinUser(u, parameters[1].c_str(), false, "", false, ServerInstance->Time());
+ LocalUser* localuser = IS_LOCAL(u);
+ if (localuser)
+ Channel::JoinUser(localuser, parameters[1]);
return CMD_SUCCESS;
}
diff --git a/src/modules/m_spanningtree/svsnick.cpp b/src/modules/m_spanningtree/svsnick.cpp
index 59973202d..bb21fc54d 100644
--- a/src/modules/m_spanningtree/svsnick.cpp
+++ b/src/modules/m_spanningtree/svsnick.cpp
@@ -21,41 +21,50 @@
#include "inspircd.h"
#include "main.h"
-#include "utils.h"
#include "commands.h"
-CmdResult CommandSVSNick::Handle(const std::vector<std::string>& parameters, User *user)
+CmdResult CommandSVSNick::Handle(User* user, std::vector<std::string>& parameters)
{
User* u = ServerInstance->FindNick(parameters[0]);
if (u && IS_LOCAL(u))
{
+ // The 4th parameter is optional and it is the expected nick TS of the target user. If this parameter is
+ // present and it doesn't match the user's nick TS, the SVSNICK is not acted upon.
+ // This makes it possible to detect the case when services wants to change the nick of a user, but the
+ // user changes their nick before the SVSNICK arrives, making the SVSNICK nick change (usually to a guest nick)
+ // unnecessary. Consider the following for example:
+ //
+ // 1. test changes nick to Attila which is protected by services
+ // 2. Services SVSNICKs the user to Guest12345
+ // 3. Attila changes nick to Attila_ which isn't protected by services
+ // 4. SVSNICK arrives
+ // 5. Attila_ gets his nick changed to Guest12345 unnecessarily
+ //
+ // In this case when the SVSNICK is processed the target has already changed his nick to something
+ // which isn't protected, so changing the nick again to a Guest nick is not desired.
+ // However, if the expected nick TS parameter is present in the SVSNICK then the nick change in step 5
+ // won't happen because the timestamps won't match.
+ if (parameters.size() > 3)
+ {
+ time_t ExpectedTS = ConvToInt(parameters[3]);
+ if (u->age != ExpectedTS)
+ return CMD_FAILURE; // Ignore SVSNICK
+ }
+
std::string nick = parameters[1];
if (isdigit(nick[0]))
nick = u->uuid;
- // Don't update the TS if the nick is exactly the same
- if (u->nick == nick)
- return CMD_FAILURE;
-
time_t NickTS = ConvToInt(parameters[2]);
if (NickTS <= 0)
return CMD_FAILURE;
- ModuleSpanningTree* st = (ModuleSpanningTree*)(Module*)creator;
- st->KeepNickTS = true;
- u->age = NickTS;
-
- if (!u->ForceNickChange(nick.c_str()))
+ if (!u->ChangeNick(nick, NickTS))
{
/* buh. UID them */
- if (!u->ForceNickChange(u->uuid.c_str()))
- {
- ServerInstance->Users->QuitUser(u, "Nickname collision");
- }
+ u->ChangeNick(u->uuid);
}
-
- st->KeepNickTS = false;
}
return CMD_SUCCESS;
diff --git a/src/modules/m_spanningtree/svspart.cpp b/src/modules/m_spanningtree/svspart.cpp
index 3bdf13b25..f86afa367 100644
--- a/src/modules/m_spanningtree/svspart.cpp
+++ b/src/modules/m_spanningtree/svspart.cpp
@@ -19,16 +19,10 @@
#include "inspircd.h"
-#include "socket.h"
-#include "xline.h"
-#include "socketengine.h"
-#include "main.h"
-#include "utils.h"
-#include "treeserver.h"
#include "commands.h"
-CmdResult CommandSVSPart::Handle(const std::vector<std::string>& parameters, User *user)
+CmdResult CommandSVSPart::Handle(User* user, std::vector<std::string>& parameters)
{
User* u = ServerInstance->FindUUID(parameters[0]);
if (!u)
diff --git a/src/modules/m_spanningtree/treeserver.cpp b/src/modules/m_spanningtree/treeserver.cpp
index 493b05ebf..74854acc9 100644
--- a/src/modules/m_spanningtree/treeserver.cpp
+++ b/src/modules/m_spanningtree/treeserver.cpp
@@ -21,56 +21,45 @@
#include "inspircd.h"
-#include "socket.h"
#include "xline.h"
#include "main.h"
-#include "../spanningtree.h"
+#include "modules/spanningtree.h"
#include "utils.h"
#include "treeserver.h"
-/* $ModDep: m_spanningtree/utils.h m_spanningtree/treeserver.h */
-
/** We use this constructor only to create the 'root' item, Utils->TreeRoot, which
* represents our own server. Therefore, it has no route, no parent, and
* no socket associated with it. Its version string is our own local version.
*/
-TreeServer::TreeServer(SpanningTreeUtilities* Util, std::string Name, std::string Desc, const std::string &id)
- : ServerName(Name.c_str()), ServerDesc(Desc), Utils(Util), ServerUser(ServerInstance->FakeClient)
+TreeServer::TreeServer()
+ : Server(ServerInstance->Config->ServerName, ServerInstance->Config->ServerDesc)
+ , Parent(NULL), Route(NULL)
+ , VersionString(ServerInstance->GetVersionString())
+ , fullversion(ServerInstance->GetVersionString(true))
+ , Socket(NULL), sid(ServerInstance->Config->GetSID()), ServerUser(ServerInstance->FakeClient)
+ , age(ServerInstance->Time()), Warned(false), bursting(false), UserCount(ServerInstance->Users.GetLocalUsers().size())
+ , OperCount(0), rtt(0), StartBurst(0), Hidden(false)
{
- age = ServerInstance->Time();
- bursting = false;
- Parent = NULL;
- VersionString.clear();
- ServerUserCount = ServerOperCount = 0;
- VersionString = ServerInstance->GetVersionString();
- Route = NULL;
- Socket = NULL; /* Fix by brain */
- StartBurst = rtt = 0;
- Warned = Hidden = false;
AddHashEntry();
- SetID(id);
}
/** When we create a new server, we call this constructor to initialize it.
* This constructor initializes the server's Route and Parent, and sets up
* its ping counters so that it will be pinged one minute from now.
*/
-TreeServer::TreeServer(SpanningTreeUtilities* Util, std::string Name, std::string Desc, const std::string &id, TreeServer* Above, TreeSocket* Sock, bool Hide)
- : Parent(Above), ServerName(Name.c_str()), ServerDesc(Desc), Socket(Sock), Utils(Util), ServerUser(new FakeUser(id, Name)), Hidden(Hide)
+TreeServer::TreeServer(const std::string& Name, const std::string& Desc, const std::string& id, TreeServer* Above, TreeSocket* Sock, bool Hide)
+ : Server(Name, Desc)
+ , Parent(Above), Socket(Sock), sid(id), ServerUser(new FakeUser(id, this))
+ , age(ServerInstance->Time()), Warned(false), bursting(true), UserCount(0), OperCount(0), rtt(0), Hidden(Hide)
{
- age = ServerInstance->Time();
- bursting = true;
- VersionString.clear();
- ServerUserCount = ServerOperCount = 0;
+ CheckULine();
SetNextPingTime(ServerInstance->Time() + Utils->PingFreq);
SetPingFlag();
- Warned = false;
- rtt = 0;
long ts = ServerInstance->Time() * 1000 + (ServerInstance->Time_ns() / 1000000);
this->StartBurst = ts;
- ServerInstance->Logs->Log("m_spanningtree",DEBUG, "Started bursting at time %lu", ts);
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Server %s started bursting at time %lu", sid.c_str(), ts);
/* find the 'route' for this server (e.g. the one directly connected
* to the local server, which we can use to reach it)
@@ -124,8 +113,6 @@ TreeServer::TreeServer(SpanningTreeUtilities* Util, std::string Name, std::strin
*/
this->AddHashEntry();
-
- SetID(id);
}
const std::string& TreeServer::GetID()
@@ -138,9 +125,9 @@ void TreeServer::FinishBurstInternal()
this->bursting = false;
SetNextPingTime(ServerInstance->Time() + Utils->PingFreq);
SetPingFlag();
- for(unsigned int q=0; q < ChildCount(); q++)
+ for (ChildServers::const_iterator i = Children.begin(); i != Children.end(); ++i)
{
- TreeServer* child = GetChild(q);
+ TreeServer* child = *i;
child->FinishBurstInternal();
}
}
@@ -152,43 +139,49 @@ void TreeServer::FinishBurst()
long ts = ServerInstance->Time() * 1000 + (ServerInstance->Time_ns() / 1000000);
unsigned long bursttime = ts - this->StartBurst;
ServerInstance->SNO->WriteToSnoMask(Parent == Utils->TreeRoot ? 'l' : 'L', "Received end of netburst from \2%s\2 (burst time: %lu %s)",
- ServerName.c_str(), (bursttime > 10000 ? bursttime / 1000 : bursttime), (bursttime > 10000 ? "secs" : "msecs"));
- AddServerEvent(Utils->Creator, ServerName.c_str());
-}
-
-void TreeServer::SetID(const std::string &id)
-{
- ServerInstance->Logs->Log("m_spanningtree",DEBUG, "Setting SID to " + id);
- sid = id;
- Utils->sidlist[sid] = this;
+ GetName().c_str(), (bursttime > 10000 ? bursttime / 1000 : bursttime), (bursttime > 10000 ? "secs" : "msecs"));
+ AddServerEvent(Utils->Creator, GetName());
}
int TreeServer::QuitUsers(const std::string &reason)
{
- const char* reason_s = reason.c_str();
- std::vector<User*> time_to_die;
- for (user_hash::iterator n = ServerInstance->Users->clientlist->begin(); n != ServerInstance->Users->clientlist->end(); n++)
+ std::string publicreason = ServerInstance->Config->HideSplits ? "*.net *.split" : reason;
+
+ const user_hash& users = ServerInstance->Users->GetUsers();
+ unsigned int original_size = users.size();
+ for (user_hash::const_iterator i = users.begin(); i != users.end(); )
{
- if (n->second->server == ServerName)
- {
- time_to_die.push_back(n->second);
- }
+ User* user = i->second;
+ // Increment the iterator now because QuitUser() removes the user from the container
+ ++i;
+ if (user->server == this)
+ ServerInstance->Users->QuitUser(user, publicreason, &reason);
}
- for (std::vector<User*>::iterator n = time_to_die.begin(); n != time_to_die.end(); n++)
+ return original_size - users.size();
+}
+
+void TreeServer::CheckULine()
+{
+ uline = silentuline = false;
+
+ ConfigTagList tags = ServerInstance->Config->ConfTags("uline");
+ for (ConfigIter i = tags.first; i != tags.second; ++i)
{
- User* a = (User*)*n;
- if (!IS_LOCAL(a))
+ ConfigTag* tag = i->second;
+ std::string server = tag->getString("server");
+ if (!strcasecmp(server.c_str(), GetName().c_str()))
{
- if (this->Utils->quiet_bursts)
- a->quietquit = true;
-
- if (ServerInstance->Config->HideSplits)
- ServerInstance->Users->QuitUser(a, "*.net *.split", reason_s);
- else
- ServerInstance->Users->QuitUser(a, reason_s);
+ if (this->IsRoot())
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Servers should not uline themselves (at " + tag->getTagLocation() + ")");
+ return;
+ }
+
+ uline = true;
+ silentuline = tag->getBool("silent");
+ break;
}
}
- return time_to_die.size();
}
/** This method is used to add the structure to the
@@ -197,20 +190,8 @@ int TreeServer::QuitUsers(const std::string &reason)
*/
void TreeServer::AddHashEntry()
{
- server_hash::iterator iter = Utils->serverlist.find(this->ServerName.c_str());
- if (iter == Utils->serverlist.end())
- Utils->serverlist[this->ServerName.c_str()] = this;
-}
-
-/** This method removes the reference to this object
- * from the hash_map which is used for linear searches.
- * It is only called by the default destructor.
- */
-void TreeServer::DelHashEntry()
-{
- server_hash::iterator iter = Utils->serverlist.find(this->ServerName.c_str());
- if (iter != Utils->serverlist.end())
- Utils->serverlist.erase(iter);
+ Utils->serverlist[GetName()] = this;
+ Utils->sidlist[sid] = this;
}
/** These accessors etc should be pretty self-
@@ -221,16 +202,6 @@ TreeServer* TreeServer::GetRoute()
return Route;
}
-std::string TreeServer::GetName()
-{
- return ServerName.c_str();
-}
-
-const std::string& TreeServer::GetDesc()
-{
- return ServerDesc;
-}
-
const std::string& TreeServer::GetVersion()
{
return VersionString;
@@ -257,26 +228,6 @@ void TreeServer::SetPingFlag()
LastPingWasGood = true;
}
-unsigned int TreeServer::GetUserCount()
-{
- return ServerUserCount;
-}
-
-void TreeServer::SetUserCount(int diff)
-{
- ServerUserCount += diff;
-}
-
-void TreeServer::SetOperCount(int diff)
-{
- ServerOperCount += diff;
-}
-
-unsigned int TreeServer::GetOperCount()
-{
- return ServerOperCount;
-}
-
TreeSocket* TreeServer::GetSocket()
{
return Socket;
@@ -292,28 +243,6 @@ void TreeServer::SetVersion(const std::string &Version)
VersionString = Version;
}
-unsigned int TreeServer::ChildCount()
-{
- return Children.size();
-}
-
-TreeServer* TreeServer::GetChild(unsigned int n)
-{
- if (n < Children.size())
- {
- /* Make sure they cant request
- * an out-of-range object. After
- * all we know what these programmer
- * types are like *grin*.
- */
- return Children[n];
- }
- else
- {
- return NULL;
- }
-}
-
void TreeServer::AddChild(TreeServer* Child)
{
Children.push_back(Child);
@@ -334,13 +263,13 @@ bool TreeServer::DelChild(TreeServer* Child)
* This is used during netsplits to automatically tidy up the
* server tree. It is slow, we don't use it for much else.
*/
-bool TreeServer::Tidy()
+void TreeServer::Tidy()
{
while (1)
{
std::vector<TreeServer*>::iterator a = Children.begin();
if (a == Children.end())
- return true;
+ return;
TreeServer* s = *a;
s->Tidy();
s->cull();
@@ -351,7 +280,7 @@ bool TreeServer::Tidy()
CullResult TreeServer::cull()
{
- if (ServerUser != ServerInstance->FakeClient)
+ if (!IsRoot())
ServerUser->cull();
return classbase::cull();
}
@@ -359,11 +288,9 @@ CullResult TreeServer::cull()
TreeServer::~TreeServer()
{
/* We'd better tidy up after ourselves, eh? */
- this->DelHashEntry();
- if (ServerUser != ServerInstance->FakeClient)
+ if (!IsRoot())
delete ServerUser;
- server_hash::iterator iter = Utils->sidlist.find(GetID());
- if (iter != Utils->sidlist.end())
- Utils->sidlist.erase(iter);
+ Utils->sidlist.erase(sid);
+ Utils->serverlist.erase(GetName());
}
diff --git a/src/modules/m_spanningtree/treeserver.h b/src/modules/m_spanningtree/treeserver.h
index 60b6d1def..6bd1a4f7c 100644
--- a/src/modules/m_spanningtree/treeserver.h
+++ b/src/modules/m_spanningtree/treeserver.h
@@ -19,8 +19,7 @@
*/
-#ifndef M_SPANNINGTREE_TREESERVER_H
-#define M_SPANNINGTREE_TREESERVER_H
+#pragma once
#include "treesocket.h"
@@ -38,79 +37,75 @@
* TreeServer items, deleting and inserting them as they
* are created and destroyed.
*/
-class TreeServer : public classbase
+class TreeServer : public Server
{
TreeServer* Parent; /* Parent entry */
TreeServer* Route; /* Route entry */
std::vector<TreeServer*> Children; /* List of child objects */
- irc::string ServerName; /* Server's name */
- std::string ServerDesc; /* Server's description */
std::string VersionString; /* Version string or empty string */
- unsigned int ServerUserCount; /* How many users are on this server? [note: doesn't care about +i] */
- unsigned int ServerOperCount; /* How many opers are on this server? */
- TreeSocket* Socket; /* For directly connected servers this points at the socket object */
+
+ /** Full version string including patch version and other info
+ */
+ std::string fullversion;
+
+ TreeSocket* Socket; /* Socket used to communicate with this server */
time_t NextPing; /* After this time, the server should be PINGed*/
bool LastPingWasGood; /* True if the server responded to the last PING with a PONG */
- SpanningTreeUtilities* Utils; /* Utility class */
std::string sid; /* Server ID */
- /** Set server ID
- * @param id Server ID
- * @throws CoreException on duplicate ID
+ /** This method is used to add this TreeServer to the
+ * hash maps. It is only called by the constructors.
*/
- void SetID(const std::string &id);
+ void AddHashEntry();
public:
+ typedef std::vector<TreeServer*> ChildServers;
FakeUser* const ServerUser; /* User representing this server */
- time_t age;
+ const time_t age;
bool Warned; /* True if we've warned opers about high latency on this server */
bool bursting; /* whether or not this server is bursting */
+ unsigned int UserCount; /* How many users are on this server? [note: doesn't care about +i] */
+ unsigned int OperCount; /* How many opers are on this server? */
+
/** We use this constructor only to create the 'root' item, Utils->TreeRoot, which
* represents our own server. Therefore, it has no route, no parent, and
* no socket associated with it. Its version string is our own local version.
*/
- TreeServer(SpanningTreeUtilities* Util, std::string Name, std::string Desc, const std::string &id);
+ TreeServer();
/** When we create a new server, we call this constructor to initialize it.
* This constructor initializes the server's Route and Parent, and sets up
* its ping counters so that it will be pinged one minute from now.
*/
- TreeServer(SpanningTreeUtilities* Util, std::string Name, std::string Desc, const std::string &id, TreeServer* Above, TreeSocket* Sock, bool Hide);
+ TreeServer(const std::string& Name, const std::string& Desc, const std::string& id, TreeServer* Above, TreeSocket* Sock, bool Hide);
int QuitUsers(const std::string &reason);
- /** This method is used to add the structure to the
- * hash_map for linear searches. It is only called
- * by the constructors.
- */
- void AddHashEntry();
-
- /** This method removes the reference to this object
- * from the hash_map which is used for linear searches.
- * It is only called by the default destructor.
- */
- void DelHashEntry();
-
/** Get route.
* The 'route' is defined as the locally-
* connected server which can be used to reach this server.
*/
TreeServer* GetRoute();
- /** Get server name
+ /** Returns true if this server is the tree root (i.e.: us)
*/
- std::string GetName();
+ bool IsRoot() const { return (this->Parent == NULL); }
- /** Get server description (GECOS)
+ /** Returns true if this server is locally connected
*/
- const std::string& GetDesc();
+ bool IsLocal() const { return (this->Route == this); }
/** Get server version string
*/
const std::string& GetVersion();
+ /** Get the full version string of this server
+ * @return The full version string of this server, including patch version and other info
+ */
+ const std::string& GetFullVersion() const { return fullversion; }
+
/** Set time we are next due to ping this server
*/
void SetNextPingTime(time_t t);
@@ -143,22 +138,6 @@ class TreeServer : public classbase
*/
void SetPingFlag();
- /** Get the number of users on this server.
- */
- unsigned int GetUserCount();
-
- /** Increment or decrement the user count by diff.
- */
- void SetUserCount(int diff);
-
- /** Gets the numbers of opers on this server.
- */
- unsigned int GetOperCount();
-
- /** Increment or decrement the oper count by diff.
- */
- void SetOperCount(int diff);
-
/** Get the TreeSocket pointer for local servers.
* For remote servers, this returns NULL.
*/
@@ -173,13 +152,20 @@ class TreeServer : public classbase
*/
void SetVersion(const std::string &Version);
- /** Return number of child servers
+ /** Set the full version string
+ * @param verstr The version string to set
+ */
+ void SetFullVersion(const std::string& verstr) { fullversion = verstr; }
+
+ /** Sets the description of this server. Called when the description of a remote server changes
+ * and we are notified about it.
+ * @param descstr The description to set
*/
- unsigned int ChildCount();
+ void SetDesc(const std::string& descstr) { description = descstr; }
- /** Return a child server indexed 0..n
+ /** Return all child servers
*/
- TreeServer* GetChild(unsigned int n);
+ const ChildServers& GetChildren() const { return Children; }
/** Add a child server
*/
@@ -193,7 +179,7 @@ class TreeServer : public classbase
* This is used during netsplits to automatically tidy up the
* server tree. It is slow, we don't use it for much else.
*/
- bool Tidy();
+ void Tidy();
/** Get server ID
*/
@@ -205,10 +191,24 @@ class TreeServer : public classbase
/** Recursive call for child servers */
void FinishBurstInternal();
+ /** (Re)check the uline state of this server
+ */
+ void CheckULine();
+
CullResult cull();
+
/** Destructor
+ * Removes the reference to this object from the
+ * hash maps.
*/
~TreeServer();
-};
-#endif
+ /** Returns the TreeServer the given user is connected to
+ * @param user The user whose server to return
+ * @return The TreeServer this user is connected to.
+ */
+ static TreeServer* Get(User* user)
+ {
+ return static_cast<TreeServer*>(user->server);
+ }
+};
diff --git a/src/modules/m_spanningtree/treesocket.h b/src/modules/m_spanningtree/treesocket.h
index d8445572b..27c8ab275 100644
--- a/src/modules/m_spanningtree/treesocket.h
+++ b/src/modules/m_spanningtree/treesocket.h
@@ -20,12 +20,9 @@
*/
-#ifndef M_SPANNINGTREE_TREESOCKET_H
-#define M_SPANNINGTREE_TREESOCKET_H
+#pragma once
-#include "socket.h"
#include "inspircd.h"
-#include "xline.h"
#include "utils.h"
@@ -76,7 +73,7 @@ struct CapabData
std::string ourchallenge; /* Challenge sent for challenge/response */
std::string theirchallenge; /* Challenge recv for challenge/response */
int capab_phase; /* Have sent CAPAB already */
- bool auth_fingerprint; /* Did we auth using SSL fingerprint */
+ bool auth_fingerprint; /* Did we auth using SSL certificate fingerprint */
bool auth_challenge; /* Did we auth using challenge/response */
// Data saved from incoming SERVER command, for later use when our credentials have been accepted by the other party
@@ -92,7 +89,8 @@ struct CapabData
*/
class TreeSocket : public BufferedSocket
{
- SpanningTreeUtilities* Utils; /* Utility class */
+ struct BurstState;
+
std::string linkID; /* Description for this link */
ServerState LinkState; /* Link state */
CapabData* capab; /* Link setup data (held until burst is sent) */
@@ -106,21 +104,46 @@ class TreeSocket : public BufferedSocket
*/
bool CheckDuplicate(const std::string& servername, const std::string& sid);
+ /** Send all ListModeBase modes set on the channel
+ */
+ void SendListModes(Channel* chan);
+
+ /** Send all known information about a channel */
+ void SyncChannel(Channel* chan, BurstState& bs);
+
+ /** Send all users and their oper state, away state and metadata */
+ void SendUsers(BurstState& bs);
+
+ /** Send all additional info about the given server to this server */
+ void SendServerInfo(TreeServer* from);
+
+ /** Find the User source of a command given a prefix and a command string.
+ * This connection must be fully up when calling this function.
+ * @param prefix Prefix string to find the source User object for. Can be a sid, a uuid or a server name.
+ * @param command The command whose source to find. This is required because certain commands (like mode
+ * changes and kills) must be processed even if their claimed source doesn't exist. If the given command is
+ * such a command and the source does not exist, the function returns a valid FakeUser that can be used to
+ * to process the command with.
+ * @return The command source to use when processing the command or NULL if the source wasn't found.
+ * Note that the direction of the returned source is not verified.
+ */
+ User* FindSource(const std::string& prefix, const std::string& command);
+
public:
- time_t age;
+ const time_t age;
/** Because most of the I/O gubbins are encapsulated within
* BufferedSocket, we just call the superclass constructor for
* most of the action, and append a few of our own values
* to it.
*/
- TreeSocket(SpanningTreeUtilities* Util, Link* link, Autoconnect* myac, const std::string& ipaddr);
+ TreeSocket(Link* link, Autoconnect* myac, const std::string& ipaddr);
/** When a listening socket gives us a new file descriptor,
* we must associate it with a socket without creating a new
* connection. This constructor is used for this purpose.
*/
- TreeSocket(SpanningTreeUtilities* Util, int newfd, ListenSocket* via, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server);
+ TreeSocket(int newfd, ListenSocket* via, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server);
/** Get link state
*/
@@ -166,11 +189,11 @@ class TreeSocket : public BufferedSocket
* to server docs on the inspircd.org site, the other side
* will then send back its own server string.
*/
- virtual void OnConnected();
+ void OnConnected();
/** Handle socket error event
*/
- virtual void OnError(BufferedSocketError e);
+ void OnError(BufferedSocketError e) CXX11_OVERRIDE;
/** Sends an error to the remote server, and displays it locally to show
* that it was sent.
@@ -180,13 +203,8 @@ class TreeSocket : public BufferedSocket
/** Recursively send the server tree with distances as hops.
* This is used during network burst to inform the other server
* (and any of ITS servers too) of what servers we know about.
- * If at any point any of these servers already exist on the other
- * end, our connection may be terminated. The hopcounts given
- * by this function are relative, this doesn't matter so long as
- * they are all >1, as all the remote servers re-calculate them
- * to be relative too, with themselves as hop 0.
*/
- void SendServers(TreeServer* Current, TreeServer* s, int hops);
+ void SendServers(TreeServer* Current, TreeServer* s);
/** Returns module list as a string, filtered by filter
* @param filter a module version bitmask, such as VF_COMMON or VF_OPTCOMMON
@@ -197,9 +215,6 @@ class TreeSocket : public BufferedSocket
*/
void SendCapabilities(int phase);
- /** Add modules to VF_COMMON list for backwards compatability */
- void CompatAddModules(std::vector<std::string>& modlist);
-
/* Isolate and return the elements that are different between two lists */
void ListDifference(const std::string &one, const std::string &two, char sep,
std::string& mleft, std::string& mright);
@@ -220,9 +235,6 @@ class TreeSocket : public BufferedSocket
*/
void Squit(TreeServer* Current, const std::string &reason);
- /* Used on nick collision ... XXX ugly function HACK */
- int DoCollision(User *u, time_t remotets, const std::string &remoteident, const std::string &remoteip, const std::string &remoteuid);
-
/** Send one or more FJOINs for a channel of users.
* If the length of a single line is more than 480-NICKMAX
* in length, it is split over multiple lines.
@@ -232,11 +244,8 @@ class TreeSocket : public BufferedSocket
/** Send G, Q, Z and E lines */
void SendXLines();
- /** Send channel modes and topics */
- void SendChannelModes();
-
- /** send all users and their oper state/modes */
- void SendUsers();
+ /** Send all known information about a channel */
+ void SyncChannel(Channel* chan);
/** This function is called when we want to send a netburst to a local
* server. There is a set order we must do this, because for example
@@ -252,57 +261,11 @@ class TreeSocket : public BufferedSocket
/** Send one or more complete lines down the socket
*/
- void WriteLine(std::string line);
+ void WriteLine(const std::string& line);
/** Handle ERROR command */
void Error(parameterlist &params);
- /** Remote AWAY */
- bool Away(const std::string &prefix, parameterlist &params);
-
- /** SAVE to resolve nick collisions without killing */
- bool ForceNick(const std::string &prefix, parameterlist &params);
-
- /** ENCAP command
- */
- void Encap(User* who, parameterlist &params);
-
- /** OPERQUIT command
- */
- bool OperQuit(const std::string &prefix, parameterlist &params);
-
- /** PONG
- */
- bool LocalPong(const std::string &prefix, parameterlist &params);
-
- /** VERSION
- */
- bool ServerVersion(const std::string &prefix, parameterlist &params);
-
- /** ADDLINE
- */
- bool AddLine(const std::string &prefix, parameterlist &params);
-
- /** DELLINE
- */
- bool DelLine(const std::string &prefix, parameterlist &params);
-
- /** WHOIS
- */
- bool Whois(const std::string &prefix, parameterlist &params);
-
- /** PUSH
- */
- bool Push(const std::string &prefix, parameterlist &params);
-
- /** PING
- */
- bool LocalPing(const std::string &prefix, parameterlist &params);
-
- /** <- (remote) <- SERVER
- */
- bool RemoteServer(const std::string &prefix, parameterlist &params);
-
/** (local) -> SERVER
*/
bool Outbound_Reply_Server(parameterlist &params);
@@ -323,15 +286,16 @@ class TreeSocket : public BufferedSocket
/** Handle socket timeout from connect()
*/
- virtual void OnTimeout();
+ void OnTimeout();
/** Handle server quit on close
*/
- virtual void Close();
+ void Close();
/** Returns true if this server was introduced to the rest of the network
*/
bool Introduced();
-};
-
-#endif
+ /** Fixes messages coming from old servers so the new command handlers understand them
+ */
+ bool PreProcessOldProtocolMessage(User*& who, std::string& cmd, std::vector<std::string>& params);
+};
diff --git a/src/modules/m_spanningtree/treesocket1.cpp b/src/modules/m_spanningtree/treesocket1.cpp
index c9729cc0f..931bd3f9f 100644
--- a/src/modules/m_spanningtree/treesocket1.cpp
+++ b/src/modules/m_spanningtree/treesocket1.cpp
@@ -21,46 +21,30 @@
#include "inspircd.h"
-#include "socket.h"
-#include "xline.h"
-#include "socketengine.h"
+#include "iohook.h"
#include "main.h"
-#include "../spanningtree.h"
+#include "modules/spanningtree.h"
#include "utils.h"
#include "treeserver.h"
#include "link.h"
#include "treesocket.h"
-#include "resolvers.h"
+#include "commands.h"
/** Because most of the I/O gubbins are encapsulated within
* BufferedSocket, we just call the superclass constructor for
* most of the action, and append a few of our own values
* to it.
*/
-TreeSocket::TreeSocket(SpanningTreeUtilities* Util, Link* link, Autoconnect* myac, const std::string& ipaddr)
- : Utils(Util)
+TreeSocket::TreeSocket(Link* link, Autoconnect* myac, const std::string& ipaddr)
+ : linkID(assign(link->Name)), LinkState(CONNECTING), MyRoot(NULL), proto_version(0), ConnectionFailureShown(false)
+ , age(ServerInstance->Time())
{
- age = ServerInstance->Time();
- linkID = assign(link->Name);
capab = new CapabData;
capab->link = link;
capab->ac = myac;
capab->capab_phase = 0;
- MyRoot = NULL;
- proto_version = 0;
- ConnectionFailureShown = false;
- LinkState = CONNECTING;
- if (!link->Hook.empty())
- {
- ServiceProvider* prov = ServerInstance->Modules->FindService(SERVICE_IOHOOK, link->Hook);
- if (!prov)
- {
- SetError("Could not find hook '" + link->Hook + "' for connection to " + linkID);
- return;
- }
- AddIOHook(prov->creator);
- }
+
DoConnect(ipaddr, link->Port, link->Timeout, link->Bind);
Utils->timeoutlist[this] = std::pair<std::string, int>(linkID, link->Timeout);
SendCapabilities(1);
@@ -70,21 +54,16 @@ TreeSocket::TreeSocket(SpanningTreeUtilities* Util, Link* link, Autoconnect* mya
* we must associate it with a socket without creating a new
* connection. This constructor is used for this purpose.
*/
-TreeSocket::TreeSocket(SpanningTreeUtilities* Util, int newfd, ListenSocket* via, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server)
- : BufferedSocket(newfd), Utils(Util)
+TreeSocket::TreeSocket(int newfd, ListenSocket* via, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server)
+ : BufferedSocket(newfd)
+ , linkID("inbound from " + client->addr()), LinkState(WAIT_AUTH_1), MyRoot(NULL), proto_version(0)
+ , ConnectionFailureShown(false), age(ServerInstance->Time())
{
capab = new CapabData;
capab->capab_phase = 0;
- MyRoot = NULL;
- age = ServerInstance->Time();
- LinkState = WAIT_AUTH_1;
- proto_version = 0;
- ConnectionFailureShown = false;
- linkID = "inbound from " + client->addr();
- FOREACH_MOD(I_OnHookIO, OnHookIO(this, via));
- if (GetIOHook())
- GetIOHook()->OnStreamSocketAccept(this, client, server);
+ if (via->iohookprov)
+ via->iohookprov->OnAccept(this, client, server);
SendCapabilities(1);
Utils->timeoutlist[this] = std::pair<std::string, int>(linkID, 30);
@@ -114,8 +93,7 @@ CullResult TreeSocket::cull()
TreeSocket::~TreeSocket()
{
- if (capab)
- delete capab;
+ delete capab;
}
/** When an outbound connection finishes connecting, we receive
@@ -128,6 +106,17 @@ void TreeSocket::OnConnected()
{
if (this->LinkState == CONNECTING)
{
+ if (!capab->link->Hook.empty())
+ {
+ ServiceProvider* prov = ServerInstance->Modules->FindService(SERVICE_IOHOOK, capab->link->Hook);
+ if (!prov)
+ {
+ SetError("Could not find hook '" + capab->link->Hook + "' for connection to " + linkID);
+ return;
+ }
+ static_cast<IOHookProvider*>(prov)->OnConnect(this);
+ }
+
ServerInstance->SNO->WriteGlobalSno('l', "Connection to \2%s\2[%s] started.", linkID.c_str(),
(capab->link->HiddenFromStats ? "<hidden>" : capab->link->IPAddr.c_str()));
this->SendCapabilities(1);
@@ -157,16 +146,15 @@ void TreeSocket::SendError(const std::string &errormessage)
*/
void TreeSocket::SquitServer(std::string &from, TreeServer* Current, int& num_lost_servers, int& num_lost_users)
{
- std::string servername = Current->GetName();
- ServerInstance->Logs->Log("m_spanningtree",DEBUG,"SquitServer for %s from %s",
- servername.c_str(), from.c_str());
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "SquitServer for %s from %s", Current->GetName().c_str(), from.c_str());
/* recursively squit the servers attached to 'Current'.
* We're going backwards so we don't remove users
* while we still need them ;)
*/
- for (unsigned int q = 0; q < Current->ChildCount(); q++)
+ const TreeServer::ChildServers& children = Current->GetChildren();
+ for (TreeServer::ChildServers::const_iterator i = children.begin(); i != children.end(); ++i)
{
- TreeServer* recursive_server = Current->GetChild(q);
+ TreeServer* recursive_server = *i;
this->SquitServer(from,recursive_server, num_lost_servers, num_lost_users);
}
/* Now we've whacked the kids, whack self */
@@ -182,22 +170,21 @@ void TreeSocket::Squit(TreeServer* Current, const std::string &reason)
{
bool LocalSquit = false;
- if ((Current) && (Current != Utils->TreeRoot))
+ if (!Current->IsRoot())
{
DelServerEvent(Utils->Creator, Current->GetName());
- if (!Current->GetSocket() || Current->GetSocket()->Introduced())
- {
- parameterlist params;
- params.push_back(Current->GetID());
- params.push_back(":"+reason);
- Utils->DoOneToAllButSender(Current->GetParent()->GetID(),"SQUIT",params,Current->GetID());
- }
-
- if (Current->GetParent() == Utils->TreeRoot)
+ if (Current->IsLocal())
{
ServerInstance->SNO->WriteGlobalSno('l', "Server \002"+Current->GetName()+"\002 split: "+reason);
LocalSquit = true;
+ if (Current->GetSocket()->Introduced())
+ {
+ CmdBuilder params("SQUIT");
+ params.push_back(Current->GetID());
+ params.push_last(reason);
+ params.Broadcast();
+ }
}
else
{
@@ -206,7 +193,12 @@ void TreeSocket::Squit(TreeServer* Current, const std::string &reason)
int num_lost_servers = 0;
int num_lost_users = 0;
std::string from = Current->GetParent()->GetName()+" "+Current->GetName();
+
+ ModuleSpanningTree* st = Utils->Creator;
+ st->SplitInProgress = true;
SquitServer(from, Current, num_lost_servers, num_lost_users);
+ st->SplitInProgress = false;
+
ServerInstance->SNO->WriteToSnoMask(LocalSquit ? 'l' : 'L', "Netsplit complete, lost \002%d\002 user%s on \002%d\002 server%s.",
num_lost_users, num_lost_users != 1 ? "s" : "", num_lost_servers, num_lost_servers != 1 ? "s" : "");
Current->Tidy();
@@ -220,8 +212,26 @@ void TreeSocket::Squit(TreeServer* Current, const std::string &reason)
Close();
}
}
- else
- ServerInstance->Logs->Log("m_spanningtree",DEFAULT,"Squit from unknown server");
+}
+
+CmdResult CommandSQuit::HandleServer(TreeServer* server, std::vector<std::string>& params)
+{
+ TreeServer* quitting = Utils->FindServer(params[0]);
+ if (!quitting)
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Squit from unknown server");
+ return CMD_FAILURE;
+ }
+
+ TreeSocket* sock = server->GetSocket();
+ sock->Squit(quitting, params[1]);
+
+ // XXX: Return CMD_FAILURE when servers SQUIT themselves (i.e. :00S SQUIT 00S :Shutting down)
+ // to avoid RouteCommand() being called. RouteCommand() requires a valid command source but we
+ // do not have one because the server user is deleted when its TreeServer is destructed.
+ // We generate a SQUIT in TreeSocket::Squit(), with our sid as the source and send it to the
+ // remaining servers.
+ return ((quitting == server) ? CMD_FAILURE : CMD_SUCCESS);
}
/** This function is called when we receive data from a remote
@@ -241,7 +251,18 @@ void TreeSocket::OnDataReady()
SendError("Read null character from socket");
break;
}
- ProcessLine(line);
+
+ try
+ {
+ ProcessLine(line);
+ }
+ catch (CoreException& ex)
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Error while processing: " + line);
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, ex.GetReason());
+ SendError(ex.GetReason() + " - check the log file for details");
+ }
+
if (!getError().empty())
break;
}
diff --git a/src/modules/m_spanningtree/treesocket2.cpp b/src/modules/m_spanningtree/treesocket2.cpp
index fb658c9c7..3df0bdee8 100644
--- a/src/modules/m_spanningtree/treesocket2.cpp
+++ b/src/modules/m_spanningtree/treesocket2.cpp
@@ -23,16 +23,13 @@
#include "inspircd.h"
-#include "socket.h"
-#include "xline.h"
-#include "socketengine.h"
#include "main.h"
#include "utils.h"
#include "treeserver.h"
-#include "link.h"
#include "treesocket.h"
#include "resolvers.h"
+#include "commands.h"
/* Handle ERROR command */
void TreeSocket::Error(parameterlist &params)
@@ -47,7 +44,7 @@ void TreeSocket::Split(const std::string& line, std::string& prefix, std::string
if (!tokens.GetToken(prefix))
return;
-
+
if (prefix[0] == ':')
{
prefix = prefix.substr(1);
@@ -84,7 +81,7 @@ void TreeSocket::ProcessLine(std::string &line)
std::string command;
parameterlist params;
- ServerInstance->Logs->Log("m_spanningtree", RAWIO, "S[%d] I %s", this->GetFd(), line.c_str());
+ ServerInstance->Logs->Log(MODNAME, LOG_RAWIO, "S[%d] I %s", this->GetFd(), line.c_str());
Split(line, prefix, command, params);
@@ -151,7 +148,7 @@ void TreeSocket::ProcessLine(std::string &line)
{
if (params.size())
{
- time_t them = atoi(params[0].c_str());
+ time_t them = ConvToInt(params[0]);
time_t delta = them - ServerInstance->Time();
if ((delta < -600) || (delta > 600))
{
@@ -176,20 +173,14 @@ void TreeSocket::ProcessLine(std::string &line)
linkID = capab->name;
- MyRoot = new TreeServer(Utils, capab->name, capab->description, capab->sid, Utils->TreeRoot, this, capab->hidden);
+ MyRoot = new TreeServer(capab->name, capab->description, capab->sid, Utils->TreeRoot, this, capab->hidden);
Utils->TreeRoot->AddChild(MyRoot);
MyRoot->bursting = true;
this->DoBurst(MyRoot);
- parameterlist sparams;
- sparams.push_back(MyRoot->GetName());
- sparams.push_back("*");
- sparams.push_back("0");
- sparams.push_back(MyRoot->GetID());
- sparams.push_back(":" + MyRoot->GetDesc());
- Utils->DoOneToAllButSender(ServerInstance->Config->GetSID(), "SERVER", sparams, MyRoot->GetName());
- Utils->DoOneToAllButSender(MyRoot->GetID(), "BURST", params, MyRoot->GetName());
+ CommandServer::Builder(MyRoot).Forward(MyRoot);
+ CmdBuilder(MyRoot->GetID(), "BURST").insert(params).Forward(MyRoot);
}
else if (command == "ERROR")
{
@@ -235,52 +226,53 @@ void TreeSocket::ProcessLine(std::string &line)
}
}
-void TreeSocket::ProcessConnectedLine(std::string& prefix, std::string& command, parameterlist& params)
+User* TreeSocket::FindSource(const std::string& prefix, const std::string& command)
{
+ // Empty prefix means the source is the directly connected server that sent this command
+ if (prefix.empty())
+ return MyRoot->ServerUser;
+
+ // If the prefix string is a uuid or a sid FindUUID() returns the appropriate User object
User* who = ServerInstance->FindUUID(prefix);
- std::string direction;
+ if (who)
+ return who;
- if (!who)
- {
- TreeServer* ServerSource = Utils->FindServer(prefix);
- if (prefix.empty())
- ServerSource = MyRoot;
+ // Some implementations wrongly send a server name as prefix occasionally, handle that too for now
+ TreeServer* const server = Utils->FindServer(prefix);
+ if (server)
+ return server->ServerUser;
- if (ServerSource)
- {
- who = ServerSource->ServerUser;
- }
- else
- {
- /* It is important that we don't close the link here, unknown prefix can occur
- * due to various race conditions such as the KILL message for a user somehow
- * crossing the users QUIT further upstream from the server. Thanks jilles!
- */
+ /* It is important that we don't close the link here, unknown prefix can occur
+ * due to various race conditions such as the KILL message for a user somehow
+ * crossing the users QUIT further upstream from the server. Thanks jilles!
+ */
- if ((prefix.length() == UUID_LENGTH-1) && (isdigit(prefix[0])) &&
- ((command == "FMODE") || (command == "MODE") || (command == "KICK") || (command == "TOPIC") || (command == "KILL") || (command == "ADDLINE") || (command == "DELLINE")))
- {
- /* Special case, we cannot drop these commands as they've been committed already on a
- * part of the network by the time we receive them, so in this scenario pretend the
- * command came from a server to avoid desync.
- */
+ if ((prefix.length() == UIDGenerator::UUID_LENGTH) && (isdigit(prefix[0])) &&
+ ((command == "FMODE") || (command == "MODE") || (command == "KICK") || (command == "TOPIC") || (command == "KILL") || (command == "ADDLINE") || (command == "DELLINE")))
+ {
+ /* Special case, we cannot drop these commands as they've been committed already on a
+ * part of the network by the time we receive them, so in this scenario pretend the
+ * command came from a server to avoid desync.
+ */
- who = ServerInstance->FindUUID(prefix.substr(0, 3));
- if (!who)
- who = this->MyRoot->ServerUser;
- }
- else
- {
- ServerInstance->Logs->Log("m_spanningtree", DEBUG, "Command '%s' from unknown prefix '%s'! Dropping entire command.",
- command.c_str(), prefix.c_str());
- return;
- }
- }
+ who = ServerInstance->FindUUID(prefix.substr(0, 3));
+ if (who)
+ return who;
+ return this->MyRoot->ServerUser;
}
- // Make sure prefix is still good
- direction = who->server;
- prefix = who->uuid;
+ // Unknown prefix
+ return NULL;
+}
+
+void TreeSocket::ProcessConnectedLine(std::string& prefix, std::string& command, parameterlist& params)
+{
+ User* who = FindSource(prefix, command);
+ if (!who)
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Command '%s' from unknown prefix '%s'! Dropping entire command.", command.c_str(), prefix.c_str());
+ return;
+ }
/*
* Check for fake direction here, and drop any instances that are found.
@@ -298,214 +290,63 @@ void TreeSocket::ProcessConnectedLine(std::string& prefix, std::string& command,
* a valid SID or a valid UUID, so that invalid UUID or SID never makes it
* to the higher level functions. -- B
*/
- TreeServer* route_back_again = Utils->BestRouteTo(direction);
- if ((!route_back_again) || (route_back_again->GetSocket() != this))
+ TreeServer* const server = TreeServer::Get(who);
+ if (server->GetSocket() != this)
{
- if (route_back_again)
- ServerInstance->Logs->Log("m_spanningtree",DEBUG,"Protocol violation: Fake direction '%s' from connection '%s'",
- prefix.c_str(),linkID.c_str());
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Protocol violation: Fake direction '%s' from connection '%s'", prefix.c_str(), linkID.c_str());
return;
}
- /*
- * First up, check for any malformed commands (e.g. MODE without a timestamp)
- * and rewrite commands where necessary (SVSMODE -> MODE for services). -- w
- */
- if (command == "SVSMODE") // This isn't in an "else if" so we still force FMODE for changes on channels.
- command = "MODE";
-
- // TODO move all this into Commands
- if (command == "MAP")
- {
- Utils->Creator->HandleMap(params, who);
- }
- else if (command == "SERVER")
- {
- this->RemoteServer(prefix,params);
- }
- else if (command == "ERROR")
- {
- this->Error(params);
- }
- else if (command == "AWAY")
+ // Translate commands coming from servers using an older protocol
+ if (proto_version < ProtocolVersion)
{
- this->Away(prefix,params);
- }
- else if (command == "PING")
- {
- this->LocalPing(prefix,params);
- }
- else if (command == "PONG")
- {
- TreeServer *s = Utils->FindServer(prefix);
- if (s && s->bursting)
- {
- ServerInstance->SNO->WriteGlobalSno('l',"Server \002%s\002 has not finished burst, forcing end of burst (send ENDBURST!)", prefix.c_str());
- s->FinishBurst();
- }
- this->LocalPong(prefix,params);
- }
- else if (command == "VERSION")
- {
- this->ServerVersion(prefix,params);
- }
- else if (command == "ADDLINE")
- {
- this->AddLine(prefix,params);
- }
- else if (command == "DELLINE")
- {
- this->DelLine(prefix,params);
- }
- else if (command == "SAVE")
- {
- this->ForceNick(prefix,params);
- }
- else if (command == "OPERQUIT")
- {
- this->OperQuit(prefix,params);
- }
- else if (command == "IDLE")
- {
- this->Whois(prefix,params);
- }
- else if (command == "PUSH")
- {
- this->Push(prefix,params);
- }
- else if (command == "SQUIT")
- {
- if (params.size() == 2)
- {
- this->Squit(Utils->FindServer(params[0]),params[1]);
- }
- }
- else if (command == "SNONOTICE")
- {
- if (params.size() >= 2)
- {
- ServerInstance->SNO->WriteToSnoMask(params[0][0], "From " + who->nick + ": "+ params[1]);
- params[1] = ":" + params[1];
- Utils->DoOneToAllButSender(prefix, command, params, prefix);
- }
- }
- else if (command == "BURST")
- {
- // Set prefix server as bursting
- TreeServer* ServerSource = Utils->FindServer(prefix);
- if (!ServerSource)
- {
- ServerInstance->SNO->WriteGlobalSno('l', "WTF: Got BURST from a non-server(?): %s", prefix.c_str());
+ if (!PreProcessOldProtocolMessage(who, command, params))
return;
- }
-
- ServerSource->bursting = true;
- Utils->DoOneToAllButSender(prefix, command, params, prefix);
}
- else if (command == "ENDBURST")
- {
- TreeServer* ServerSource = Utils->FindServer(prefix);
- if (!ServerSource)
- {
- ServerInstance->SNO->WriteGlobalSno('l', "WTF: Got ENDBURST from a non-server(?): %s", prefix.c_str());
- return;
- }
- ServerSource->FinishBurst();
- Utils->DoOneToAllButSender(prefix, command, params, prefix);
- }
- else if (command == "ENCAP")
- {
- this->Encap(who, params);
- }
- else if (command == "NICK")
+ ServerCommand* scmd = Utils->Creator->CmdManager.GetHandler(command);
+ CommandBase* cmdbase = scmd;
+ Command* cmd = NULL;
+ if (!scmd)
{
- if (params.size() != 2)
- {
- SendError("Protocol violation: Wrong number of parameters for NICK message");
- return;
- }
-
- if (IS_SERVER(who))
- {
- SendError("Protocol violation: Server changing nick");
- return;
- }
-
- if ((isdigit(params[0][0])) && (params[0] != who->uuid))
- {
- SendError("Protocol violation: User changing nick to an invalid UID - " + params[0]);
- return;
- }
-
- /* Update timestamp on user when they change nicks */
- who->age = atoi(params[1].c_str());
-
- /*
- * On nick messages, check that the nick doesnt already exist here.
- * If it does, perform collision logic.
- */
- bool callfnc = true;
- User* x = ServerInstance->FindNickOnly(params[0]);
- if ((x) && (x != who) && (x->registered == REG_ALL))
+ // Not a special server-to-server command
+ cmd = ServerInstance->Parser.GetHandler(command);
+ if (!cmd)
{
- int collideret = 0;
- /* x is local, who is remote */
- collideret = this->DoCollision(x, who->age, who->ident, who->GetIPString(), who->uuid);
- if (collideret != 1)
+ if (command == "ERROR")
{
- // Remote client lost, or both lost, rewrite this nick change as a change to uuid before
- // forwarding and don't call ForceNickChange() because DoCollision() has done it already
- params[0] = who->uuid;
- callfnc = false;
+ this->Error(params);
+ return;
}
- }
- if (callfnc)
- who->ForceNickChange(params[0].c_str());
- Utils->RouteCommand(route_back_again, command, params, who);
- }
- else
- {
- Command* cmd = ServerInstance->Parser->GetHandler(command);
-
- if (!cmd)
- {
- irc::stringjoiner pmlist(" ", params, 0, params.size() - 1);
- ServerInstance->Logs->Log("m_spanningtree", SPARSE, "Unrecognised S2S command :%s %s %s",
- who->uuid.c_str(), command.c_str(), pmlist.GetJoined().c_str());
- SendError("Unrecognised command '" + command + "' -- possibly loaded mismatched modules");
- return;
- }
- if (params.size() < cmd->min_params)
- {
- irc::stringjoiner pmlist(" ", params, 0, params.size() - 1);
- ServerInstance->Logs->Log("m_spanningtree", SPARSE, "Insufficient parameters for S2S command :%s %s %s",
- who->uuid.c_str(), command.c_str(), pmlist.GetJoined().c_str());
- SendError("Insufficient parameters for command '" + command + "'");
- return;
+ throw ProtocolException("Unknown command");
}
+ cmdbase = cmd;
+ }
- if ((!params.empty()) && (params.back().empty()) && (!cmd->allow_empty_last_param))
- {
- // the last param is empty and the command handler doesn't allow that, check if there will be enough params if we drop the last
- if (params.size()-1 < cmd->min_params)
- return;
- params.pop_back();
- }
+ if (params.size() < cmdbase->min_params)
+ throw ProtocolException("Insufficient parameters");
- CmdResult res = cmd->Handle(params, who);
+ if ((!params.empty()) && (params.back().empty()) && (!cmdbase->allow_empty_last_param))
+ {
+ // the last param is empty and the command handler doesn't allow that, check if there will be enough params if we drop the last
+ if (params.size()-1 < cmdbase->min_params)
+ return;
+ params.pop_back();
+ }
+ CmdResult res;
+ if (scmd)
+ res = scmd->Handle(who, params);
+ else
+ {
+ res = cmd->Handle(params, who);
if (res == CMD_INVALID)
- {
- irc::stringjoiner pmlist(" ", params, 0, params.size() - 1);
- ServerInstance->Logs->Log("m_spanningtree", SPARSE, "Error handling S2S command :%s %s %s",
- who->uuid.c_str(), command.c_str(), pmlist.GetJoined().c_str());
- SendError("Error handling '" + command + "' -- possibly loaded mismatched modules");
- }
- else if (res == CMD_SUCCESS)
- Utils->RouteCommand(route_back_again, command, params, who);
+ throw ProtocolException("Error in command handler");
}
+
+ if (res == CMD_SUCCESS)
+ Utils->RouteCommand(server->GetRoute(), cmdbase, params, who);
}
void TreeSocket::OnTimeout()
@@ -534,7 +375,7 @@ void TreeSocket::Close()
time_t server_uptime = ServerInstance->Time() - this->age;
if (server_uptime)
{
- std::string timestr = Utils->Creator->TimeToStr(server_uptime);
+ std::string timestr = ModuleSpanningTree::TimeToStr(server_uptime);
ServerInstance->SNO->WriteGlobalSno('l', "Connection to '\2%s\2' was established for %s", linkID.c_str(), timestr.c_str());
}
}
diff --git a/src/modules/m_spanningtree/uid.cpp b/src/modules/m_spanningtree/uid.cpp
index 6620dd13a..ac9041ecc 100644
--- a/src/modules/m_spanningtree/uid.cpp
+++ b/src/modules/m_spanningtree/uid.cpp
@@ -23,42 +23,28 @@
#include "commands.h"
#include "utils.h"
-#include "link.h"
-#include "treesocket.h"
#include "treeserver.h"
-#include "resolvers.h"
-CmdResult CommandUID::Handle(const parameterlist &params, User* serversrc)
+CmdResult CommandUID::HandleServer(TreeServer* remoteserver, std::vector<std::string>& params)
{
- SpanningTreeUtilities* Utils = ((ModuleSpanningTree*)(Module*)creator)->Utils;
/** Do we have enough parameters:
* 0 1 2 3 4 5 6 7 8 9 (n-1)
* UID uuid age nick host dhost ident ip.string signon +modes (modepara) :gecos
*/
- time_t age_t = ConvToInt(params[1]);
- time_t signon = ConvToInt(params[7]);
+ time_t age_t = ServerCommand::ExtractTS(params[1]);
+ time_t signon = ServerCommand::ExtractTS(params[7]);
std::string empty;
- std::string modestr(params[8]);
+ const std::string& modestr = params[8];
- TreeServer* remoteserver = Utils->FindServer(serversrc->server);
-
- if (!remoteserver)
- return CMD_INVALID;
/* Is this a valid UID, and not misrouted? */
- if (params[0].length() != 9 || params[0].substr(0,3) != serversrc->uuid)
- return CMD_INVALID;
+ if (params[0].length() != UIDGenerator::UUID_LENGTH || params[0].compare(0, 3, remoteserver->GetID()))
+ throw ProtocolException("Bogus UUID");
/* Check parameters for validity before introducing the client, discovered by dmb */
- if (!age_t)
- return CMD_INVALID;
- if (!signon)
- return CMD_INVALID;
if (modestr[0] != '+')
- return CMD_INVALID;
- TreeSocket* sock = remoteserver->GetRoute()->GetSocket();
+ throw ProtocolException("Invalid mode string");
/* check for collision */
- User* const collideswith = ServerInstance->FindNickOnly(params[2]);
-
+ User* collideswith = ServerInstance->FindNickOnly(params[2]);
if ((collideswith) && (collideswith->registered != REG_ALL))
{
// User that the incoming user is colliding with is not fully registered, we force nick change the
@@ -75,121 +61,113 @@ CmdResult CommandUID::Handle(const parameterlist &params, User* serversrc)
/*
* Nick collision.
*/
- int collide = sock->DoCollision(collideswith, age_t, params[5], params[6], params[0]);
- ServerInstance->Logs->Log("m_spanningtree",DEBUG,"*** Collision on %s, collide=%d", params[2].c_str(), collide);
+ int collide = Utils->DoCollision(collideswith, remoteserver, age_t, params[5], params[6], params[0]);
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "*** Collision on %s, collide=%d", params[2].c_str(), collide);
if (collide != 1)
{
- /* remote client lost, make sure we change their nick for the hash too
- *
- * This alters the line that will be sent to other servers, which
- * commands normally shouldn't do; hence the required const_cast.
- */
- const_cast<parameterlist&>(params)[2] = params[0];
+ // Remote client lost, make sure we change their nick for the hash too
+ params[2] = params[0];
}
}
/* IMPORTANT NOTE: For remote users, we pass the UUID in the constructor. This automatically
* sets it up in the UUID hash for us.
+ *
+ * If the UUID already exists User::User() throws an exception which causes this connection to be closed.
*/
- User* _new = NULL;
- try
- {
- _new = new RemoteUser(params[0], remoteserver->GetName());
- }
- catch (...)
- {
- ServerInstance->Logs->Log("m_spanningtree", DEFAULT, "Duplicate UUID %s in client introduction", params[0].c_str());
- return CMD_INVALID;
- }
- (*(ServerInstance->Users->clientlist))[params[2]] = _new;
+ RemoteUser* _new = new RemoteUser(params[0], remoteserver);
+ ServerInstance->Users->clientlist[params[2]] = _new;
_new->nick = params[2];
_new->host = params[3];
_new->dhost = params[4];
_new->ident = params[5];
- _new->fullname = params[params.size() - 1];
+ _new->fullname = params.back();
_new->registered = REG_ALL;
_new->signon = signon;
_new->age = age_t;
- /* we need to remove the + from the modestring, so we can do our stuff */
- std::string::size_type pos_after_plus = modestr.find_first_not_of('+');
- if (pos_after_plus != std::string::npos)
- modestr = modestr.substr(pos_after_plus);
-
unsigned int paramptr = 9;
- for (std::string::iterator v = modestr.begin(); v != modestr.end(); v++)
+
+ for (std::string::const_iterator v = modestr.begin(); v != modestr.end(); ++v)
{
- /* For each mode thats set, increase counter */
+ // Accept more '+' chars, for now
+ if (*v == '+')
+ continue;
+
+ /* For each mode thats set, find the mode handler and set it on the new user */
ModeHandler* mh = ServerInstance->Modes->FindMode(*v, MODETYPE_USER);
+ if (!mh)
+ throw ProtocolException("Unrecognised mode '" + std::string(1, *v) + "'");
- if (mh)
+ if (mh->GetNumParams(true))
{
- if (mh->GetNumParams(true))
- {
- if (paramptr >= params.size() - 1)
- return CMD_INVALID;
- std::string mp = params[paramptr++];
- /* IMPORTANT NOTE:
- * All modes are assumed to succeed here as they are being set by a remote server.
- * Modes CANNOT FAIL here. If they DO fail, then the failure is ignored. This is important
- * to note as all but one modules currently cannot ever fail in this situation, except for
- * m_servprotect which specifically works this way to prevent the mode being set ANYWHERE
- * but here, at client introduction. You may safely assume this behaviour is standard and
- * will not change in future versions if you want to make use of this protective behaviour
- * yourself.
- */
- mh->OnModeChange(_new, _new, NULL, mp, true);
- }
- else
- mh->OnModeChange(_new, _new, NULL, empty, true);
- _new->SetMode(*v, true);
+ if (paramptr >= params.size() - 1)
+ throw ProtocolException("Out of parameters while processing modes");
+ std::string mp = params[paramptr++];
+ /* IMPORTANT NOTE:
+ * All modes are assumed to succeed here as they are being set by a remote server.
+ * Modes CANNOT FAIL here. If they DO fail, then the failure is ignored. This is important
+ * to note as all but one modules currently cannot ever fail in this situation, except for
+ * m_servprotect which specifically works this way to prevent the mode being set ANYWHERE
+ * but here, at client introduction. You may safely assume this behaviour is standard and
+ * will not change in future versions if you want to make use of this protective behaviour
+ * yourself.
+ */
+ mh->OnModeChange(_new, _new, NULL, mp, true);
}
+ else
+ mh->OnModeChange(_new, _new, NULL, empty, true);
+ _new->SetMode(mh, true);
}
- /* now we've done with modes processing, put the + back for remote servers */
- if (modestr[0] != '+')
- modestr = "+" + modestr;
-
_new->SetClientIP(params[6].c_str());
- ServerInstance->Users->AddGlobalClone(_new);
- remoteserver->SetUserCount(1); // increment by 1
+ ServerInstance->Users->AddClone(_new);
+ remoteserver->UserCount++;
bool dosend = true;
- if ((Utils->quiet_bursts && remoteserver->bursting) || ServerInstance->SilentULine(_new->server))
+ if ((Utils->quiet_bursts && remoteserver->bursting) || _new->server->IsSilentULine())
dosend = false;
if (dosend)
- ServerInstance->SNO->WriteToSnoMask('C',"Client connecting at %s: %s (%s) [%s]", _new->server.c_str(), _new->GetFullRealHost().c_str(), _new->GetIPString(), _new->fullname.c_str());
+ ServerInstance->SNO->WriteToSnoMask('C',"Client connecting at %s: %s (%s) [%s]", remoteserver->GetName().c_str(), _new->GetFullRealHost().c_str(), _new->GetIPString().c_str(), _new->fullname.c_str());
- FOREACH_MOD(I_OnPostConnect,OnPostConnect(_new));
+ FOREACH_MOD(OnPostConnect, (_new));
return CMD_SUCCESS;
}
-CmdResult CommandFHost::Handle(const parameterlist &params, User* src)
+CmdResult CommandFHost::HandleRemote(RemoteUser* src, std::vector<std::string>& params)
{
- if (IS_SERVER(src))
- return CMD_FAILURE;
- src->ChangeDisplayedHost(params[0].c_str());
+ src->ChangeDisplayedHost(params[0]);
return CMD_SUCCESS;
}
-CmdResult CommandFIdent::Handle(const parameterlist &params, User* src)
+CmdResult CommandFIdent::HandleRemote(RemoteUser* src, std::vector<std::string>& params)
{
- if (IS_SERVER(src))
- return CMD_FAILURE;
- src->ChangeIdent(params[0].c_str());
+ src->ChangeIdent(params[0]);
return CMD_SUCCESS;
}
-CmdResult CommandFName::Handle(const parameterlist &params, User* src)
+CmdResult CommandFName::HandleRemote(RemoteUser* src, std::vector<std::string>& params)
{
- if (IS_SERVER(src))
- return CMD_FAILURE;
- src->ChangeName(params[0].c_str());
+ src->ChangeName(params[0]);
return CMD_SUCCESS;
}
+CommandUID::Builder::Builder(User* user)
+ : CmdBuilder(TreeServer::Get(user)->GetID(), "UID")
+{
+ push(user->uuid);
+ push_int(user->age);
+ push(user->nick);
+ push(user->host);
+ push(user->dhost);
+ push(user->ident);
+ push(user->GetIPString());
+ push_int(user->signon);
+ push('+').push_raw(user->FormatModes(true));
+ push_last(user->fullname);
+}
diff --git a/src/modules/m_spanningtree/utils.cpp b/src/modules/m_spanningtree/utils.cpp
index 3bd0aa2c7..d81bfa934 100644
--- a/src/modules/m_spanningtree/utils.cpp
+++ b/src/modules/m_spanningtree/utils.cpp
@@ -21,16 +21,15 @@
#include "inspircd.h"
-#include "socket.h"
-#include "xline.h"
-#include "socketengine.h"
#include "main.h"
#include "utils.h"
#include "treeserver.h"
-#include "link.h"
#include "treesocket.h"
#include "resolvers.h"
+#include "commandbuilder.h"
+
+SpanningTreeUtilities* Utils = NULL;
/* Create server sockets off a listener. */
ModResult ModuleSpanningTree::OnAcceptConnection(int newsock, ListenSocket* from, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server)
@@ -45,7 +44,7 @@ ModResult ModuleSpanningTree::OnAcceptConnection(int newsock, ListenSocket* from
if (*i == "*" || *i == incomingip || irc::sockets::cidr_mask(*i).match(*client))
{
/* we don't need to do anything with the pointer, creating it stores it in the necessary places */
- new TreeSocket(Utils, newsock, from, client, server);
+ new TreeSocket(newsock, from, client, server);
return MOD_RES_ALLOW;
}
}
@@ -61,10 +60,10 @@ ModResult ModuleSpanningTree::OnAcceptConnection(int newsock, ListenSocket* from
*/
TreeServer* SpanningTreeUtilities::FindServer(const std::string &ServerName)
{
- if (ServerInstance->IsSID(ServerName))
+ if (InspIRCd::IsSID(ServerName))
return this->FindServerID(ServerName);
- server_hash::iterator iter = serverlist.find(ServerName.c_str());
+ server_hash::iterator iter = serverlist.find(ServerName);
if (iter != serverlist.end())
{
return iter->second;
@@ -83,8 +82,6 @@ TreeServer* SpanningTreeUtilities::FindServer(const std::string &ServerName)
*/
TreeServer* SpanningTreeUtilities::BestRouteTo(const std::string &ServerName)
{
- if (ServerName.c_str() == TreeRoot->GetName() || ServerName == ServerInstance->Config->GetSID())
- return NULL;
TreeServer* Found = FindServer(ServerName);
if (Found)
{
@@ -96,9 +93,7 @@ TreeServer* SpanningTreeUtilities::BestRouteTo(const std::string &ServerName)
User *u = ServerInstance->FindNick(ServerName);
if (u)
{
- Found = FindServer(u->server);
- if (Found)
- return Found->GetRoute();
+ return TreeServer::Get(u)->GetRoute();
}
return NULL;
@@ -130,24 +125,19 @@ TreeServer* SpanningTreeUtilities::FindServerID(const std::string &id)
return NULL;
}
-SpanningTreeUtilities::SpanningTreeUtilities(ModuleSpanningTree* C) : Creator(C)
+SpanningTreeUtilities::SpanningTreeUtilities(ModuleSpanningTree* C)
+ : Creator(C), TreeRoot(NULL)
{
- ServerInstance->Logs->Log("m_spanningtree",DEBUG,"***** Using SID for hash: %s *****", ServerInstance->Config->GetSID().c_str());
-
- this->TreeRoot = new TreeServer(this, ServerInstance->Config->ServerName, ServerInstance->Config->ServerDesc, ServerInstance->Config->GetSID());
- this->ReadConfiguration();
+ ServerInstance->Timers.AddTimer(&RefreshTimer);
}
CullResult SpanningTreeUtilities::cull()
{
- while (TreeRoot->ChildCount())
+ const TreeServer::ChildServers& children = TreeRoot->GetChildren();
+ while (!children.empty())
{
- TreeServer* child_server = TreeRoot->GetChild(0);
- if (child_server)
- {
- TreeSocket* sock = child_server->GetSocket();
- sock->Close();
- }
+ TreeSocket* sock = children.front()->GetSocket();
+ sock->Close();
}
for(std::map<TreeSocket*, std::pair<std::string, int> >::iterator i = timeoutlist.begin(); i != timeoutlist.end(); ++i)
@@ -165,26 +155,19 @@ SpanningTreeUtilities::~SpanningTreeUtilities()
delete TreeRoot;
}
-void SpanningTreeUtilities::AddThisServer(TreeServer* server, TreeServerList &list)
-{
- if (list.find(server) == list.end())
- list[server] = server;
-}
-
/* returns a list of DIRECT servernames for a specific channel */
-void SpanningTreeUtilities::GetListOfServersForChannel(Channel* c, TreeServerList &list, char status, const CUList &exempt_list)
+void SpanningTreeUtilities::GetListOfServersForChannel(Channel* c, TreeSocketSet& list, char status, const CUList& exempt_list)
{
unsigned int minrank = 0;
if (status)
{
- ModeHandler* mh = ServerInstance->Modes->FindPrefix(status);
+ PrefixMode* mh = ServerInstance->Modes->FindPrefix(status);
if (mh)
minrank = mh->GetPrefixRank();
}
- const UserMembList *ulist = c->GetUsers();
-
- for (UserMembCIter i = ulist->begin(); i != ulist->end(); i++)
+ const Channel::MemberMap& ulist = c->GetUsers();
+ for (Channel::MemberMap::const_iterator i = ulist.begin(); i != ulist.end(); ++i)
{
if (IS_LOCAL(i->first))
continue;
@@ -194,86 +177,45 @@ void SpanningTreeUtilities::GetListOfServersForChannel(Channel* c, TreeServerLis
if (exempt_list.find(i->first) == exempt_list.end())
{
- TreeServer* best = this->BestRouteTo(i->first->server);
- if (best)
- AddThisServer(best,list);
+ TreeServer* best = TreeServer::Get(i->first);
+ list.insert(best->GetSocket());
}
}
return;
}
-bool SpanningTreeUtilities::DoOneToAllButSender(const std::string &prefix, const std::string &command, const parameterlist &params, const std::string& omit)
+void SpanningTreeUtilities::DoOneToAllButSender(const CmdBuilder& params, TreeServer* omitroute)
{
- TreeServer* omitroute = this->BestRouteTo(omit);
- std::string FullLine = ":" + prefix + " " + command;
- unsigned int words = params.size();
- for (unsigned int x = 0; x < words; x++)
- {
- FullLine = FullLine + " " + params[x];
- }
- unsigned int items = this->TreeRoot->ChildCount();
- for (unsigned int x = 0; x < items; x++)
+ const std::string& FullLine = params.str();
+
+ const TreeServer::ChildServers& children = TreeRoot->GetChildren();
+ for (TreeServer::ChildServers::const_iterator i = children.begin(); i != children.end(); ++i)
{
- TreeServer* Route = this->TreeRoot->GetChild(x);
- // Send the line IF:
- // The route has a socket (its a direct connection)
- // The route isnt the one to be omitted
- // The route isnt the path to the one to be omitted
- if ((Route) && (Route->GetSocket()) && (Route->GetName() != omit) && (omitroute != Route))
+ TreeServer* Route = *i;
+ // Send the line if the route isn't the path to the one to be omitted
+ if (Route != omitroute)
{
- TreeSocket* Sock = Route->GetSocket();
- if (Sock)
- Sock->WriteLine(FullLine);
+ Route->GetSocket()->WriteLine(FullLine);
}
}
- return true;
}
-bool SpanningTreeUtilities::DoOneToMany(const std::string &prefix, const std::string &command, const parameterlist &params)
+bool SpanningTreeUtilities::DoOneToOne(const CmdBuilder& params, const std::string& target)
{
- std::string FullLine = ":" + prefix + " " + command;
- unsigned int words = params.size();
- for (unsigned int x = 0; x < words; x++)
- {
- FullLine = FullLine + " " + params[x];
- }
- unsigned int items = this->TreeRoot->ChildCount();
- for (unsigned int x = 0; x < items; x++)
- {
- TreeServer* Route = this->TreeRoot->GetChild(x);
- if (Route && Route->GetSocket())
- {
- TreeSocket* Sock = Route->GetSocket();
- if (Sock)
- Sock->WriteLine(FullLine);
- }
- }
+ TreeServer* Route = this->BestRouteTo(target);
+ if (!Route)
+ return false;
+
+ DoOneToOne(params, Route);
return true;
}
-bool SpanningTreeUtilities::DoOneToOne(const std::string &prefix, const std::string &command, const parameterlist &params, const std::string& target)
+void SpanningTreeUtilities::DoOneToOne(const CmdBuilder& params, Server* server)
{
- TreeServer* Route = this->BestRouteTo(target);
- if (Route)
- {
- std::string FullLine = ":" + prefix + " " + command;
- unsigned int words = params.size();
- for (unsigned int x = 0; x < words; x++)
- {
- FullLine = FullLine + " " + params[x];
- }
- if (Route && Route->GetSocket())
- {
- TreeSocket* Sock = Route->GetSocket();
- if (Sock)
- Sock->WriteLine(FullLine);
- }
- return true;
- }
- else
- {
- return false;
- }
+ TreeServer* ts = static_cast<TreeServer*>(server);
+ TreeSocket* sock = ts->GetSocket();
+ if (sock)
+ sock->WriteLine(params);
}
void SpanningTreeUtilities::RefreshIPCache()
@@ -284,28 +226,27 @@ void SpanningTreeUtilities::RefreshIPCache()
Link* L = *i;
if (!L->Port)
{
- ServerInstance->Logs->Log("m_spanningtree",DEFAULT,"m_spanningtree: Ignoring a link block without a port.");
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Ignoring a link block without a port.");
/* Invalid link block */
continue;
}
- if (L->AllowMask.length())
- ValidIPs.push_back(L->AllowMask);
+ ValidIPs.insert(ValidIPs.end(), L->AllowMasks.begin(), L->AllowMasks.end());
irc::sockets::sockaddrs dummy;
bool ipvalid = irc::sockets::aptosa(L->IPAddr, L->Port, dummy);
if ((L->IPAddr == "*") || (ipvalid))
ValidIPs.push_back(L->IPAddr);
- else
+ else if (this->Creator->DNS)
{
+ SecurityIPResolver* sr = new SecurityIPResolver(Creator, *this->Creator->DNS, L->IPAddr, L, DNS::QUERY_AAAA);
try
{
- bool cached = false;
- SecurityIPResolver* sr = new SecurityIPResolver(Creator, this, L->IPAddr, L, cached, DNS_QUERY_AAAA);
- ServerInstance->AddResolver(sr, cached);
+ this->Creator->DNS->Process(sr);
}
- catch (...)
+ catch (DNS::Exception &)
{
+ delete sr;
}
}
}
@@ -319,7 +260,6 @@ void SpanningTreeUtilities::ReadConfiguration()
HideULines = security->getBool("hideulines");
AnnounceTSChange = options->getBool("announcets");
AllowOptCommon = options->getBool("allowmismatch");
- ChallengeResponse = !security->getBool("disablehmac");
quiet_bursts = ServerInstance->Config->ConfValue("performance")->getBool("quietbursts");
PingWarnTime = options->getInt("pingwarning");
PingFreq = options->getInt("serverpingfreq");
@@ -339,14 +279,18 @@ void SpanningTreeUtilities::ReadConfiguration()
reference<Link> L = new Link(tag);
std::string linkname = tag->getString("name");
L->Name = linkname.c_str();
- L->AllowMask = tag->getString("allowmask");
+
+ irc::spacesepstream sep = tag->getString("allowmask");
+ for (std::string s; sep.GetToken(s);)
+ L->AllowMasks.push_back(s);
+
L->IPAddr = tag->getString("ipaddr");
L->Port = tag->getInt("port");
L->SendPass = tag->getString("sendpass", tag->getString("password"));
L->RecvPass = tag->getString("recvpass", tag->getString("password"));
L->Fingerprint = tag->getString("fingerprint");
L->HiddenFromStats = tag->getBool("statshidden");
- L->Timeout = tag->getInt("timeout", 30);
+ L->Timeout = tag->getDuration("timeout", 30);
L->Hook = tag->getString("ssl");
L->Bind = tag->getString("bind");
L->Hidden = tag->getBool("hidden");
@@ -357,8 +301,8 @@ void SpanningTreeUtilities::ReadConfiguration()
if (L->Name.find('.') == std::string::npos)
throw ModuleException("The link name '"+assign(L->Name)+"' is invalid as it must contain at least one '.' character");
- if (L->Name.length() > 64)
- throw ModuleException("The link name '"+assign(L->Name)+"' is invalid as it is longer than 64 characters");
+ if (L->Name.length() > ServerInstance->Config->Limits.MaxHost)
+ throw ModuleException("The link name '"+assign(L->Name)+"' is invalid as it is longer than " + ConvToStr(ServerInstance->Config->Limits.MaxHost) + " characters");
if (L->RecvPass.empty())
throw ModuleException("Invalid configuration for server '"+assign(L->Name)+"', recvpass not defined");
@@ -375,11 +319,11 @@ void SpanningTreeUtilities::ReadConfiguration()
if (L->IPAddr.empty())
{
L->IPAddr = "*";
- ServerInstance->Logs->Log("m_spanningtree",DEFAULT,"Configuration warning: Link block '" + assign(L->Name) + "' has no IP defined! This will allow any IP to connect as this server, and MAY not be what you want.");
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Configuration warning: Link block '" + assign(L->Name) + "' has no IP defined! This will allow any IP to connect as this server, and MAY not be what you want.");
}
if (!L->Port)
- ServerInstance->Logs->Log("m_spanningtree",DEFAULT,"Configuration warning: Link block '" + assign(L->Name) + "' has no port defined, you will not be able to /connect it.");
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Configuration warning: Link block '" + assign(L->Name) + "' has no port defined, you will not be able to /connect it.");
L->Fingerprint.erase(std::remove(L->Fingerprint.begin(), L->Fingerprint.end(), ':'), L->Fingerprint.end());
LinkBlocks.push_back(L);
@@ -390,7 +334,7 @@ void SpanningTreeUtilities::ReadConfiguration()
{
ConfigTag* tag = i->second;
reference<Autoconnect> A = new Autoconnect(tag);
- A->Period = tag->getInt("period");
+ A->Period = tag->getDuration("period", 60, 1);
A->NextConnectTime = ServerInstance->Time() + A->Period;
A->position = -1;
irc::spacesepstream ss(tag->getString("server"));
@@ -400,11 +344,6 @@ void SpanningTreeUtilities::ReadConfiguration()
A->servers.push_back(server);
}
- if (A->Period <= 0)
- {
- throw ModuleException("Invalid configuration for autoconnect, period not a positive integer!");
- }
-
if (A->servers.empty())
{
throw ModuleException("Invalid configuration for autoconnect, server cannot be empty!");
@@ -413,6 +352,9 @@ void SpanningTreeUtilities::ReadConfiguration()
AutoconnectBlocks.push_back(A);
}
+ for (server_hash::const_iterator i = serverlist.begin(); i != serverlist.end(); ++i)
+ i->second->CheckULine();
+
RefreshIPCache();
}
@@ -428,3 +370,21 @@ Link* SpanningTreeUtilities::FindLink(const std::string& name)
}
return NULL;
}
+
+void SpanningTreeUtilities::SendChannelMessage(const std::string& prefix, Channel* target, const std::string& text, char status, const CUList& exempt_list, const char* message_type, TreeSocket* omit)
+{
+ CmdBuilder msg(prefix, message_type);
+ msg.push_raw(' ');
+ if (status != 0)
+ msg.push_raw(status);
+ msg.push_raw(target->name).push_last(text);
+
+ TreeSocketSet list;
+ this->GetListOfServersForChannel(target, list, status, exempt_list);
+ for (TreeSocketSet::iterator i = list.begin(); i != list.end(); ++i)
+ {
+ TreeSocket* Sock = *i;
+ if (Sock != omit)
+ Sock->WriteLine(msg);
+ }
+}
diff --git a/src/modules/m_spanningtree/utils.h b/src/modules/m_spanningtree/utils.h
index a0543b6bd..bc2ea24a1 100644
--- a/src/modules/m_spanningtree/utils.h
+++ b/src/modules/m_spanningtree/utils.h
@@ -20,10 +20,10 @@
*/
-#ifndef M_SPANNINGTREE_UTILS_H
-#define M_SPANNINGTREE_UTILS_H
+#pragma once
#include "inspircd.h"
+#include "cachetimer.h"
/* Foward declarations */
class TreeServer;
@@ -32,24 +32,24 @@ class Link;
class Autoconnect;
class ModuleSpanningTree;
class SpanningTreeUtilities;
+class CmdBuilder;
+
+extern SpanningTreeUtilities* Utils;
/* This hash_map holds the hash equivalent of the server
* tree, used for rapid linear lookups.
*/
-#ifdef HASHMAP_DEPRECATED
- typedef nspace::hash_map<std::string, TreeServer*, nspace::insensitive, irc::StrHashComp> server_hash;
-#else
- typedef nspace::hash_map<std::string, TreeServer*, nspace::hash<std::string>, irc::StrHashComp> server_hash;
-#endif
-
-typedef std::map<TreeServer*,TreeServer*> TreeServerList;
+typedef TR1NS::unordered_map<std::string, TreeServer*, irc::insensitive, irc::StrHashComp> server_hash;
/** Contains helper functions and variables for this module,
* and keeps them out of the global namespace
*/
class SpanningTreeUtilities : public classbase
{
+ CacheRefreshTimer RefreshTimer;
+
public:
+ typedef std::set<TreeSocket*> TreeSocketSet;
typedef std::map<TreeSocket*, std::pair<std::string, int> > TimeoutList;
/** Creator module
@@ -100,14 +100,6 @@ class SpanningTreeUtilities : public classbase
*/
std::vector<reference<Autoconnect> > AutoconnectBlocks;
- /** True (default) if we are to use challenge-response HMAC
- * to authenticate passwords.
- *
- * NOTE: This defaults to on, but should be turned off if
- * you are linking to an older version of inspircd.
- */
- bool ChallengeResponse;
-
/** Ping frequency of server to server links
*/
int PingFreq;
@@ -124,31 +116,32 @@ class SpanningTreeUtilities : public classbase
*/
~SpanningTreeUtilities();
- void RouteCommand(TreeServer*, const std::string&, const parameterlist&, User*);
+ void RouteCommand(TreeServer* origin, CommandBase* cmd, const parameterlist& parameters, User* user);
/** Send a message from this server to one other local or remote
*/
- bool DoOneToOne(const std::string &prefix, const std::string &command, const parameterlist &params, const std::string& target);
+ bool DoOneToOne(const CmdBuilder& params, const std::string& target);
+ void DoOneToOne(const CmdBuilder& params, Server* target);
/** Send a message from this server to all but one other, local or remote
*/
- bool DoOneToAllButSender(const std::string &prefix, const std::string &command, const parameterlist &params, const std::string& omit);
+ void DoOneToAllButSender(const CmdBuilder& params, TreeServer* omit);
/** Send a message from this server to all others
*/
- bool DoOneToMany(const std::string &prefix, const std::string &command, const parameterlist &params);
+ void DoOneToMany(const CmdBuilder& params);
/** Read the spanningtree module's tags from the config file
*/
void ReadConfiguration();
- /** Add a server to the server list for GetListOfServersForChannel
+ /** Handle nick collision
*/
- void AddThisServer(TreeServer* server, TreeServerList &list);
+ int DoCollision(User* u, TreeServer* server, time_t remotets, const std::string& remoteident, const std::string& remoteip, const std::string& remoteuid);
/** Compile a list of servers which contain members of channel c
*/
- void GetListOfServersForChannel(Channel* c, TreeServerList &list, char status, const CUList &exempt_list);
+ void GetListOfServersForChannel(Channel* c, TreeSocketSet& list, char status, const CUList& exempt_list);
/** Find a server by name
*/
@@ -173,6 +166,13 @@ class SpanningTreeUtilities : public classbase
/** Refresh the IP cache used for allowing inbound connections
*/
void RefreshIPCache();
+
+ /** Sends a PRIVMSG or a NOTICE to a channel obeying an exempt list and an optional prefix
+ */
+ void SendChannelMessage(const std::string& prefix, Channel* target, const std::string& text, char status, const CUList& exempt_list, const char* message_type, TreeSocket* omit = NULL);
};
-#endif
+inline void SpanningTreeUtilities::DoOneToMany(const CmdBuilder& params)
+{
+ DoOneToAllButSender(params, NULL);
+}
diff --git a/src/modules/m_spanningtree/version.cpp b/src/modules/m_spanningtree/version.cpp
deleted file mode 100644
index e08d13e6e..000000000
--- a/src/modules/m_spanningtree/version.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-#include "socket.h"
-#include "xline.h"
-#include "socketengine.h"
-
-#include "main.h"
-#include "utils.h"
-#include "treeserver.h"
-#include "treesocket.h"
-
-/* $ModDep: m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h */
-
-bool TreeSocket::ServerVersion(const std::string &prefix, parameterlist &params)
-{
- if (params.size() < 1)
- return true;
-
- TreeServer* ServerSource = Utils->FindServer(prefix);
-
- if (ServerSource)
- {
- ServerSource->SetVersion(params[0]);
- }
- params[0] = ":" + params[0];
- Utils->DoOneToAllButSender(prefix,"VERSION",params,prefix);
- return true;
-}
-
diff --git a/src/modules/m_sqlauth.cpp b/src/modules/m_sqlauth.cpp
index df97145be..1ffb3305a 100644
--- a/src/modules/m_sqlauth.cpp
+++ b/src/modules/m_sqlauth.cpp
@@ -18,10 +18,9 @@
#include "inspircd.h"
-#include "sql.h"
-#include "hash.h"
-
-/* $ModDesc: Allow/Deny connections based upon an arbitrary SQL table */
+#include "modules/sql.h"
+#include "modules/hash.h"
+#include "modules/ssl.h"
enum AuthState {
AUTH_STATE_NONE = 0,
@@ -39,8 +38,8 @@ class AuthQuery : public SQLQuery
: SQLQuery(me), uid(u), pendingExt(e), verbose(v)
{
}
-
- void OnResult(SQLResult& res)
+
+ void OnResult(SQLResult& res) CXX11_OVERRIDE
{
User* user = ServerInstance->FindNick(uid);
if (!user)
@@ -57,7 +56,7 @@ class AuthQuery : public SQLQuery
}
}
- void OnError(SQLerror& error)
+ void OnError(SQLerror& error) CXX11_OVERRIDE
{
User* user = ServerInstance->FindNick(uid);
if (!user)
@@ -83,15 +82,7 @@ class ModuleSQLAuth : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(pendingExt);
- OnRehash(NULL);
- Implementation eventlist[] = { I_OnCheckReady, I_OnRehash, I_OnUserRegister };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ConfigTag* conf = ServerInstance->Config->ConfValue("sqlauth");
std::string dbid = conf->getString("dbid");
@@ -105,7 +96,7 @@ class ModuleSQLAuth : public Module
verbose = conf->getBool("verbose");
}
- ModResult OnUserRegister(LocalUser* user)
+ ModResult OnUserRegister(LocalUser* user) CXX11_OVERRIDE
{
// Note this is their initial (unresolved) connect block
ConfigTag* tag = user->MyClass->config;
@@ -139,12 +130,15 @@ class ModuleSQLAuth : public Module
if (sha256)
userinfo["sha256pass"] = sha256->hexsum(user->password);
+ const std::string certfp = SSLClientCert::GetFingerprint(&user->eh);
+ userinfo["certfp"] = certfp;
+
SQL->submit(new AuthQuery(this, user->uuid, pendingExt, verbose), freeformquery, userinfo);
return MOD_RES_PASSTHRU;
}
- ModResult OnCheckReady(LocalUser* user)
+ ModResult OnCheckReady(LocalUser* user) CXX11_OVERRIDE
{
switch (pendingExt.get(user))
{
@@ -159,7 +153,7 @@ class ModuleSQLAuth : public Module
return MOD_RES_PASSTHRU;
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Allow/Deny connections based upon an arbitrary SQL table", VF_VENDOR);
}
diff --git a/src/modules/m_sqloper.cpp b/src/modules/m_sqloper.cpp
index ae581cc4b..d6581682c 100644
--- a/src/modules/m_sqloper.cpp
+++ b/src/modules/m_sqloper.cpp
@@ -18,24 +18,8 @@
#include "inspircd.h"
-#include "sql.h"
-#include "hash.h"
-
-/* $ModDesc: Allows storage of oper credentials in an SQL table */
-
-static bool OneOfMatches(const char* host, const char* ip, const std::string& hostlist)
-{
- std::stringstream hl(hostlist);
- std::string xhost;
- while (hl >> xhost)
- {
- if (InspIRCd::Match(host, xhost, ascii_case_insensitive_map) || InspIRCd::MatchCIDR(ip, xhost, ascii_case_insensitive_map))
- {
- return true;
- }
- }
- return false;
-}
+#include "modules/sql.h"
+#include "modules/hash.h"
class OpMeQuery : public SQLQuery
{
@@ -46,9 +30,9 @@ class OpMeQuery : public SQLQuery
{
}
- void OnResult(SQLResult& res)
+ void OnResult(SQLResult& res) CXX11_OVERRIDE
{
- ServerInstance->Logs->Log("m_sqloper",DEBUG, "SQLOPER: result for %s", uid.c_str());
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "result for %s", uid.c_str());
User* user = ServerInstance->FindNick(uid);
if (!user)
return;
@@ -57,30 +41,17 @@ class OpMeQuery : public SQLQuery
SQLEntries row;
while (res.GetRow(row))
{
-#if 0
- parameterlist cols;
- res.GetCols(cols);
-
- std::vector<KeyVal>* items;
- reference<ConfigTag> tag = ConfigTag::create("oper", "<m_sqloper>", 0, items);
- for(unsigned int i=0; i < cols.size(); i++)
- {
- if (!row[i].nul)
- items->insert(std::make_pair(cols[i], row[i]));
- }
-#else
if (OperUser(user, row[0], row[1]))
return;
-#endif
}
- ServerInstance->Logs->Log("m_sqloper",DEBUG, "SQLOPER: no matches for %s (checked %d rows)", uid.c_str(), res.Rows());
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "no matches for %s (checked %d rows)", uid.c_str(), res.Rows());
// nobody succeeded... fall back to OPER
fallback();
}
- void OnError(SQLerror& error)
+ void OnError(SQLerror& error) CXX11_OVERRIDE
{
- ServerInstance->Logs->Log("m_sqloper",DEFAULT, "SQLOPER: query failed (%s)", error.Str());
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "query failed (%s)", error.Str());
fallback();
}
@@ -90,7 +61,7 @@ class OpMeQuery : public SQLQuery
if (!user)
return;
- Command* oper_command = ServerInstance->Parser->GetHandler("OPER");
+ Command* oper_command = ServerInstance->Parser.GetHandler("OPER");
if (oper_command)
{
@@ -101,16 +72,16 @@ class OpMeQuery : public SQLQuery
}
else
{
- ServerInstance->Logs->Log("m_sqloper",SPARSE, "BUG: WHAT?! Why do we have no OPER command?!");
+ ServerInstance->Logs->Log(MODNAME, LOG_SPARSE, "BUG: WHAT?! Why do we have no OPER command?!");
}
}
bool OperUser(User* user, const std::string &pattern, const std::string &type)
{
- OperIndex::iterator iter = ServerInstance->Config->oper_blocks.find(" " + type);
- if (iter == ServerInstance->Config->oper_blocks.end())
+ ServerConfig::OperIndex::const_iterator iter = ServerInstance->Config->OperTypes.find(type);
+ if (iter == ServerInstance->Config->OperTypes.end())
{
- ServerInstance->Logs->Log("m_sqloper",DEFAULT, "SQLOPER: bad type '%s' in returned row for oper %s", type.c_str(), username.c_str());
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "bad type '%s' in returned row for oper %s", type.c_str(), username.c_str());
return false;
}
OperInfo* ifo = iter->second;
@@ -119,7 +90,7 @@ class OpMeQuery : public SQLQuery
hostname.append("@").append(user->host);
- if (OneOfMatches(hostname.c_str(), user->GetIPString(), pattern))
+ if (InspIRCd::MatchMask(pattern, hostname, user->GetIPString()))
{
/* Opertype and host match, looks like this is it. */
@@ -140,15 +111,7 @@ class ModuleSQLOper : public Module
public:
ModuleSQLOper() : SQL(this, "SQL") {}
- void init()
- {
- OnRehash(NULL);
-
- Implementation eventlist[] = { I_OnRehash, I_OnPreCommand };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ConfigTag* tag = ServerInstance->Config->ConfValue("sqloper");
@@ -162,7 +125,7 @@ public:
query = tag->getString("query", "SELECT hostname as host, type FROM ircd_opers WHERE username='$username' AND password='$password'");
}
- ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line)
+ ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line) CXX11_OVERRIDE
{
if (validated && command == "OPER" && parameters.size() >= 2)
{
@@ -172,7 +135,7 @@ public:
/* Query is in progress, it will re-invoke OPER if needed */
return MOD_RES_DENY;
}
- ServerInstance->Logs->Log("m_sqloper",DEFAULT, "SQLOPER: database not present");
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "database not present");
}
return MOD_RES_PASSTHRU;
}
@@ -189,11 +152,10 @@ public:
SQL->submit(new OpMeQuery(this, user->uuid, username, password), query, userinfo);
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Allows storage of oper credentials in an SQL table", VF_VENDOR);
}
-
};
MODULE_INIT(ModuleSQLOper)
diff --git a/src/modules/m_sslinfo.cpp b/src/modules/m_sslinfo.cpp
index 2bfe0e1c4..c354e4e0e 100644
--- a/src/modules/m_sslinfo.cpp
+++ b/src/modules/m_sslinfo.cpp
@@ -18,9 +18,7 @@
#include "inspircd.h"
-#include "ssl.h"
-
-/* $ModDesc: Provides SSL metadata, including /WHOIS information and /SSLINFO command */
+#include "modules/ssl.h"
class SSLCertExt : public ExtensionItem {
public:
@@ -93,90 +91,84 @@ class CommandSSLInfo : public Command
if ((!target) || (target->registered != REG_ALL))
{
- user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nickname", user->nick.c_str(), parameters[0].c_str());
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nickname", parameters[0].c_str());
return CMD_FAILURE;
}
bool operonlyfp = ServerInstance->Config->ConfValue("sslinfo")->getBool("operonly");
- if (operonlyfp && !IS_OPER(user) && target != user)
+ if (operonlyfp && !user->IsOper() && target != user)
{
- user->WriteServ("NOTICE %s :*** You cannot view SSL certificate information for other users", user->nick.c_str());
+ user->WriteNotice("*** You cannot view SSL certificate information for other users");
return CMD_FAILURE;
}
ssl_cert* cert = CertExt.get(target);
if (!cert)
{
- user->WriteServ("NOTICE %s :*** No SSL certificate for this user", user->nick.c_str());
+ user->WriteNotice("*** No SSL certificate for this user");
}
else if (cert->GetError().length())
{
- user->WriteServ("NOTICE %s :*** No SSL certificate information for this user (%s).", user->nick.c_str(), cert->GetError().c_str());
+ user->WriteNotice("*** No SSL certificate information for this user (" + cert->GetError() + ").");
}
else
{
- user->WriteServ("NOTICE %s :*** Distinguished Name: %s", user->nick.c_str(), cert->GetDN().c_str());
- user->WriteServ("NOTICE %s :*** Issuer: %s", user->nick.c_str(), cert->GetIssuer().c_str());
- user->WriteServ("NOTICE %s :*** Key Fingerprint: %s", user->nick.c_str(), cert->GetFingerprint().c_str());
+ user->WriteNotice("*** Distinguished Name: " + cert->GetDN());
+ user->WriteNotice("*** Issuer: " + cert->GetIssuer());
+ user->WriteNotice("*** Key Fingerprint: " + cert->GetFingerprint());
}
return CMD_SUCCESS;
}
};
-class ModuleSSLInfo : public Module
+class UserCertificateAPIImpl : public UserCertificateAPIBase
{
- CommandSSLInfo cmd;
+ SSLCertExt& ext;
public:
- ModuleSSLInfo() : cmd(this)
+ UserCertificateAPIImpl(Module* mod, SSLCertExt& certext)
+ : UserCertificateAPIBase(mod), ext(certext)
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cmd);
+ ssl_cert* GetCertificate(User* user) CXX11_OVERRIDE
+ {
+ return ext.get(user);
+ }
+};
- ServerInstance->Modules->AddService(cmd.CertExt);
+class ModuleSSLInfo : public Module
+{
+ CommandSSLInfo cmd;
+ UserCertificateAPIImpl APIImpl;
- Implementation eventlist[] = { I_OnWhois, I_OnPreCommand, I_OnSetConnectClass, I_OnUserConnect, I_OnPostConnect };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
+ public:
+ ModuleSSLInfo()
+ : cmd(this), APIImpl(this, cmd.CertExt)
+ {
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("SSL Certificate Utilities", VF_VENDOR);
}
- void OnWhois(User* source, User* dest)
+ void OnWhois(User* source, User* dest) CXX11_OVERRIDE
{
ssl_cert* cert = cmd.CertExt.get(dest);
if (cert)
{
- ServerInstance->SendWhoisLine(source, dest, 671, "%s %s :is using a secure connection", source->nick.c_str(), dest->nick.c_str());
+ ServerInstance->SendWhoisLine(source, dest, 671, "%s :is using a secure connection", dest->nick.c_str());
bool operonlyfp = ServerInstance->Config->ConfValue("sslinfo")->getBool("operonly");
- if ((!operonlyfp || source == dest || IS_OPER(source)) && !cert->fingerprint.empty())
- ServerInstance->SendWhoisLine(source, dest, 276, "%s %s :has client certificate fingerprint %s",
- source->nick.c_str(), dest->nick.c_str(), cert->fingerprint.c_str());
+ if ((!operonlyfp || source == dest || source->IsOper()) && !cert->fingerprint.empty())
+ ServerInstance->SendWhoisLine(source, dest, 276, "%s :has client certificate fingerprint %s",
+ dest->nick.c_str(), cert->fingerprint.c_str());
}
}
- bool OneOfMatches(const char* host, const char* ip, const char* hostlist)
- {
- std::stringstream hl(hostlist);
- std::string xhost;
- while (hl >> xhost)
- {
- if (InspIRCd::Match(host, xhost, ascii_case_insensitive_map) || InspIRCd::MatchCIDR(ip, xhost, ascii_case_insensitive_map))
- {
- return true;
- }
- }
- return false;
- }
-
- ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line)
+ ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line) CXX11_OVERRIDE
{
if ((command == "OPER") && (validated))
{
- OperIndex::iterator i = ServerInstance->Config->oper_blocks.find(parameters[0]);
+ ServerConfig::OperIndex::const_iterator i = ServerInstance->Config->oper_blocks.find(parameters[0]);
if (i != ServerInstance->Config->oper_blocks.end())
{
OperInfo* ifo = i->second;
@@ -184,7 +176,7 @@ class ModuleSSLInfo : public Module
if (ifo->oper_block->getBool("sslonly") && !cert)
{
- user->WriteNumeric(491, "%s :This oper login requires an SSL connection.", user->nick.c_str());
+ user->WriteNumeric(491, ":This oper login requires an SSL connection.");
user->CommandFloodPenalty += 10000;
return MOD_RES_DENY;
}
@@ -192,7 +184,7 @@ class ModuleSSLInfo : public Module
std::string fingerprint;
if (ifo->oper_block->readString("fingerprint", fingerprint) && (!cert || cert->GetFingerprint() != fingerprint))
{
- user->WriteNumeric(491, "%s :This oper login requires a matching SSL fingerprint.",user->nick.c_str());
+ user->WriteNumeric(491, ":This oper login requires a matching SSL certificate fingerprint.");
user->CommandFloodPenalty += 10000;
return MOD_RES_DENY;
}
@@ -203,21 +195,20 @@ class ModuleSSLInfo : public Module
return MOD_RES_PASSTHRU;
}
- void OnUserConnect(LocalUser* user)
+ void OnUserConnect(LocalUser* user) CXX11_OVERRIDE
{
- SocketCertificateRequest req(&user->eh, this);
- if (!req.cert)
- return;
- cmd.CertExt.set(user, req.cert);
+ ssl_cert* cert = SSLClientCert::GetCertificate(&user->eh);
+ if (cert)
+ cmd.CertExt.set(user, cert);
}
- void OnPostConnect(User* user)
+ void OnPostConnect(User* user) CXX11_OVERRIDE
{
ssl_cert *cert = cmd.CertExt.get(user);
if (!cert || cert->fingerprint.empty())
return;
// find an auto-oper block for this user
- for(OperIndex::iterator i = ServerInstance->Config->oper_blocks.begin(); i != ServerInstance->Config->oper_blocks.end(); i++)
+ for (ServerConfig::OperIndex::const_iterator i = ServerInstance->Config->oper_blocks.begin(); i != ServerInstance->Config->oper_blocks.end(); ++i)
{
OperInfo* ifo = i->second;
std::string fp = ifo->oper_block->getString("fingerprint");
@@ -226,33 +217,23 @@ class ModuleSSLInfo : public Module
}
}
- ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass)
+ ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass) CXX11_OVERRIDE
{
- SocketCertificateRequest req(&user->eh, this);
+ ssl_cert* cert = SSLClientCert::GetCertificate(&user->eh);
bool ok = true;
if (myclass->config->getString("requiressl") == "trusted")
{
- ok = (req.cert && req.cert->IsCAVerified());
+ ok = (cert && cert->IsCAVerified());
}
else if (myclass->config->getBool("requiressl"))
{
- ok = (req.cert != NULL);
+ ok = (cert != NULL);
}
if (!ok)
return MOD_RES_DENY;
return MOD_RES_PASSTHRU;
}
-
- void OnRequest(Request& request)
- {
- if (strcmp("GET_USER_CERT", request.id) == 0)
- {
- UserCertificateRequest& req = static_cast<UserCertificateRequest&>(request);
- req.cert = cmd.CertExt.get(req.user);
- }
- }
};
MODULE_INIT(ModuleSSLInfo)
-
diff --git a/src/modules/m_sslmodes.cpp b/src/modules/m_sslmodes.cpp
index c81c74207..1a596f5e0 100644
--- a/src/modules/m_sslmodes.cpp
+++ b/src/modules/m_sslmodes.cpp
@@ -22,38 +22,44 @@
#include "inspircd.h"
-#include "ssl.h"
-
-/* $ModDesc: Provides channel mode +z to allow for Secure/SSL only channels */
+#include "modules/ssl.h"
/** Handle channel mode +z
*/
class SSLMode : public ModeHandler
{
public:
- SSLMode(Module* Creator) : ModeHandler(Creator, "sslonly", 'z', PARAM_NONE, MODETYPE_CHANNEL) { }
+ UserCertificateAPI API;
+
+ SSLMode(Module* Creator)
+ : ModeHandler(Creator, "sslonly", 'z', PARAM_NONE, MODETYPE_CHANNEL)
+ , API(Creator)
+ {
+ }
ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
{
if (adding)
{
- if (!channel->IsModeSet('z'))
+ if (!channel->IsModeSet(this))
{
if (IS_LOCAL(source))
{
- const UserMembList* userlist = channel->GetUsers();
- for(UserMembCIter i = userlist->begin(); i != userlist->end(); i++)
+ if (!API)
+ return MODEACTION_DENY;
+
+ const Channel::MemberMap& userlist = channel->GetUsers();
+ for (Channel::MemberMap::const_iterator i = userlist.begin(); i != userlist.end(); ++i)
{
- UserCertificateRequest req(i->first, creator);
- req.Send();
- if(!req.cert && !ServerInstance->ULine(i->first->server))
+ ssl_cert* cert = API->GetCertificate(i->first);
+ if (!cert && !i->first->server->IsULine())
{
- source->WriteNumeric(ERR_ALLMUSTSSL, "%s %s :all members of the channel must be connected via SSL", source->nick.c_str(), channel->name.c_str());
+ source->WriteNumeric(ERR_ALLMUSTSSL, "%s :all members of the channel must be connected via SSL", channel->name.c_str());
return MODEACTION_DENY;
}
}
}
- channel->SetMode('z',true);
+ channel->SetMode(this, true);
return MODEACTION_ALLOW;
}
else
@@ -63,9 +69,9 @@ class SSLMode : public ModeHandler
}
else
{
- if (channel->IsModeSet('z'))
+ if (channel->IsModeSet(this))
{
- channel->SetMode('z',false);
+ channel->SetMode(this, false);
return MODEACTION_ALLOW;
}
@@ -85,20 +91,15 @@ class ModuleSSLModes : public Module
{
}
- void init()
+ ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE
{
- ServerInstance->Modules->AddService(sslm);
- Implementation eventlist[] = { I_OnUserPreJoin, I_OnCheckBan, I_On005Numeric };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven)
- {
- if(chan && chan->IsModeSet('z'))
+ if(chan && chan->IsModeSet(sslm))
{
- UserCertificateRequest req(user, this);
- req.Send();
- if (req.cert)
+ if (!sslm.API)
+ return MOD_RES_DENY;
+
+ ssl_cert* cert = sslm.API->GetCertificate(user);
+ if (cert)
{
// Let them in
return MOD_RES_PASSTHRU;
@@ -106,7 +107,7 @@ class ModuleSSLModes : public Module
else
{
// Deny
- user->WriteServ( "489 %s %s :Cannot join channel; SSL users only (+z)", user->nick.c_str(), cname);
+ user->WriteNumeric(489, "%s :Cannot join channel; SSL users only (+z)", cname.c_str());
return MOD_RES_DENY;
}
}
@@ -114,33 +115,29 @@ class ModuleSSLModes : public Module
return MOD_RES_PASSTHRU;
}
- ModResult OnCheckBan(User *user, Channel *c, const std::string& mask)
+ ModResult OnCheckBan(User *user, Channel *c, const std::string& mask) CXX11_OVERRIDE
{
if ((mask.length() > 2) && (mask[0] == 'z') && (mask[1] == ':'))
{
- UserCertificateRequest req(user, this);
- req.Send();
- if (req.cert && InspIRCd::Match(req.cert->GetFingerprint(), mask.substr(2)))
+ if (!sslm.API)
+ return MOD_RES_DENY;
+
+ ssl_cert* cert = sslm.API->GetCertificate(user);
+ if (cert && InspIRCd::Match(cert->GetFingerprint(), mask.substr(2)))
return MOD_RES_DENY;
}
return MOD_RES_PASSTHRU;
}
- ~ModuleSSLModes()
- {
- }
-
- void On005Numeric(std::string &output)
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
- ServerInstance->AddExtBanChar('z');
+ tokens["EXTBAN"].push_back('z');
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides channel mode +z to allow for Secure/SSL only channels", VF_VENDOR);
}
};
-
MODULE_INIT(ModuleSSLModes)
-
diff --git a/src/modules/m_starttls.cpp b/src/modules/m_starttls.cpp
new file mode 100644
index 000000000..d591eed55
--- /dev/null
+++ b/src/modules/m_starttls.cpp
@@ -0,0 +1,121 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2014 Adam <Adam@anope.org>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "modules/ssl.h"
+#include "modules/cap.h"
+
+// From IRCv3 tls-3.1
+enum
+{
+ RPL_STARTTLS = 670,
+ ERR_STARTTLS = 691
+};
+
+class CommandStartTLS : public SplitCommand
+{
+ dynamic_reference_nocheck<IOHookProvider>& ssl;
+
+ public:
+ CommandStartTLS(Module* mod, dynamic_reference_nocheck<IOHookProvider>& s)
+ : SplitCommand(mod, "STARTTLS")
+ , ssl(s)
+ {
+ works_before_reg = true;
+ }
+
+ CmdResult HandleLocal(const std::vector<std::string>& parameters, LocalUser* user)
+ {
+ if (!ssl)
+ {
+ user->WriteNumeric(ERR_STARTTLS, ":STARTTLS is not enabled");
+ return CMD_FAILURE;
+ }
+
+ if (user->registered == REG_ALL)
+ {
+ user->WriteNumeric(ERR_STARTTLS, ":STARTTLS is not permitted after client registration is complete");
+ return CMD_FAILURE;
+ }
+
+ if (user->eh.GetIOHook())
+ {
+ user->WriteNumeric(ERR_STARTTLS, ":STARTTLS failure");
+ return CMD_FAILURE;
+ }
+
+ user->WriteNumeric(RPL_STARTTLS, ":STARTTLS successful, go ahead with TLS handshake");
+ /* We need to flush the write buffer prior to adding the IOHook,
+ * otherwise we'll be sending this line inside the SSL session - which
+ * won't start its handshake until the client gets this line. Currently,
+ * we assume the write will not block here; this is usually safe, as
+ * STARTTLS is sent very early on in the registration phase, where the
+ * user hasn't built up much sendq. Handling a blocked write here would
+ * be very annoying.
+ */
+ user->eh.DoWrite();
+
+ ssl->OnAccept(&user->eh, NULL, NULL);
+
+ return CMD_SUCCESS;
+ }
+};
+
+class ModuleStartTLS : public Module
+{
+ CommandStartTLS starttls;
+ GenericCap tls;
+ dynamic_reference_nocheck<IOHookProvider> ssl;
+
+ public:
+ ModuleStartTLS()
+ : starttls(this, ssl)
+ , tls(this, "tls")
+ , ssl(this, "ssl")
+ {
+ }
+
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
+ {
+ ConfigTag* conf = ServerInstance->Config->ConfValue("starttls");
+
+ std::string newprovider = conf->getString("provider");
+ if (newprovider.empty())
+ ssl.SetProvider("ssl");
+ else
+ ssl.SetProvider("ssl/" + newprovider);
+ }
+
+ void OnEvent(Event& ev) CXX11_OVERRIDE
+ {
+ tls.HandleEvent(ev);
+ }
+
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
+ {
+ tokens["STARTTLS"];
+ }
+
+ Version GetVersion() CXX11_OVERRIDE
+ {
+ return Version("Provides support for the STARTTLS command", VF_VENDOR);
+ }
+};
+
+MODULE_INIT(ModuleStartTLS)
diff --git a/src/modules/m_stripcolor.cpp b/src/modules/m_stripcolor.cpp
index f1504edaf..0d4bdb877 100644
--- a/src/modules/m_stripcolor.cpp
+++ b/src/modules/m_stripcolor.cpp
@@ -21,8 +21,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides channel +S mode (strip ansi color) */
-
/** Handles channel mode +S
*/
class ChannelStripColor : public SimpleChannelModeHandler
@@ -50,24 +48,12 @@ class ModuleStripColor : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(usc);
- ServerInstance->Modules->AddService(csc);
- Implementation eventlist[] = { I_OnUserPreMessage, I_OnUserPreNotice, I_On005Numeric };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- virtual ~ModuleStripColor()
- {
- }
-
- virtual void On005Numeric(std::string &output)
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
- ServerInstance->AddExtBanChar('S');
+ tokens["EXTBAN"].push_back('S');
}
- virtual ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+ ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE
{
if (!IS_LOCAL(user))
return MOD_RES_PASSTHRU;
@@ -76,7 +62,7 @@ class ModuleStripColor : public Module
if (target_type == TYPE_USER)
{
User* t = (User*)dest;
- active = t->IsModeSet('S');
+ active = t->IsModeSet(usc);
}
else if (target_type == TYPE_CHANNEL)
{
@@ -86,7 +72,7 @@ class ModuleStripColor : public Module
if (res == MOD_RES_ALLOW)
return MOD_RES_PASSTHRU;
- active = !t->GetExtBanStatus(user, 'S').check(!t->IsModeSet('S'));
+ active = !t->GetExtBanStatus(user, 'S').check(!t->IsModeSet(csc));
}
if (active)
@@ -97,12 +83,7 @@ class ModuleStripColor : public Module
return MOD_RES_PASSTHRU;
}
- virtual ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
- {
- return OnUserPreMessage(user,dest,target_type,text,status,exempt_list);
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides channel +S mode (strip ansi color)", VF_VENDOR);
}
diff --git a/src/modules/m_svshold.cpp b/src/modules/m_svshold.cpp
index e666b0fe2..a623e1553 100644
--- a/src/modules/m_svshold.cpp
+++ b/src/modules/m_svshold.cpp
@@ -23,8 +23,6 @@
#include "inspircd.h"
#include "xline.h"
-/* $ModDesc: Implements SVSHOLD. Like Q:Lines, but can only be added/removed by Services. */
-
namespace
{
bool silent;
@@ -35,16 +33,12 @@ namespace
class SVSHold : public XLine
{
public:
- irc::string nickname;
+ std::string nickname;
SVSHold(time_t s_time, long d, const std::string& src, const std::string& re, const std::string& nick)
: XLine(s_time, d, src, re, "SVSHOLD")
{
- this->nickname = nick.c_str();
- }
-
- ~SVSHold()
- {
+ this->nickname = nick;
}
bool Matches(User *u)
@@ -56,23 +50,21 @@ public:
bool Matches(const std::string &s)
{
- if (nickname == s)
- return true;
- return false;
+ return InspIRCd::Match(s, nickname);
}
void DisplayExpiry()
{
if (!silent)
{
- ServerInstance->SNO->WriteToSnoMask('x',"Removing expired SVSHOLD %s (set by %s %ld seconds ago)",
- this->nickname.c_str(), this->source.c_str(), (long int)(ServerInstance->Time() - this->set_time));
+ ServerInstance->SNO->WriteToSnoMask('x', "Removing expired SVSHOLD %s (set by %s %ld seconds ago)",
+ nickname.c_str(), source.c_str(), (long)(ServerInstance->Time() - set_time));
}
}
- const char* Displayable()
+ const std::string& Displayable()
{
- return nickname.c_str();
+ return nickname;
}
};
@@ -104,7 +96,6 @@ class CommandSvshold : public Command
CommandSvshold(Module* Creator) : Command(Creator, "SVSHOLD", 1)
{
flags_needed = 'o'; this->syntax = "<nickname> [<duration> :<reason>]";
- TRANSLATE4(TR_TEXT, TR_TEXT, TR_TEXT, TR_END);
}
CmdResult Handle(const std::vector<std::string> &parameters, User *user)
@@ -112,7 +103,7 @@ class CommandSvshold : public Command
/* syntax: svshold nickname time :reason goes here */
/* 'time' is a human-readable timestring, like 2d3h2s. */
- if (!ServerInstance->ULine(user->server))
+ if (!user->server->IsULine())
{
/* don't allow SVSHOLD from non-ulined clients */
return CMD_FAILURE;
@@ -127,7 +118,7 @@ class CommandSvshold : public Command
}
else
{
- user->WriteServ("NOTICE %s :*** SVSHOLD %s not found in list, try /stats S.",user->nick.c_str(),parameters[0].c_str());
+ user->WriteNotice("*** SVSHOLD " + parameters[0] + " not found in list, try /stats S.");
}
}
else
@@ -135,8 +126,7 @@ class CommandSvshold : public Command
if (parameters.size() < 3)
return CMD_FAILURE;
- // Adding - XXX todo make this respect <insane> tag perhaps..
- long duration = ServerInstance->Duration(parameters[1]);
+ unsigned long duration = InspIRCd::Duration(parameters[1]);
SVSHold* r = new SVSHold(ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), parameters[0].c_str());
if (ServerInstance->XLines->AddLine(r, user))
@@ -151,7 +141,7 @@ class CommandSvshold : public Command
else
{
time_t c_requires_crap = duration + ServerInstance->Time();
- std::string timestr = ServerInstance->TimeString(c_requires_crap);
+ std::string timestr = InspIRCd::TimeString(c_requires_crap);
ServerInstance->SNO->WriteGlobalSno('x', "%s added timed SVSHOLD for %s, expires on %s: %s", user->nick.c_str(), parameters[0].c_str(), timestr.c_str(), parameters[2].c_str());
}
}
@@ -182,22 +172,18 @@ class ModuleSVSHold : public Module
{
}
- void init()
+ void init() CXX11_OVERRIDE
{
ServerInstance->XLines->RegisterFactory(&s);
- ServerInstance->Modules->AddService(cmd);
- Implementation eventlist[] = { I_OnUserPreNick, I_OnStats, I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- OnRehash(NULL);
}
- void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
ConfigTag* tag = ServerInstance->Config->ConfValue("svshold");
- silent = tag->getBool("silent");
+ silent = tag->getBool("silent", true);
}
- virtual ModResult OnStats(char symbol, User* user, string_list &out)
+ ModResult OnStats(char symbol, User* user, string_list &out) CXX11_OVERRIDE
{
if(symbol != 'S')
return MOD_RES_PASSTHRU;
@@ -206,26 +192,26 @@ class ModuleSVSHold : public Module
return MOD_RES_DENY;
}
- virtual ModResult OnUserPreNick(User *user, const std::string &newnick)
+ ModResult OnUserPreNick(LocalUser* user, const std::string& newnick) CXX11_OVERRIDE
{
XLine *rl = ServerInstance->XLines->MatchesLine("SVSHOLD", newnick);
if (rl)
{
- user->WriteServ( "432 %s %s :Services reserved nickname: %s", user->nick.c_str(), newnick.c_str(), rl->reason.c_str());
+ user->WriteNumeric(ERR_ERRONEUSNICKNAME, "%s :Services reserved nickname: %s", newnick.c_str(), rl->reason.c_str());
return MOD_RES_DENY;
}
return MOD_RES_PASSTHRU;
}
- virtual ~ModuleSVSHold()
+ ~ModuleSVSHold()
{
ServerInstance->XLines->DelAll("SVSHOLD");
ServerInstance->XLines->UnregisterFactory(&s);
}
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Implements SVSHOLD. Like Q:Lines, but can only be added/removed by Services.", VF_COMMON | VF_VENDOR);
}
diff --git a/src/modules/m_swhois.cpp b/src/modules/m_swhois.cpp
index 742781747..4eb2a9cda 100644
--- a/src/modules/m_swhois.cpp
+++ b/src/modules/m_swhois.cpp
@@ -25,8 +25,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides the SWHOIS command which allows setting of arbitrary WHOIS lines */
-
/** Handle /SWHOIS
*/
class CommandSwhois : public Command
@@ -36,7 +34,7 @@ class CommandSwhois : public Command
CommandSwhois(Module* Creator) : Command(Creator,"SWHOIS", 2,2), swhois("swhois", Creator)
{
flags_needed = 'o'; syntax = "<nick> :<swhois>";
- TRANSLATE3(TR_NICK, TR_TEXT, TR_END);
+ TRANSLATE2(TR_NICK, TR_TEXT);
}
CmdResult Handle(const std::vector<std::string> &parameters, User* user)
@@ -45,7 +43,7 @@ class CommandSwhois : public Command
if ((!dest) || (IS_SERVER(dest))) // allow setting swhois using SWHOIS before reg
{
- user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel", user->nick.c_str(), parameters[0].c_str());
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", parameters[0].c_str());
return CMD_FAILURE;
}
@@ -53,11 +51,11 @@ class CommandSwhois : public Command
if (text)
{
// We already had it set...
- if (!ServerInstance->ULine(user->server))
+ if (!user->server->IsULine())
// Ulines set SWHOISes silently
ServerInstance->SNO->WriteGlobalSno('a', "%s used SWHOIS to set %s's extra whois from '%s' to '%s'", user->nick.c_str(), dest->nick.c_str(), text->c_str(), parameters[1].c_str());
}
- else if (!ServerInstance->ULine(user->server))
+ else if (!user->server->IsULine())
{
// Ulines set SWHOISes silently
ServerInstance->SNO->WriteGlobalSno('a', "%s used SWHOIS to set %s's extra whois to '%s'", user->nick.c_str(), dest->nick.c_str(), parameters[1].c_str());
@@ -90,16 +88,8 @@ class ModuleSWhois : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cmd);
- ServerInstance->Modules->AddService(cmd.swhois);
- Implementation eventlist[] = { I_OnWhoisLine, I_OnPostOper };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
// :kenny.chatspike.net 320 Brain Azhrarn :is getting paid to play games.
- ModResult OnWhoisLine(User* user, User* dest, int &numeric, std::string &text)
+ ModResult OnWhoisLine(User* user, User* dest, int &numeric, std::string &text) CXX11_OVERRIDE
{
/* We use this and not OnWhois because this triggers for remote, too */
if (numeric == 312)
@@ -108,7 +98,7 @@ class ModuleSWhois : public Module
std::string* swhois = cmd.swhois.get(dest);
if (swhois)
{
- ServerInstance->SendWhoisLine(user, dest, 320, "%s %s :%s",user->nick.c_str(), dest->nick.c_str(), swhois->c_str());
+ ServerInstance->SendWhoisLine(user, dest, 320, "%s :%s", dest->nick.c_str(), swhois->c_str());
}
}
@@ -116,7 +106,7 @@ class ModuleSWhois : public Module
return MOD_RES_PASSTHRU;
}
- void OnPostOper(User* user, const std::string &opertype, const std::string &opername)
+ void OnPostOper(User* user, const std::string &opertype, const std::string &opername) CXX11_OVERRIDE
{
if (!IS_LOCAL(user))
return;
@@ -130,11 +120,7 @@ class ModuleSWhois : public Module
ServerInstance->PI->SendMetaData(user, "swhois", swhois);
}
- ~ModuleSWhois()
- {
- }
-
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides the SWHOIS command which allows setting of arbitrary WHOIS lines", VF_OPTCOMMON | VF_VENDOR);
}
diff --git a/src/modules/m_testnet.cpp b/src/modules/m_testnet.cpp
index 401766d8a..6e05ed681 100644
--- a/src/modules/m_testnet.cpp
+++ b/src/modules/m_testnet.cpp
@@ -17,167 +17,8 @@
*/
-/* $ModDesc: Provides a module for testing the server while linked in a network */
-
#include "inspircd.h"
-struct vtbase
-{
- virtual void isok(const char* name, int impl, Module* basemod, std::vector<std::string>& allmods) = 0;
- virtual ~vtbase() {}
-};
-
-template<typename T> struct vtable : public vtbase
-{
- union u {
- T function;
- struct v {
- size_t delta;
- size_t vtoff;
- } v;
- } u;
- vtable(T t) {
- u.function = t;
- }
- /** member function pointer dereference from vtable; depends on the GCC 4.4 ABI (x86_64) */
- template<typename E> void* read(E* obj)
- {
- if (u.v.delta & 1)
- {
- uint8_t* optr = reinterpret_cast<uint8_t*>(obj);
- optr += u.v.vtoff;
- uint8_t* vptr = *reinterpret_cast<uint8_t**>(optr);
- vptr += u.v.delta - 1;
- return *reinterpret_cast<void**>(vptr);
- }
- else
- return reinterpret_cast<void*>(u.v.delta);
- }
- void isok(const char* name, int impl, Module* basemod, std::vector<std::string>& allmods)
- {
- void* base = read(basemod);
- for(unsigned int i=0; i < allmods.size(); ++i)
- {
- Module* mod = ServerInstance->Modules->Find(allmods[i]);
- void* fptr = read(mod);
- for(EventHandlerIter j = ServerInstance->Modules->EventHandlers[impl].begin();
- j != ServerInstance->Modules->EventHandlers[impl].end(); j++)
- {
- if (mod == *j)
- {
- if (fptr == base)
- {
- ServerInstance->SNO->WriteToSnoMask('a', "Module %s implements %s but uses default function",
- mod->ModuleSourceFile.c_str(), name);
- }
- goto done;
- }
- }
- if (fptr != base)
- {
- ServerInstance->SNO->WriteToSnoMask('a', "Module %s does not implement %s but overrides function",
- mod->ModuleSourceFile.c_str(), name);
- }
- done:;
- }
- }
-};
-
-template<typename T> vtbase* vtinit(T t)
-{
- return new vtable<T>(t);
-}
-
-static void checkall(Module* noimpl)
-{
- std::vector<std::string> allmods = ServerInstance->Modules->GetAllModuleNames(0);
-#define CHK(name) do { \
- vtbase* vt = vtinit(&Module::name); \
- vt->isok(#name, I_ ## name, noimpl, allmods); \
- delete vt; \
-} while (0)
- CHK(OnUserConnect);
- CHK(OnUserQuit);
- CHK(OnUserDisconnect);
- CHK(OnUserJoin);
- CHK(OnUserPart);
- CHK(OnRehash);
- CHK(OnSendSnotice);
- CHK(OnUserPreJoin);
- CHK(OnUserPreKick);
- CHK(OnUserKick);
- CHK(OnOper);
- CHK(OnInfo);
- CHK(OnWhois);
- CHK(OnUserPreInvite);
- CHK(OnUserInvite);
- CHK(OnUserPreMessage);
- CHK(OnUserPreNotice);
- CHK(OnUserPreNick);
- CHK(OnUserMessage);
- CHK(OnUserNotice);
- CHK(OnMode);
- CHK(OnGetServerDescription);
- CHK(OnSyncUser);
- CHK(OnSyncChannel);
- CHK(OnDecodeMetaData);
- CHK(OnWallops);
- CHK(OnAcceptConnection);
- CHK(OnChangeHost);
- CHK(OnChangeName);
- CHK(OnAddLine);
- CHK(OnDelLine);
- CHK(OnExpireLine);
- CHK(OnUserPostNick);
- CHK(OnPreMode);
- CHK(On005Numeric);
- CHK(OnKill);
- CHK(OnRemoteKill);
- CHK(OnLoadModule);
- CHK(OnUnloadModule);
- CHK(OnBackgroundTimer);
- CHK(OnPreCommand);
- CHK(OnCheckReady);
- CHK(OnCheckInvite);
- CHK(OnRawMode);
- CHK(OnCheckKey);
- CHK(OnCheckLimit);
- CHK(OnCheckBan);
- CHK(OnCheckChannelBan);
- CHK(OnExtBanCheck);
- CHK(OnStats);
- CHK(OnChangeLocalUserHost);
- CHK(OnPreTopicChange);
- CHK(OnPostTopicChange);
- CHK(OnEvent);
- CHK(OnGlobalOper);
- CHK(OnPostConnect);
- CHK(OnAddBan);
- CHK(OnDelBan);
- CHK(OnChangeLocalUserGECOS);
- CHK(OnUserRegister);
- CHK(OnChannelPreDelete);
- CHK(OnChannelDelete);
- CHK(OnPostOper);
- CHK(OnSyncNetwork);
- CHK(OnSetAway);
- CHK(OnPostCommand);
- CHK(OnPostJoin);
- CHK(OnWhoisLine);
- CHK(OnBuildNeighborList);
- CHK(OnGarbageCollect);
- CHK(OnText);
- CHK(OnPassCompare);
- CHK(OnRunTestSuite);
- CHK(OnNamesListItem);
- CHK(OnNumeric);
- CHK(OnHookIO);
- CHK(OnPreRehash);
- CHK(OnModuleRehash);
- CHK(OnSendWhoLine);
- CHK(OnChangeIdent);
-}
-
class CommandTest : public Command
{
public:
@@ -199,11 +40,6 @@ class CommandTest : public Command
{
IS_LOCAL(user)->CommandFloodPenalty += atoi(parameters[1].c_str());
}
- else if (parameters[0] == "check")
- {
- checkall(creator);
- ServerInstance->SNO->WriteToSnoMask('a', "Module check complete");
- }
return CMD_SUCCESS;
}
};
@@ -216,18 +52,16 @@ class ModuleTest : public Module
{
}
- void init()
+ void init() CXX11_OVERRIDE
{
if (!strstr(ServerInstance->Config->ServerName.c_str(), ".test"))
throw ModuleException("Don't load modules without reading their descriptions!");
- ServerInstance->Modules->AddService(cmd);
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides a module for testing the server while linked in a network", VF_VENDOR|VF_OPTCOMMON);
}
};
MODULE_INIT(ModuleTest)
-
diff --git a/src/modules/m_timedbans.cpp b/src/modules/m_timedbans.cpp
index 497ac2569..e3a938336 100644
--- a/src/modules/m_timedbans.cpp
+++ b/src/modules/m_timedbans.cpp
@@ -20,8 +20,6 @@
*/
-/* $ModDesc: Adds timed bans */
-
#include "inspircd.h"
/** Holds a timed ban
@@ -45,7 +43,6 @@ class CommandTban : public Command
CommandTban(Module* Creator) : Command(Creator,"TBAN", 3)
{
syntax = "<channel> <duration> <banmask>";
- TRANSLATE4(TR_TEXT, TR_TEXT, TR_TEXT, TR_END);
}
CmdResult Handle (const std::vector<std::string> &parameters, User *user)
@@ -53,24 +50,24 @@ class CommandTban : public Command
Channel* channel = ServerInstance->FindChan(parameters[0]);
if (!channel)
{
- user->WriteNumeric(401, "%s %s :No such channel",user->nick.c_str(), parameters[0].c_str());
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such channel", parameters[0].c_str());
return CMD_FAILURE;
}
int cm = channel->GetPrefixValue(user);
if (cm < HALFOP_VALUE)
{
- user->WriteNumeric(482, "%s %s :You do not have permission to set bans on this channel",
- user->nick.c_str(), channel->name.c_str());
+ user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s :You do not have permission to set bans on this channel",
+ channel->name.c_str());
return CMD_FAILURE;
- }
+ }
TimedBan T;
std::string channelname = parameters[0];
- long duration = ServerInstance->Duration(parameters[1]);
+ unsigned long duration = InspIRCd::Duration(parameters[1]);
unsigned long expire = duration + ServerInstance->Time();
if (duration < 1)
{
- user->WriteServ("NOTICE "+user->nick+" :Invalid ban time");
+ user->WriteNotice("Invalid ban time");
return CMD_FAILURE;
}
std::string mask = parameters[2];
@@ -78,22 +75,19 @@ class CommandTban : public Command
setban.push_back(parameters[0]);
setban.push_back("+b");
bool isextban = ((mask.size() > 2) && (mask[1] == ':'));
- if (!isextban && !ServerInstance->IsValidMask(mask))
+ if (!isextban && !InspIRCd::IsValidMask(mask))
mask.append("!*@*");
- if ((mask.length() > 250) || (!ServerInstance->IsValidMask(mask) && !isextban))
+
+ setban.push_back(mask);
+ // Pass the user (instead of ServerInstance->FakeClient) to ModeHandler::Process() to
+ // make it so that the user sets the mode themselves
+ ServerInstance->Modes->Process(setban, user);
+ if (ServerInstance->Modes->GetLastParse().empty())
{
- user->WriteServ("NOTICE "+user->nick+" :Invalid ban mask");
+ user->WriteNotice("Invalid ban mask");
return CMD_FAILURE;
}
- setban.push_back(mask);
- // use CallHandler to make it so that the user sets the mode
- // themselves
- ServerInstance->Parser->CallHandler("MODE",setban,user);
- for (BanList::iterator i = channel->bans.begin(); i != channel->bans.end(); i++)
- if (!strcasecmp(i->data.c_str(), mask.c_str()))
- goto found;
- return CMD_FAILURE;
-found:
+
CUList tmp;
T.channel = channelname;
T.mask = mask;
@@ -114,27 +108,22 @@ found:
}
};
-class ModuleTimedBans : public Module
+class BanWatcher : public ModeWatcher
{
- CommandTban cmd;
public:
- ModuleTimedBans()
- : cmd(this)
+ BanWatcher(Module* parent)
+ : ModeWatcher(parent, "ban", MODETYPE_CHANNEL)
{
}
- void init()
+ void AfterMode(User* source, User* dest, Channel* chan, const std::string& banmask, bool adding)
{
- ServerInstance->Modules->AddService(cmd);
- Implementation eventlist[] = { I_OnDelBan, I_OnBackgroundTimer };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
+ if (adding)
+ return;
- virtual ModResult OnDelBan(User* source, Channel* chan, const std::string &banmask)
- {
irc::string listitem = banmask.c_str();
irc::string thischan = chan->name.c_str();
- for (timedbans::iterator i = TimedBanList.begin(); i != TimedBanList.end(); i++)
+ for (timedbans::iterator i = TimedBanList.begin(); i != TimedBanList.end(); ++i)
{
irc::string target = i->mask.c_str();
irc::string tchan = i->channel.c_str();
@@ -144,10 +133,22 @@ class ModuleTimedBans : public Module
break;
}
}
- return MOD_RES_PASSTHRU;
+ }
+};
+
+class ModuleTimedBans : public Module
+{
+ CommandTban cmd;
+ BanWatcher banwatcher;
+
+ public:
+ ModuleTimedBans()
+ : cmd(this)
+ , banwatcher(this)
+ {
}
- virtual void OnBackgroundTimer(time_t curtime)
+ void OnBackgroundTimer(time_t curtime) CXX11_OVERRIDE
{
timedbans expired;
for (timedbans::iterator i = TimedBanList.begin(); i != TimedBanList.end();)
@@ -178,16 +179,15 @@ class ModuleTimedBans : public Module
cr->WriteAllExcept(ServerInstance->FakeClient, true, '@', empty, "NOTICE %s :%s", cr->name.c_str(), expiry.c_str());
ServerInstance->PI->SendChannelNotice(cr, '@', expiry);
- ServerInstance->SendGlobalMode(setban, ServerInstance->FakeClient);
+ ServerInstance->Modes->Process(setban, ServerInstance->FakeClient);
}
}
}
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Adds timed bans", VF_COMMON | VF_VENDOR);
}
};
MODULE_INIT(ModuleTimedBans)
-
diff --git a/src/modules/m_tline.cpp b/src/modules/m_tline.cpp
index b4e7e5a99..77ec0e26c 100644
--- a/src/modules/m_tline.cpp
+++ b/src/modules/m_tline.cpp
@@ -20,8 +20,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides /tline command used to test who a mask matches */
-
/** Handle /TLINE
*/
class CommandTline : public Command
@@ -34,14 +32,13 @@ class CommandTline : public Command
CmdResult Handle (const std::vector<std::string> &parameters, User *user)
{
- float n_counted = 0;
- float n_matched = 0;
- float n_match_host = 0;
- float n_match_ip = 0;
+ unsigned int n_matched = 0;
+ unsigned int n_match_host = 0;
+ unsigned int n_match_ip = 0;
- for (user_hash::const_iterator u = ServerInstance->Users->clientlist->begin(); u != ServerInstance->Users->clientlist->end(); u++)
+ const user_hash& users = ServerInstance->Users->GetUsers();
+ for (user_hash::const_iterator u = users.begin(); u != users.end(); ++u)
{
- n_counted++;
if (InspIRCd::Match(u->second->GetFullRealHost(),parameters[0]))
{
n_matched++;
@@ -57,10 +54,15 @@ class CommandTline : public Command
}
}
}
+
+ unsigned long n_counted = users.size();
if (n_matched)
- user->WriteServ( "NOTICE %s :*** TLINE: Counted %0.0f user(s). Matched '%s' against %0.0f user(s) (%0.2f%% of the userbase). %0.0f by hostname and %0.0f by IP address.",user->nick.c_str(), n_counted, parameters[0].c_str(), n_matched, (n_matched/n_counted)*100, n_match_host, n_match_ip);
+ {
+ float p = (n_matched / (float)n_counted) * 100;
+ user->WriteNotice(InspIRCd::Format("*** TLINE: Counted %lu user(s). Matched '%s' against %u user(s) (%0.2f%% of the userbase). %u by hostname and %u by IP address.", n_counted, parameters[0].c_str(), n_matched, p, n_match_host, n_match_ip));
+ }
else
- user->WriteServ( "NOTICE %s :*** TLINE: Counted %0.0f user(s). Matched '%s' against no user(s).", user->nick.c_str(), n_counted, parameters[0].c_str());
+ user->WriteNotice(InspIRCd::Format("*** TLINE: Counted %lu user(s). Matched '%s' against no user(s).", n_counted, parameters[0].c_str()));
return CMD_SUCCESS;
}
@@ -75,20 +77,10 @@ class ModuleTLine : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cmd);
- }
-
- virtual ~ModuleTLine()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides /tline command used to test who a mask matches", VF_VENDOR);
}
};
MODULE_INIT(ModuleTLine)
-
diff --git a/src/modules/m_topiclock.cpp b/src/modules/m_topiclock.cpp
index 3e8a846e7..42ed6e4c1 100644
--- a/src/modules/m_topiclock.cpp
+++ b/src/modules/m_topiclock.cpp
@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/* $ModDesc: Implements server-side topic locks and the server-to-server command SVSTOPIC */
-
#include "inspircd.h"
class CommandSVSTOPIC : public Command
@@ -31,7 +29,7 @@ class CommandSVSTOPIC : public Command
CmdResult Handle(const std::vector<std::string> &parameters, User *user)
{
- if (!ServerInstance->ULine(user->server))
+ if (!user->server->IsULine())
{
// Ulines only
return CMD_FAILURE;
@@ -47,7 +45,7 @@ class CommandSVSTOPIC : public Command
time_t topicts = ConvToInt(parameters[1]);
if (!topicts)
{
- ServerInstance->Logs->Log("m_topiclock", DEFAULT, "Received SVSTOPIC with a 0 topicts, dropped.");
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Received SVSTOPIC with a 0 topicts, dropped.");
return CMD_INVALID;
}
@@ -96,10 +94,6 @@ class FlagExtItem : public ExtensionItem
{
}
- virtual ~FlagExtItem()
- {
- }
-
bool get(const Extensible* container) const
{
return (get_raw(container) != NULL);
@@ -151,14 +145,7 @@ class ModuleTopicLock : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cmd);
- ServerInstance->Modules->AddService(topiclock);
- ServerInstance->Modules->Attach(I_OnPreTopicChange, this);
- }
-
- ModResult OnPreTopicChange(User* user, Channel* chan, const std::string &topic)
+ ModResult OnPreTopicChange(User* user, Channel* chan, const std::string &topic) CXX11_OVERRIDE
{
// Only fired for local users currently, but added a check anyway
if ((IS_LOCAL(user)) && (topiclock.get(chan)))
@@ -170,7 +157,7 @@ class ModuleTopicLock : public Module
return MOD_RES_PASSTHRU;
}
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Implements server-side topic locks and the server-to-server command SVSTOPIC", VF_COMMON | VF_VENDOR);
}
diff --git a/src/modules/m_uhnames.cpp b/src/modules/m_uhnames.cpp
index 2cd090f97..0a171c4dc 100644
--- a/src/modules/m_uhnames.cpp
+++ b/src/modules/m_uhnames.cpp
@@ -20,9 +20,7 @@
#include "inspircd.h"
-#include "m_cap.h"
-
-/* $ModDesc: Provides the UHNAMES facility. */
+#include "modules/cap.h"
class ModuleUHNames : public Module
{
@@ -33,27 +31,17 @@ class ModuleUHNames : public Module
{
}
- void init()
- {
- Implementation eventlist[] = { I_OnEvent, I_OnPreCommand, I_OnNamesListItem, I_On005Numeric };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- ~ModuleUHNames()
- {
- }
-
- Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides the UHNAMES facility.",VF_VENDOR);
}
- void On005Numeric(std::string &output)
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
- output.append(" UHNAMES");
+ tokens["UHNAMES"];
}
- ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line)
+ ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line) CXX11_OVERRIDE
{
/* We don't actually create a proper command handler class for PROTOCTL,
* because other modules might want to have PROTOCTL hooks too.
@@ -71,18 +59,15 @@ class ModuleUHNames : public Module
return MOD_RES_PASSTHRU;
}
- void OnNamesListItem(User* issuer, Membership* memb, std::string &prefixes, std::string &nick)
+ ModResult OnNamesListItem(User* issuer, Membership* memb, std::string& prefixes, std::string& nick) CXX11_OVERRIDE
{
- if (!cap.ext.get(issuer))
- return;
+ if (cap.ext.get(issuer))
+ nick = memb->user->GetFullHost();
- if (nick.empty())
- return;
-
- nick = memb->user->GetFullHost();
+ return MOD_RES_PASSTHRU;
}
- void OnEvent(Event& ev)
+ void OnEvent(Event& ev) CXX11_OVERRIDE
{
cap.HandleEvent(ev);
}
diff --git a/src/modules/m_uninvite.cpp b/src/modules/m_uninvite.cpp
index ff392edc3..97ad841f1 100644
--- a/src/modules/m_uninvite.cpp
+++ b/src/modules/m_uninvite.cpp
@@ -20,8 +20,6 @@
*/
-/* $ModDesc: Provides the UNINVITE command which lets users un-invite other users from channels (!) */
-
#include "inspircd.h"
/** Handle /UNINVITE
@@ -32,7 +30,7 @@ class CommandUninvite : public Command
CommandUninvite(Module* Creator) : Command(Creator,"UNINVITE", 2)
{
syntax = "<nick> <channel>";
- TRANSLATE3(TR_NICK, TR_TEXT, TR_END);
+ TRANSLATE2(TR_NICK, TR_TEXT);
}
CmdResult Handle (const std::vector<std::string> &parameters, User *user)
@@ -49,11 +47,11 @@ class CommandUninvite : public Command
{
if (!c)
{
- user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[1].c_str());
+ user->WriteNumeric(401, "%s :No such nick/channel", parameters[1].c_str());
}
else
{
- user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
+ user->WriteNumeric(401, "%s :No such nick/channel", parameters[0].c_str());
}
return CMD_FAILURE;
@@ -63,7 +61,7 @@ class CommandUninvite : public Command
{
if (c->GetPrefixValue(user) < HALFOP_VALUE)
{
- user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must be a channel %soperator", user->nick.c_str(), c->name.c_str(), c->GetPrefixValue(u) == HALFOP_VALUE ? "" : "half-");
+ user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s :You must be a channel %soperator", c->name.c_str(), c->GetPrefixValue(u) == HALFOP_VALUE ? "" : "half-");
return CMD_FAILURE;
}
}
@@ -75,16 +73,14 @@ class CommandUninvite : public Command
LocalUser* lu = IS_LOCAL(u);
if (lu)
{
- irc::string xname(c->name.c_str());
- if (!lu->IsInvited(xname))
+ if (!lu->RemoveInvite(c))
{
- user->SendText(":%s 505 %s %s %s :Is not invited to channel %s", user->server.c_str(), user->nick.c_str(), u->nick.c_str(), c->name.c_str(), c->name.c_str());
+ user->SendText(":%s 505 %s %s %s :Is not invited to channel %s", user->server->GetName().c_str(), user->nick.c_str(), u->nick.c_str(), c->name.c_str(), c->name.c_str());
return CMD_FAILURE;
}
- user->SendText(":%s 494 %s %s %s :Uninvited", user->server.c_str(), user->nick.c_str(), c->name.c_str(), u->nick.c_str());
- lu->RemoveInvite(xname);
- lu->WriteNumeric(493, "%s :You were uninvited from %s by %s", u->nick.c_str(), c->name.c_str(), user->nick.c_str());
+ user->SendText(":%s 494 %s %s %s :Uninvited", user->server->GetName().c_str(), user->nick.c_str(), c->name.c_str(), u->nick.c_str());
+ lu->WriteNumeric(493, ":You were uninvited from %s by %s", c->name.c_str(), user->nick.c_str());
std::string msg = "*** " + user->nick + " uninvited " + u->nick + ".";
c->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE " + c->name + " :" + msg);
@@ -111,20 +107,10 @@ class ModuleUninvite : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cmd);
- }
-
- virtual ~ModuleUninvite()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides the UNINVITE command which lets users un-invite other users from channels", VF_VENDOR | VF_OPTCOMMON);
}
};
MODULE_INIT(ModuleUninvite)
-
diff --git a/src/modules/m_userip.cpp b/src/modules/m_userip.cpp
index 9502c91b1..043967393 100644
--- a/src/modules/m_userip.cpp
+++ b/src/modules/m_userip.cpp
@@ -21,8 +21,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides support for USERIP command */
-
/** Handle /USERIP
*/
class CommandUserip : public Command
@@ -54,15 +52,15 @@ class CommandUserip : public Command
checked_privs = true;
has_privs = user->HasPrivPermission("users/auspex");
if (!has_privs)
- user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - You do not have the required operator privileges",user->nick.c_str());
+ user->WriteNumeric(ERR_NOPRIVILEGES, ":Permission Denied - You do not have the required operator privileges");
}
if (!has_privs)
continue;
}
- retbuf = retbuf + u->nick + (IS_OPER(u) ? "*" : "") + "=";
- if (IS_AWAY(u))
+ retbuf = retbuf + u->nick + (u->IsOper() ? "*" : "") + "=";
+ if (u->IsAway())
retbuf += "-";
else
retbuf += "+";
@@ -87,28 +85,15 @@ class ModuleUserIP : public Module
{
}
- void init()
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
- ServerInstance->Modules->AddService(cmd);
- Implementation eventlist[] = { I_On005Numeric };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
+ tokens["USERIP"];
}
- virtual void On005Numeric(std::string &output)
- {
- output = output + " USERIP";
- }
-
- virtual ~ModuleUserIP()
- {
- }
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for USERIP command",VF_VENDOR);
}
-
};
MODULE_INIT(ModuleUserIP)
-
diff --git a/src/modules/m_vhost.cpp b/src/modules/m_vhost.cpp
index 31c504af8..53910fdbe 100644
--- a/src/modules/m_vhost.cpp
+++ b/src/modules/m_vhost.cpp
@@ -22,8 +22,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides masking of user hostnames via traditional /VHOST command */
-
/** Handle /VHOST
*/
class CommandVhost : public Command
@@ -45,25 +43,24 @@ class CommandVhost : public Command
std::string pass = tag->getString("pass");
std::string hash = tag->getString("hash");
- if (parameters[0] == username && !ServerInstance->PassCompare(user, pass, parameters[1], hash))
+ if (parameters[0] == username && ServerInstance->PassCompare(user, pass, parameters[1], hash))
{
if (!mask.empty())
{
- user->WriteServ("NOTICE "+user->nick+" :Setting your VHost: " + mask);
- user->ChangeDisplayedHost(mask.c_str());
+ user->WriteNotice("Setting your VHost: " + mask);
+ user->ChangeDisplayedHost(mask);
return CMD_SUCCESS;
}
}
}
- user->WriteServ("NOTICE "+user->nick+" :Invalid username or password.");
+ user->WriteNotice("Invalid username or password.");
return CMD_FAILURE;
}
};
class ModuleVHost : public Module
{
- private:
CommandVhost cmd;
public:
@@ -71,22 +68,10 @@ class ModuleVHost : public Module
{
}
- void init()
- {
- ServerInstance->Modules->AddService(cmd);
- }
-
- virtual ~ModuleVHost()
- {
- }
-
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides masking of user hostnames via traditional /VHOST command",VF_VENDOR);
}
-
};
MODULE_INIT(ModuleVHost)
-
diff --git a/src/modules/m_watch.cpp b/src/modules/m_watch.cpp
index be05d7d2d..68fe09d64 100644
--- a/src/modules/m_watch.cpp
+++ b/src/modules/m_watch.cpp
@@ -22,8 +22,6 @@
#include "inspircd.h"
-/* $ModDesc: Provides support for the /WATCH command */
-
/*
* Okay, it's nice that this was documented and all, but I at least understood very little
@@ -92,12 +90,7 @@
* of users using WATCH.
*/
-/*
- * Before you start screaming, this definition is only used here, so moving it to a header is pointless.
- * Yes, it's horrid. Blame cl for being different. -- w00t
- */
-
-typedef nspace::hash_map<irc::string, std::deque<User*>, irc::hash> watchentries;
+typedef TR1NS::unordered_map<irc::string, std::deque<User*>, irc::hash> watchentries;
typedef std::map<irc::string, std::string> watchlist;
/* Who's watching each nickname.
@@ -112,12 +105,12 @@ class CommandSVSWatch : public Command
CommandSVSWatch(Module* Creator) : Command(Creator,"SVSWATCH", 2)
{
syntax = "<target> [C|L|S]|[+|-<nick>]";
- TRANSLATE3(TR_NICK, TR_TEXT, TR_END); /* we watch for a nick. not a UID. */
+ TRANSLATE2(TR_NICK, TR_TEXT); /* we watch for a nick. not a UID. */
}
CmdResult Handle (const std::vector<std::string> &parameters, User *user)
{
- if (!ServerInstance->ULine(user->server))
+ if (!user->server->IsULine())
return CMD_FAILURE;
User *u = ServerInstance->FindNick(parameters[0]);
@@ -126,7 +119,7 @@ class CommandSVSWatch : public Command
if (IS_LOCAL(u))
{
- ServerInstance->Parser->CallHandler("WATCH", parameters, u);
+ ServerInstance->Parser.CallHandler("WATCH", parameters, u);
}
return CMD_SUCCESS;
@@ -151,9 +144,9 @@ class CommandWatch : public Command
CmdResult remove_watch(User* user, const char* nick)
{
// removing an item from the list
- if (!ServerInstance->IsNick(nick, ServerInstance->Config->Limits.NickMax))
+ if (!ServerInstance->IsNick(nick))
{
- user->WriteNumeric(942, "%s %s :Invalid nickname", user->nick.c_str(), nick);
+ user->WriteNumeric(942, "%s :Invalid nickname", nick);
return CMD_FAILURE;
}
@@ -169,9 +162,9 @@ class CommandWatch : public Command
if (n != wl->end())
{
if (!n->second.empty())
- user->WriteNumeric(602, "%s %s %s :stopped watching", user->nick.c_str(), n->first.c_str(), n->second.c_str());
+ user->WriteNumeric(602, "%s %s :stopped watching", n->first.c_str(), n->second.c_str());
else
- user->WriteNumeric(602, "%s %s * * 0 :stopped watching", user->nick.c_str(), nick);
+ user->WriteNumeric(602, "%s * * 0 :stopped watching", nick);
wl->erase(n);
}
@@ -201,9 +194,9 @@ class CommandWatch : public Command
CmdResult add_watch(User* user, const char* nick)
{
- if (!ServerInstance->IsNick(nick, ServerInstance->Config->Limits.NickMax))
+ if (!ServerInstance->IsNick(nick))
{
- user->WriteNumeric(942, "%s %s :Invalid nickname",user->nick.c_str(),nick);
+ user->WriteNumeric(942, "%s :Invalid nickname", nick);
return CMD_FAILURE;
}
@@ -216,7 +209,7 @@ class CommandWatch : public Command
if (wl->size() >= MAX_WATCH)
{
- user->WriteNumeric(512, "%s %s :Too many WATCH entries", user->nick.c_str(), nick);
+ user->WriteNumeric(512, "%s :Too many WATCH entries", nick);
return CMD_FAILURE;
}
@@ -241,16 +234,16 @@ class CommandWatch : public Command
if ((target) && (target->registered == REG_ALL))
{
(*wl)[nick] = std::string(target->ident).append(" ").append(target->dhost).append(" ").append(ConvToStr(target->age));
- user->WriteNumeric(604, "%s %s %s :is online",user->nick.c_str(), nick, (*wl)[nick].c_str());
- if (IS_AWAY(target))
+ user->WriteNumeric(604, "%s %s :is online", nick, (*wl)[nick].c_str());
+ if (target->IsAway())
{
- user->WriteNumeric(609, "%s %s %s %s %lu :is away", user->nick.c_str(), target->nick.c_str(), target->ident.c_str(), target->dhost.c_str(), (unsigned long) target->awaytime);
+ user->WriteNumeric(609, "%s %s %s %lu :is away", target->nick.c_str(), target->ident.c_str(), target->dhost.c_str(), (unsigned long) target->awaytime);
}
}
else
{
(*wl)[nick].clear();
- user->WriteNumeric(605, "%s %s * * 0 :is offline",user->nick.c_str(), nick);
+ user->WriteNumeric(605, "%s * * 0 :is offline", nick);
}
}
@@ -260,7 +253,6 @@ class CommandWatch : public Command
CommandWatch(Module* parent, unsigned int &maxwatch) : Command(parent,"WATCH", 0), MAX_WATCH(maxwatch), ext("watchlist", parent)
{
syntax = "[C|L|S]|[+|-<nick>]";
- TRANSLATE2(TR_TEXT, TR_END); /* we watch for a nick. not a UID. */
}
CmdResult Handle (const std::vector<std::string> &parameters, User *user)
@@ -273,10 +265,10 @@ class CommandWatch : public Command
for (watchlist::iterator q = wl->begin(); q != wl->end(); q++)
{
if (!q->second.empty())
- user->WriteNumeric(604, "%s %s %s :is online", user->nick.c_str(), q->first.c_str(), q->second.c_str());
+ user->WriteNumeric(604, "%s %s :is online", q->first.c_str(), q->second.c_str());
}
}
- user->WriteNumeric(607, "%s :End of WATCH list",user->nick.c_str());
+ user->WriteNumeric(607, ":End of WATCH list");
}
else if (parameters.size() > 0)
{
@@ -319,17 +311,17 @@ class CommandWatch : public Command
User* targ = ServerInstance->FindNick(q->first.c_str());
if (targ && !q->second.empty())
{
- user->WriteNumeric(604, "%s %s %s :is online", user->nick.c_str(), q->first.c_str(), q->second.c_str());
- if (IS_AWAY(targ))
+ user->WriteNumeric(604, "%s %s :is online", q->first.c_str(), q->second.c_str());
+ if (targ->IsAway())
{
- user->WriteNumeric(609, "%s %s %s %s %lu :is away", user->nick.c_str(), targ->nick.c_str(), targ->ident.c_str(), targ->dhost.c_str(), (unsigned long) targ->awaytime);
+ user->WriteNumeric(609, "%s %s %s %lu :is away", targ->nick.c_str(), targ->ident.c_str(), targ->dhost.c_str(), (unsigned long) targ->awaytime);
}
}
else
- user->WriteNumeric(605, "%s %s * * 0 :is offline", user->nick.c_str(), q->first.c_str());
+ user->WriteNumeric(605, "%s * * 0 :is offline", q->first.c_str());
}
}
- user->WriteNumeric(607, "%s :End of WATCH list",user->nick.c_str());
+ user->WriteNumeric(607, ":End of WATCH list");
}
else if (!strcasecmp(nick,"S"))
{
@@ -349,9 +341,9 @@ class CommandWatch : public Command
if (i2 != whos_watching_me->end())
youre_on = i2->second.size();
- user->WriteNumeric(603, "%s :You have %d and are on %d WATCH entries", user->nick.c_str(), you_have, youre_on);
- user->WriteNumeric(606, "%s :%s",user->nick.c_str(), list.c_str());
- user->WriteNumeric(607, "%s :End of WATCH S",user->nick.c_str());
+ user->WriteNumeric(603, ":You have %d and are on %d WATCH entries", you_have, youre_on);
+ user->WriteNumeric(606, ":%s", list.c_str());
+ user->WriteNumeric(607, ":End of WATCH S");
}
else if (nick[0] == '-')
{
@@ -382,24 +374,14 @@ class Modulewatch : public Module
whos_watching_me = new watchentries();
}
- void init()
- {
- OnRehash(NULL);
- ServerInstance->Modules->AddService(cmdw);
- ServerInstance->Modules->AddService(sw);
- ServerInstance->Modules->AddService(cmdw.ext);
- Implementation eventlist[] = { I_OnRehash, I_OnGarbageCollect, I_OnUserQuit, I_OnPostConnect, I_OnUserPostNick, I_On005Numeric, I_OnSetAway };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- }
-
- virtual void OnRehash(User* user)
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
maxwatch = ServerInstance->Config->ConfValue("watch")->getInt("maxentries", 32);
if (!maxwatch)
maxwatch = 32;
}
- virtual ModResult OnSetAway(User *user, const std::string &awaymsg)
+ ModResult OnSetAway(User *user, const std::string &awaymsg) CXX11_OVERRIDE
{
std::string numeric;
int inum;
@@ -427,14 +409,14 @@ class Modulewatch : public Module
return MOD_RES_PASSTHRU;
}
- virtual void OnUserQuit(User* user, const std::string &reason, const std::string &oper_message)
+ void OnUserQuit(User* user, const std::string &reason, const std::string &oper_message) CXX11_OVERRIDE
{
watchentries::iterator x = whos_watching_me->find(user->nick.c_str());
if (x != whos_watching_me->end())
{
for (std::deque<User*>::iterator n = x->second.begin(); n != x->second.end(); n++)
{
- (*n)->WriteNumeric(601, "%s %s %s %s %lu :went offline", (*n)->nick.c_str() ,user->nick.c_str(), user->ident.c_str(), user->dhost.c_str(), (unsigned long) ServerInstance->Time());
+ (*n)->WriteNumeric(601, "%s %s %s %lu :went offline", user->nick.c_str(), user->ident.c_str(), user->dhost.c_str(), (unsigned long) ServerInstance->Time());
watchlist* wl = cmdw.ext.get(*n);
if (wl)
@@ -467,7 +449,7 @@ class Modulewatch : public Module
}
}
- virtual void OnGarbageCollect()
+ void OnGarbageCollect()
{
watchentries* old_watch = whos_watching_me;
whos_watching_me = new watchentries();
@@ -478,14 +460,14 @@ class Modulewatch : public Module
delete old_watch;
}
- virtual void OnPostConnect(User* user)
+ void OnPostConnect(User* user) CXX11_OVERRIDE
{
watchentries::iterator x = whos_watching_me->find(user->nick.c_str());
if (x != whos_watching_me->end())
{
for (std::deque<User*>::iterator n = x->second.begin(); n != x->second.end(); n++)
{
- (*n)->WriteNumeric(600, "%s %s %s %s %lu :arrived online", (*n)->nick.c_str(), user->nick.c_str(), user->ident.c_str(), user->dhost.c_str(), (unsigned long) user->age);
+ (*n)->WriteNumeric(600, "%s %s %s %lu :arrived online", user->nick.c_str(), user->ident.c_str(), user->dhost.c_str(), (unsigned long) user->age);
watchlist* wl = cmdw.ext.get(*n);
if (wl)
@@ -495,7 +477,7 @@ class Modulewatch : public Module
}
}
- virtual void OnUserPostNick(User* user, const std::string &oldnick)
+ void OnUserPostNick(User* user, const std::string &oldnick) CXX11_OVERRIDE
{
watchentries::iterator new_offline = whos_watching_me->find(oldnick.c_str());
watchentries::iterator new_online = whos_watching_me->find(user->nick.c_str());
@@ -507,7 +489,7 @@ class Modulewatch : public Module
watchlist* wl = cmdw.ext.get(*n);
if (wl)
{
- (*n)->WriteNumeric(601, "%s %s %s %s %lu :went offline", (*n)->nick.c_str(), oldnick.c_str(), user->ident.c_str(), user->dhost.c_str(), (unsigned long) user->age);
+ (*n)->WriteNumeric(601, "%s %s %s %lu :went offline", oldnick.c_str(), user->ident.c_str(), user->dhost.c_str(), (unsigned long) user->age);
(*wl)[oldnick.c_str()].clear();
}
}
@@ -521,28 +503,26 @@ class Modulewatch : public Module
if (wl)
{
(*wl)[user->nick.c_str()] = std::string(user->ident).append(" ").append(user->dhost).append(" ").append(ConvToStr(user->age));
- (*n)->WriteNumeric(600, "%s %s %s :arrived online", (*n)->nick.c_str(), user->nick.c_str(), (*wl)[user->nick.c_str()].c_str());
+ (*n)->WriteNumeric(600, "%s %s :arrived online", user->nick.c_str(), (*wl)[user->nick.c_str()].c_str());
}
}
}
}
- virtual void On005Numeric(std::string &output)
+ void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
{
- // we don't really have a limit...
- output = output + " WATCH=" + ConvToStr(maxwatch);
+ tokens["WATCH"] = ConvToStr(maxwatch);
}
- virtual ~Modulewatch()
+ ~Modulewatch()
{
delete whos_watching_me;
}
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides support for the /WATCH command", VF_OPTCOMMON | VF_VENDOR);
}
};
MODULE_INIT(Modulewatch)
-
diff --git a/src/modules/m_xline_db.cpp b/src/modules/m_xline_db.cpp
index 2237b0d08..c35f0d07a 100644
--- a/src/modules/m_xline_db.cpp
+++ b/src/modules/m_xline_db.cpp
@@ -20,45 +20,36 @@
#include "inspircd.h"
#include "xline.h"
-
-/* $ModConfig: <xlinedb filename="data/xline.db">
- * Specify the filename for the xline database here*/
-/* $ModDesc: Keeps a dynamic log of all XLines created, and stores them in a seperate conf file (xline.db). */
+#include <fstream>
class ModuleXLineDB : public Module
{
bool dirty;
std::string xlinedbpath;
public:
- void init()
+ void init() CXX11_OVERRIDE
{
/* Load the configuration
* Note:
- * this is on purpose not in the OnRehash() method. It would be non-trivial to change the database on-the-fly.
+ * This is on purpose not changed on a rehash. It would be non-trivial to change the database on-the-fly.
* Imagine a scenario where the new file already exists. Merging the current XLines with the existing database is likely a bad idea
* ...and so is discarding all current in-memory XLines for the ones in the database.
*/
ConfigTag* Conf = ServerInstance->Config->ConfValue("xlinedb");
- xlinedbpath = Conf->getString("filename", DATA_PATH "/xline.db");
+ xlinedbpath = ServerInstance->Config->Paths.PrependData(Conf->getString("filename", "xline.db"));
// Read xlines before attaching to events
ReadDatabase();
- Implementation eventlist[] = { I_OnAddLine, I_OnDelLine, I_OnExpireLine, I_OnBackgroundTimer };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
dirty = false;
}
- virtual ~ModuleXLineDB()
- {
- }
-
/** Called whenever an xline is added by a local user.
* This method is triggered after the line is added.
* @param source The sender of the line or NULL for local server
* @param line The xline being added
*/
- void OnAddLine(User* source, XLine* line)
+ void OnAddLine(User* source, XLine* line) CXX11_OVERRIDE
{
dirty = true;
}
@@ -68,17 +59,17 @@ class ModuleXLineDB : public Module
* @param source The user removing the line or NULL for local server
* @param line the line being deleted
*/
- void OnDelLine(User* source, XLine* line)
+ void OnDelLine(User* source, XLine* line) CXX11_OVERRIDE
{
dirty = true;
}
- void OnExpireLine(XLine *line)
+ void OnExpireLine(XLine *line) CXX11_OVERRIDE
{
dirty = true;
}
- void OnBackgroundTimer(time_t now)
+ void OnBackgroundTimer(time_t now) CXX11_OVERRIDE
{
if (dirty)
{
@@ -89,25 +80,23 @@ class ModuleXLineDB : public Module
bool WriteDatabase()
{
- FILE *f;
-
/*
* We need to perform an atomic write so as not to fuck things up.
- * So, let's write to a temporary file, flush and sync the FD, then rename the file..
+ * So, let's write to a temporary file, flush it, then rename the file..
* Technically, that means that this can block, but I have *never* seen that.
- * -- w00t
+ * -- w00t
*/
- ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: Opening temporary database");
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Opening temporary database");
std::string xlinenewdbpath = xlinedbpath + ".new";
- f = fopen(xlinenewdbpath.c_str(), "w");
- if (!f)
+ std::ofstream stream(xlinenewdbpath.c_str());
+ if (!stream.is_open())
{
- ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: Cannot create database! %s (%d)", strerror(errno), errno);
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Cannot create database! %s (%d)", strerror(errno), errno);
ServerInstance->SNO->WriteToSnoMask('a', "database: cannot create new db: %s (%d)", strerror(errno), errno);
return false;
}
- ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: Opened. Writing..");
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Opened. Writing..");
/*
* Now, much as I hate writing semi-unportable formats, additional
@@ -116,7 +105,7 @@ class ModuleXLineDB : public Module
* semblance of backwards compatibility for reading on startup..
* -- w00t
*/
- fprintf(f, "VERSION 1\n");
+ stream << "VERSION 1" << std::endl;
// Now, let's write.
std::vector<std::string> types = ServerInstance->XLines->GetAllTypes();
@@ -129,22 +118,21 @@ class ModuleXLineDB : public Module
for (LookupIter i = lookup->begin(); i != lookup->end(); ++i)
{
XLine* line = i->second;
- fprintf(f, "LINE %s %s %s %lu %lu :%s\n", line->type.c_str(), line->Displayable(),
- ServerInstance->Config->ServerName.c_str(), (unsigned long)line->set_time, (unsigned long)line->duration, line->reason.c_str());
+ stream << "LINE " << line->type << " " << line->Displayable() << " "
+ << ServerInstance->Config->ServerName << " " << line->set_time << " "
+ << line->duration << " " << line->reason << std::endl;
}
}
- ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: Finished writing XLines. Checking for error..");
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Finished writing XLines. Checking for error..");
- int write_error = 0;
- write_error = ferror(f);
- write_error |= fclose(f);
- if (write_error)
+ if (stream.fail())
{
- ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: Cannot write to new database! %s (%d)", strerror(errno), errno);
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Cannot write to new database! %s (%d)", strerror(errno), errno);
ServerInstance->SNO->WriteToSnoMask('a', "database: cannot write to new db: %s (%d)", strerror(errno), errno);
return false;
}
+ stream.close();
#ifdef _WIN32
remove(xlinedbpath.c_str());
@@ -152,7 +140,7 @@ class ModuleXLineDB : public Module
// Use rename to move temporary to new db - this is guarenteed not to fuck up, even in case of a crash.
if (rename(xlinenewdbpath.c_str(), xlinedbpath.c_str()) < 0)
{
- ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: Cannot move new to old database! %s (%d)", strerror(errno), errno);
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Cannot move new to old database! %s (%d)", strerror(errno), errno);
ServerInstance->SNO->WriteToSnoMask('a', "database: cannot replace old with new db: %s (%d)", strerror(errno), errno);
return false;
}
@@ -162,42 +150,23 @@ class ModuleXLineDB : public Module
bool ReadDatabase()
{
- FILE *f;
- char linebuf[MAXBUF];
+ // If the xline database doesn't exist then we don't need to load it.
+ if (!FileSystem::FileExists(xlinedbpath))
+ return true;
- f = fopen(xlinedbpath.c_str(), "r");
- if (!f)
+ std::ifstream stream(xlinedbpath.c_str());
+ if (!stream.is_open())
{
- if (errno == ENOENT)
- {
- /* xline.db doesn't exist, fake good return value (we don't care about this) */
- return true;
- }
- else
- {
- /* this might be slightly more problematic. */
- ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: Cannot read database! %s (%d)", strerror(errno), errno);
- ServerInstance->SNO->WriteToSnoMask('a', "database: cannot read db: %s (%d)", strerror(errno), errno);
- return false;
- }
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Cannot read database! %s (%d)", strerror(errno), errno);
+ ServerInstance->SNO->WriteToSnoMask('a', "database: cannot read db: %s (%d)", strerror(errno), errno);
+ return false;
}
- while (fgets(linebuf, MAXBUF, f))
+ std::string line;
+ while (std::getline(stream, line))
{
- char *c = linebuf;
-
- while (c && *c)
- {
- if (*c == '\n')
- {
- *c = '\0';
- }
-
- c++;
- }
-
// Inspired by the command parser. :)
- irc::tokenstream tokens(linebuf);
+ irc::tokenstream tokens(line);
int items = 0;
std::string command_p[7];
std::string tmp;
@@ -208,18 +177,14 @@ class ModuleXLineDB : public Module
items++;
}
- ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: Processing %s", linebuf);
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Processing %s", line.c_str());
if (command_p[0] == "VERSION")
{
- if (command_p[1] == "1")
- {
- ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: Reading db version %s", command_p[1].c_str());
- }
- else
+ if (command_p[1] != "1")
{
- fclose(f);
- ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: I got database version %s - I don't understand it", command_p[1].c_str());
+ stream.close();
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "I got database version %s - I don't understand it", command_p[1].c_str());
ServerInstance->SNO->WriteToSnoMask('a', "database: I got a database version (%s) I don't understand", command_p[1].c_str());
return false;
}
@@ -246,18 +211,14 @@ class ModuleXLineDB : public Module
delete xl;
}
}
-
- fclose(f);
+ stream.close();
return true;
}
-
-
- virtual Version GetVersion()
+ Version GetVersion() CXX11_OVERRIDE
{
return Version("Keeps a dynamic log of all XLines created, and stores them in a separate conf file (xline.db).", VF_VENDOR);
}
};
MODULE_INIT(ModuleXLineDB)
-
diff --git a/src/modules/sasl.h b/src/modules/sasl.h
deleted file mode 100644
index f67351104..000000000
--- a/src/modules/sasl.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#ifndef SASL_H
-#define SASL_H
-
-class SASLFallback : public Event
-{
- public:
- const parameterlist& params;
- SASLFallback(Module* me, const parameterlist& p)
- : Event(me, "sasl_fallback"), params(p)
- {
- Send();
- }
-};
-
-#endif
diff --git a/src/modules/sql.h b/src/modules/sql.h
deleted file mode 100644
index 436cd1da8..000000000
--- a/src/modules/sql.h
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#ifndef INSPIRCD_SQLAPI_3
-#define INSPIRCD_SQLAPI_3
-
-/** Defines the error types which SQLerror may be set to
- */
-enum SQLerrorNum { SQL_NO_ERROR, SQL_BAD_DBID, SQL_BAD_CONN, SQL_QSEND_FAIL, SQL_QREPLY_FAIL };
-
-/** A list of format parameters for an SQLquery object.
- */
-typedef std::vector<std::string> ParamL;
-
-typedef std::map<std::string, std::string> ParamM;
-
-class SQLEntry
-{
- public:
- std::string value;
- bool nul;
- SQLEntry() : nul(true) {}
- SQLEntry(const std::string& v) : value(v), nul(false) {}
- inline operator std::string&() { return value; }
-};
-
-typedef std::vector<SQLEntry> SQLEntries;
-
-/**
- * Result of an SQL query. Only valid inside OnResult
- */
-class SQLResult : public classbase
-{
- public:
- /**
- * Return the number of rows in the result.
- *
- * Note that if you have perfomed an INSERT or UPDATE query or other
- * query which will not return rows, this will return the number of
- * affected rows. In this case you SHOULD NEVER access any of the result
- * set rows, as there aren't any!
- * @returns Number of rows in the result set.
- */
- virtual int Rows() = 0;
-
- /**
- * Return a single row (result of the query). The internal row counter
- * is incremented by one.
- *
- * @param result Storage for the result data.
- * @returns true if there was a row, false if no row exists (end of
- * iteration)
- */
- virtual bool GetRow(SQLEntries& result) = 0;
-
- /** Returns column names for the items in this row
- */
- virtual void GetCols(std::vector<std::string>& result) = 0;
-};
-
-/** SQLerror holds the error state of a request.
- * The error string varies from database software to database software
- * and should be used to display informational error messages to users.
- */
-class SQLerror
-{
- public:
- /** The error id
- */
- SQLerrorNum id;
-
- /** The error string
- */
- std::string str;
-
- /** Initialize an SQLerror
- * @param i The error ID to set
- * @param s The (optional) error string to set
- */
- SQLerror(SQLerrorNum i, const std::string &s = "")
- : id(i), str(s)
- {
- }
-
- /** Return the error string for an error
- */
- const char* Str()
- {
- if(str.length())
- return str.c_str();
-
- switch(id)
- {
- case SQL_BAD_DBID:
- return "Invalid database ID";
- case SQL_BAD_CONN:
- return "Invalid connection";
- case SQL_QSEND_FAIL:
- return "Sending query failed";
- case SQL_QREPLY_FAIL:
- return "Getting query result failed";
- default:
- return "Unknown error";
- }
- }
-};
-
-/**
- * Object representing an SQL query. This should be allocated on the heap and
- * passed to an SQLProvider, which will free it when the query is complete or
- * when the querying module is unloaded.
- *
- * You should store whatever information is needed to have the callbacks work in
- * this object (UID of user, channel name, etc).
- */
-class SQLQuery : public classbase
-{
- public:
- ModuleRef creator;
-
- SQLQuery(Module* Creator) : creator(Creator) {}
- virtual ~SQLQuery() {}
-
- virtual void OnResult(SQLResult& result) = 0;
- /**
- * Called when the query fails
- */
- virtual void OnError(SQLerror& error) { }
-};
-
-/**
- * Provider object for SQL servers
- */
-class SQLProvider : public DataProvider
-{
- public:
- SQLProvider(Module* Creator, const std::string& Name) : DataProvider(Creator, Name) {}
- /** Submit an asynchronous SQL request
- * @param callback The result reporting point
- * @param query The hardcoded query string. If you have parameters to substitute, see below.
- */
- virtual void submit(SQLQuery* callback, const std::string& query) = 0;
-
- /** Submit an asynchronous SQL request
- * @param callback The result reporting point
- * @param format The simple parameterized query string ('?' parameters)
- * @param p Parameters to fill in for the '?' entries
- */
- virtual void submit(SQLQuery* callback, const std::string& format, const ParamL& p) = 0;
-
- /** Submit an asynchronous SQL request.
- * @param callback The result reporting point
- * @param format The parameterized query string ('$name' parameters)
- * @param p Parameters to fill in for the '$name' entries
- */
- virtual void submit(SQLQuery* callback, const std::string& format, const ParamM& p) = 0;
-
- /** Convenience function to prepare a map from a User* */
- void PopulateUserInfo(User* user, ParamM& userinfo)
- {
- userinfo["nick"] = user->nick;
- userinfo["host"] = user->host;
- userinfo["ip"] = user->GetIPString();
- userinfo["gecos"] = user->fullname;
- userinfo["ident"] = user->ident;
- userinfo["server"] = user->server;
- userinfo["uuid"] = user->uuid;
- }
-};
-
-#endif
diff --git a/src/modules/ssl.h b/src/modules/ssl.h
deleted file mode 100644
index 9deafb830..000000000
--- a/src/modules/ssl.h
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#ifndef SSL_H
-#define SSL_H
-
-#include <map>
-#include <string>
-
-/** ssl_cert is a class which abstracts SSL certificate
- * and key information.
- *
- * Because gnutls and openssl represent key information in
- * wildly different ways, this class allows it to be accessed
- * in a unified manner. These classes are attached to ssl-
- * connected local users using SSLCertExt
- */
-class ssl_cert : public refcountbase
-{
- public:
- std::string dn;
- std::string issuer;
- std::string error;
- std::string fingerprint;
- bool trusted, invalid, unknownsigner, revoked;
-
- ssl_cert() : trusted(false), invalid(true), unknownsigner(true), revoked(false) {}
-
- /** Get certificate distinguished name
- * @return Certificate DN
- */
- const std::string& GetDN()
- {
- return dn;
- }
-
- /** Get Certificate issuer
- * @return Certificate issuer
- */
- const std::string& GetIssuer()
- {
- return issuer;
- }
-
- /** Get error string if an error has occured
- * @return The error associated with this users certificate,
- * or an empty string if there is no error.
- */
- const std::string& GetError()
- {
- return error;
- }
-
- /** Get key fingerprint.
- * @return The key fingerprint as a hex string.
- */
- const std::string& GetFingerprint()
- {
- return fingerprint;
- }
-
- /** Get trust status
- * @return True if this is a trusted certificate
- * (the certificate chain validates)
- */
- bool IsTrusted()
- {
- return trusted;
- }
-
- /** Get validity status
- * @return True if the certificate itself is
- * correctly formed.
- */
- bool IsInvalid()
- {
- return invalid;
- }
-
- /** Get signer status
- * @return True if the certificate appears to be
- * self-signed.
- */
- bool IsUnknownSigner()
- {
- return unknownsigner;
- }
-
- /** Get revokation status.
- * @return True if the certificate is revoked.
- * Note that this only works properly for GnuTLS
- * right now.
- */
- bool IsRevoked()
- {
- return revoked;
- }
-
- bool IsCAVerified()
- {
- return trusted && !invalid && !revoked && !unknownsigner && error.empty();
- }
-
- std::string GetMetaLine()
- {
- std::stringstream value;
- bool hasError = !error.empty();
- value << (IsInvalid() ? "v" : "V") << (IsTrusted() ? "T" : "t") << (IsRevoked() ? "R" : "r")
- << (IsUnknownSigner() ? "s" : "S") << (hasError ? "E" : "e") << " ";
- if (hasError)
- value << GetError();
- else
- value << GetFingerprint() << " " << GetDN() << " " << GetIssuer();
- return value.str();
- }
-};
-
-/** Get certificate from a socket (only useful with an SSL module) */
-struct SocketCertificateRequest : public Request
-{
- StreamSocket* const sock;
- ssl_cert* cert;
-
- SocketCertificateRequest(StreamSocket* ss, Module* Me)
- : Request(Me, ss->GetIOHook(), "GET_SSL_CERT"), sock(ss), cert(NULL)
- {
- Send();
- }
-
- std::string GetFingerprint()
- {
- if (cert)
- return cert->GetFingerprint();
- return "";
- }
-};
-
-/** Get certificate from a user (requires m_sslinfo) */
-struct UserCertificateRequest : public Request
-{
- User* const user;
- ssl_cert* cert;
-
- UserCertificateRequest(User* u, Module* Me, Module* info = ServerInstance->Modules->Find("m_sslinfo.so"))
- : Request(Me, info, "GET_USER_CERT"), user(u), cert(NULL)
- {
- Send();
- }
-
- std::string GetFingerprint()
- {
- if (cert)
- return cert->GetFingerprint();
- return "";
- }
-};
-
-#endif
diff --git a/src/modules/u_listmode.h b/src/modules/u_listmode.h
deleted file mode 100644
index 0f5903e53..000000000
--- a/src/modules/u_listmode.h
+++ /dev/null
@@ -1,423 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#ifndef INSPIRCD_LISTMODE_PROVIDER
-#define INSPIRCD_LISTMODE_PROVIDER
-
-/** Get the time as a string
- */
-inline std::string stringtime()
-{
- std::ostringstream TIME;
- TIME << ServerInstance->Time();
- return TIME.str();
-}
-
-/** An item in a listmode's list
- */
-class ListItem
-{
-public:
- std::string nick;
- std::string mask;
- std::string time;
-};
-
-/** The number of items a listmode's list may contain
- */
-class ListLimit
-{
-public:
- std::string mask;
- unsigned int limit;
-};
-
-/** Items stored in the channel's list
- */
-typedef std::list<ListItem> modelist;
-/** Max items per channel by name
- */
-typedef std::list<ListLimit> limitlist;
-
-/** The base class for list modes, should be inherited.
- */
-class ListModeBase : public ModeHandler
-{
- protected:
- /** Numeric to use when outputting the list
- */
- unsigned int listnumeric;
- /** Numeric to indicate end of list
- */
- unsigned int endoflistnumeric;
- /** String to send for end of list
- */
- std::string endofliststring;
- /** Automatically tidy up entries
- */
- bool tidy;
- /** Config tag to check for max items per channel
- */
- std::string configtag;
- /** Limits on a per-channel basis read from the tag
- * specified in ListModeBase::configtag
- */
- limitlist chanlimits;
-
- public:
- /** Storage key
- */
- SimpleExtItem<modelist> extItem;
-
- /** Constructor.
- * @param Instance The creator of this class
- * @param modechar Mode character
- * @param eolstr End of list string
- * @pram lnum List numeric
- * @param eolnum End of list numeric
- * @param autotidy Automatically tidy list entries on add
- * @param ctag Configuration tag to get limits from
- */
- ListModeBase(Module* Creator, const std::string& Name, char modechar, const std::string &eolstr, unsigned int lnum, unsigned int eolnum, bool autotidy, const std::string &ctag = "banlist")
- : ModeHandler(Creator, Name, modechar, PARAM_ALWAYS, MODETYPE_CHANNEL),
- listnumeric(lnum), endoflistnumeric(eolnum), endofliststring(eolstr), tidy(autotidy),
- configtag(ctag), extItem("listbase_mode_" + name + "_list", Creator)
- {
- list = true;
- }
-
- /** See mode.h
- */
- std::pair<bool,std::string> ModeSet(User*, User*, Channel* channel, const std::string &parameter)
- {
- modelist* el = extItem.get(channel);
- if (el)
- {
- for (modelist::iterator it = el->begin(); it != el->end(); it++)
- {
- if(parameter == it->mask)
- {
- return std::make_pair(true, parameter);
- }
- }
- }
- return std::make_pair(false, parameter);
- }
-
- /** Display the list for this mode
- * @param user The user to send the list to
- * @param channel The channel the user is requesting the list for
- */
- virtual void DisplayList(User* user, Channel* channel)
- {
- modelist* el = extItem.get(channel);
- if (el)
- {
- for (modelist::reverse_iterator it = el->rbegin(); it != el->rend(); ++it)
- {
- user->WriteNumeric(listnumeric, "%s %s %s %s %s", user->nick.c_str(), channel->name.c_str(), it->mask.c_str(), (it->nick.length() ? it->nick.c_str() : ServerInstance->Config->ServerName.c_str()), it->time.c_str());
- }
- }
- user->WriteNumeric(endoflistnumeric, "%s %s :%s", user->nick.c_str(), channel->name.c_str(), endofliststring.c_str());
- }
-
- virtual void DisplayEmptyList(User* user, Channel* channel)
- {
- user->WriteNumeric(endoflistnumeric, "%s %s :%s", user->nick.c_str(), channel->name.c_str(), endofliststring.c_str());
- }
-
- /** Remove all instances of the mode from a channel.
- * See mode.h
- * @param channel The channel to remove all instances of the mode from
- */
- virtual void RemoveMode(Channel* channel, irc::modestacker* stack)
- {
- modelist* el = extItem.get(channel);
- if (el)
- {
- irc::modestacker modestack(false);
-
- for (modelist::iterator it = el->begin(); it != el->end(); it++)
- {
- if (stack)
- stack->Push(this->GetModeChar(), it->mask);
- else
- modestack.Push(this->GetModeChar(), it->mask);
- }
-
- if (stack)
- return;
-
- std::vector<std::string> stackresult;
- stackresult.push_back(channel->name);
- while (modestack.GetStackedLine(stackresult))
- {
- ServerInstance->SendMode(stackresult, ServerInstance->FakeClient);
- stackresult.clear();
- stackresult.push_back(channel->name);
- }
- }
- }
-
- /** See mode.h
- */
- virtual void RemoveMode(User*, irc::modestacker* stack)
- {
- /* Listmodes dont get set on users */
- }
-
- /** Perform a rehash of this mode's configuration data
- */
- virtual void DoRehash()
- {
- ConfigTagList tags = ServerInstance->Config->ConfTags(configtag);
-
- chanlimits.clear();
-
- for (ConfigIter i = tags.first; i != tags.second; i++)
- {
- // For each <banlist> tag
- ConfigTag* c = i->second;
- ListLimit limit;
- limit.mask = c->getString("chan");
- limit.limit = c->getInt("limit");
-
- if (limit.mask.size() && limit.limit > 0)
- chanlimits.push_back(limit);
- }
- if (chanlimits.empty())
- {
- ListLimit limit;
- limit.mask = "*";
- limit.limit = 64;
- chanlimits.push_back(limit);
- }
- }
-
- /** Populate the Implements list with the correct events for a List Mode
- */
- virtual void DoImplements(Module* m)
- {
- ServerInstance->Modules->AddService(extItem);
- this->DoRehash();
- Implementation eventlist[] = { I_OnSyncChannel, I_OnRehash };
- ServerInstance->Modules->Attach(eventlist, m, sizeof(eventlist)/sizeof(Implementation));
- }
-
- /** Handle the list mode.
- * See mode.h
- */
- virtual ModeAction OnModeChange(User* source, User*, Channel* channel, std::string &parameter, bool adding)
- {
- // Try and grab the list
- modelist* el = extItem.get(channel);
-
- if (adding)
- {
- if (tidy)
- ModeParser::CleanMask(parameter);
-
- if (parameter.length() > 250)
- return MODEACTION_DENY;
-
- // If there was no list
- if (!el)
- {
- // Make one
- el = new modelist;
- extItem.set(channel, el);
- }
-
- // Check if the item already exists in the list
- for (modelist::iterator it = el->begin(); it != el->end(); it++)
- {
- if (parameter == it->mask)
- {
- /* Give a subclass a chance to error about this */
- TellAlreadyOnList(source, channel, parameter);
-
- // it does, deny the change
- return MODEACTION_DENY;
- }
- }
-
- unsigned int maxsize = 0;
-
- for (limitlist::iterator it = chanlimits.begin(); it != chanlimits.end(); it++)
- {
- if (InspIRCd::Match(channel->name, it->mask))
- {
- // We have a pattern matching the channel...
- maxsize = el->size();
- if (!IS_LOCAL(source) || (maxsize < it->limit))
- {
- /* Ok, it *could* be allowed, now give someone subclassing us
- * a chance to validate the parameter.
- * The param is passed by reference, so they can both modify it
- * and tell us if we allow it or not.
- *
- * eg, the subclass could:
- * 1) allow
- * 2) 'fix' parameter and then allow
- * 3) deny
- */
- if (ValidateParam(source, channel, parameter))
- {
- // And now add the mask onto the list...
- ListItem e;
- e.mask = parameter;
- e.nick = source->nick;
- e.time = stringtime();
-
- el->push_back(e);
- return MODEACTION_ALLOW;
- }
- else
- {
- /* If they deny it they have the job of giving an error message */
- return MODEACTION_DENY;
- }
- }
- }
- }
-
- /* List is full, give subclass a chance to send a custom message */
- if (!TellListTooLong(source, channel, parameter))
- {
- source->WriteNumeric(478, "%s %s %s :Channel ban/ignore list is full", source->nick.c_str(), channel->name.c_str(), parameter.c_str());
- }
-
- parameter.clear();
- return MODEACTION_DENY;
- }
- else
- {
- // We're taking the mode off
- if (el)
- {
- for (modelist::iterator it = el->begin(); it != el->end(); it++)
- {
- if (parameter == it->mask)
- {
- el->erase(it);
- if (el->empty())
- {
- extItem.unset(channel);
- }
- return MODEACTION_ALLOW;
- }
- }
- /* Tried to remove something that wasn't set */
- TellNotSet(source, channel, parameter);
- parameter.clear();
- return MODEACTION_DENY;
- }
- else
- {
- /* Hmm, taking an exception off a non-existant list, DIE */
- TellNotSet(source, channel, parameter);
- parameter.clear();
- return MODEACTION_DENY;
- }
- }
- return MODEACTION_DENY;
- }
-
- /** Syncronize channel item list with another server.
- * See modules.h
- * @param chan Channel to syncronize
- * @param proto Protocol module pointer
- * @param opaque Opaque connection handle
- */
- virtual void DoSyncChannel(Channel* chan, Module* proto, void* opaque)
- {
- modelist* mlist = extItem.get(chan);
- irc::modestacker modestack(true);
- std::vector<std::string> stackresult;
- std::vector<TranslateType> types;
- types.push_back(TR_TEXT);
- if (mlist)
- {
- for (modelist::iterator it = mlist->begin(); it != mlist->end(); it++)
- {
- modestack.Push(std::string(1, mode)[0], it->mask);
- }
- }
- while (modestack.GetStackedLine(stackresult))
- {
- types.assign(stackresult.size(), this->GetTranslateType());
- proto->ProtoSendMode(opaque, TYPE_CHANNEL, chan, stackresult, types);
- stackresult.clear();
- }
- }
-
- /** Clean up module on unload
- * @param target_type Type of target to clean
- * @param item Item to clean
- */
- virtual void DoCleanup(int, void*)
- {
- }
-
- /** Validate parameters.
- * Overridden by implementing module.
- * @param source Source user adding the parameter
- * @param channel Channel the parameter is being added to
- * @param parameter The actual parameter being added
- * @return true if the parameter is valid
- */
- virtual bool ValidateParam(User*, Channel*, std::string&)
- {
- return true;
- }
-
- /** Tell the user the list is too long.
- * Overridden by implementing module.
- * @param source Source user adding the parameter
- * @param channel Channel the parameter is being added to
- * @param parameter The actual parameter being added
- * @return Ignored
- */
- virtual bool TellListTooLong(User*, Channel*, std::string&)
- {
- return false;
- }
-
- /** Tell the user an item is already on the list.
- * Overridden by implementing module.
- * @param source Source user adding the parameter
- * @param channel Channel the parameter is being added to
- * @param parameter The actual parameter being added
- */
- virtual void TellAlreadyOnList(User*, Channel*, std::string&)
- {
- }
-
- /** Tell the user that the parameter is not in the list.
- * Overridden by implementing module.
- * @param source Source user removing the parameter
- * @param channel Channel the parameter is being removed from
- * @param parameter The actual parameter being removed
- */
- virtual void TellNotSet(User*, Channel*, std::string&)
- {
- }
-};
-
-#endif
diff --git a/src/server.cpp b/src/server.cpp
index 4741f942d..ceefa4387 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -23,7 +23,6 @@
#include <signal.h>
#include "exitcodes.h"
#include "inspircd.h"
-#include "inspircd_version.h"
void InspIRCd::SignalHandler(int signal)
{
@@ -32,12 +31,13 @@ void InspIRCd::SignalHandler(int signal)
#else
if (signal == SIGHUP)
{
- Rehash("Caught SIGHUP");
+ ServerInstance->SNO->WriteGlobalSno('a', "Rehashing due to SIGHUP");
+ Rehash();
}
else if (signal == SIGTERM)
#endif
{
- Exit(signal);
+ Exit(EXIT_STATUS_SIGTERM);
}
}
@@ -56,48 +56,37 @@ void InspIRCd::Exit(int status)
exit (status);
}
-void RehashHandler::Call(const std::string &reason)
+void InspIRCd::Rehash(const std::string& uuid)
{
- ServerInstance->SNO->WriteToSnoMask('a', "Rehashing config file %s %s",ServerConfig::CleanFilename(ServerInstance->ConfigFileName.c_str()), reason.c_str());
- ServerInstance->RehashUsersAndChans();
- FOREACH_MOD(I_OnGarbageCollect, OnGarbageCollect());
if (!ServerInstance->ConfigThread)
{
- ServerInstance->ConfigThread = new ConfigReaderThread("");
- ServerInstance->Threads->Start(ServerInstance->ConfigThread);
+ ServerInstance->ConfigThread = new ConfigReaderThread(uuid);
+ ServerInstance->Threads.Start(ServerInstance->ConfigThread);
}
}
-std::string InspIRCd::GetVersionString(bool operstring)
+std::string InspIRCd::GetVersionString(bool getFullVersion)
{
- char versiondata[MAXBUF];
- if (operstring)
- {
- std::string sename = SE->GetName();
- snprintf(versiondata,MAXBUF,"%s %s :%s [%s,%s,%s]",VERSION, Config->ServerName.c_str(), SYSTEM,REVISION, sename.c_str(), Config->sid.c_str());
- }
- else
- snprintf(versiondata,MAXBUF,"%s %s :%s",BRANCH,Config->ServerName.c_str(),Config->CustomVersion.c_str());
- return versiondata;
+ if (getFullVersion)
+ return INSPIRCD_VERSION " " + Config->ServerName + " :" INSPIRCD_SYSTEM " [" INSPIRCD_REVISION "," INSPIRCD_SOCKETENGINE_NAME "," + Config->sid + "]";
+ return INSPIRCD_BRANCH " " + Config->ServerName + " :" + Config->CustomVersion;
}
-const char InspIRCd::LogHeader[] =
- "Log started for " VERSION " (" REVISION ", " MODULE_INIT_STR ")"
- " - compiled on " SYSTEM;
-
-void InspIRCd::BuildISupport()
+std::string UIDGenerator::GenerateSID(const std::string& servername, const std::string& serverdesc)
{
- // the neatest way to construct the initial 005 numeric, considering the number of configure constants to go in it...
- std::stringstream v;
- v << "WALLCHOPS WALLVOICES MODES=" << Config->Limits.MaxModes << " CHANTYPES=# PREFIX=" << this->Modes->BuildPrefixes() << " MAP MAXCHANNELS=" << Config->MaxChans << " MAXBANS=60 VBANLIST NICKLEN=" << Config->Limits.NickMax;
- v << " CASEMAPPING=rfc1459 STATUSMSG=" << Modes->BuildPrefixes(false) << " CHARSET=ascii TOPICLEN=" << Config->Limits.MaxTopic << " KICKLEN=" << Config->Limits.MaxKick << " MAXTARGETS=" << Config->MaxTargets;
- v << " AWAYLEN=" << Config->Limits.MaxAway << " CHANMODES=" << this->Modes->GiveModeList(MASK_CHANNEL) << " FNC NETWORK=" << Config->Network << " MAXPARA=32 ELIST=MU" << " CHANNELLEN=" << Config->Limits.ChanMax;
- Config->data005 = v.str();
- FOREACH_MOD(I_On005Numeric,On005Numeric(Config->data005));
- Config->Update005();
+ unsigned int sid = 0;
+
+ for (std::string::const_iterator i = servername.begin(); i != servername.end(); ++i)
+ sid = 5 * sid + *i;
+ for (std::string::const_iterator i = serverdesc.begin(); i != serverdesc.end(); ++i)
+ sid = 5 * sid + *i;
+
+ std::string sidstr = ConvToStr(sid % 1000);
+ sidstr.insert(0, 3 - sidstr.length(), '0');
+ return sidstr;
}
-void InspIRCd::IncrementUID(int pos)
+void UIDGenerator::IncrementUID(unsigned int pos)
{
/*
* Okay. The rules for generating a UID go like this...
@@ -106,85 +95,138 @@ void InspIRCd::IncrementUID(int pos)
* A again, in an iterative fashion.. so..
* AAA9 -> AABA, and so on. -- w00t
*/
- if ((pos == 3) && (current_uid[3] == '9'))
+
+ // If we hit Z, wrap around to 0.
+ if (current_uid[pos] == 'Z')
+ {
+ current_uid[pos] = '0';
+ }
+ else if (current_uid[pos] == '9')
{
- // At pos 3, if we hit '9', we've run out of available UIDs, and need to reset to AAA..AAA.
- for (int i = 3; i < UUID_LENGTH-1; i++)
+ /*
+ * Or, if we hit 9, wrap around to pos = 'A' and (pos - 1)++,
+ * e.g. A9 -> BA -> BB ..
+ */
+ current_uid[pos] = 'A';
+ if (pos == 3)
{
- current_uid[i] = 'A';
+ // At pos 3, if we hit '9', we've run out of available UIDs, and reset to AAA..AAA.
+ return;
}
+ this->IncrementUID(pos - 1);
}
else
{
- // If we hit Z, wrap around to 0.
- if (current_uid[pos] == 'Z')
- {
- current_uid[pos] = '0';
- }
- else if (current_uid[pos] == '9')
- {
- /*
- * Or, if we hit 9, wrap around to pos = 'A' and (pos - 1)++,
- * e.g. A9 -> BA -> BB ..
- */
- current_uid[pos] = 'A';
- this->IncrementUID(pos - 1);
- }
- else
- {
- // Anything else, nobody gives a shit. Just increment.
- current_uid[pos]++;
- }
+ // Anything else, nobody gives a shit. Just increment.
+ current_uid[pos]++;
}
}
-/*
- * Retrieve the next valid UUID that is free for this server.
- */
-std::string InspIRCd::GetUID()
+void UIDGenerator::init(const std::string& sid)
{
- static bool inited = false;
-
/*
- * If we're setting up, copy SID into the first three digits, 9's to the rest, null term at the end
+ * Copy SID into the first three digits, 9's to the rest, null term at the end
* Why 9? Well, we increment before we find, otherwise we have an unnecessary copy, and I want UID to start at AAA..AA
* and not AA..AB. So by initialising to 99999, we force it to rollover to AAAAA on the first IncrementUID call.
* Kind of silly, but I like how it looks.
* -- w
*/
- if (!inited)
- {
- inited = true;
- current_uid[0] = Config->sid[0];
- current_uid[1] = Config->sid[1];
- current_uid[2] = Config->sid[2];
- for (int i = 3; i < (UUID_LENGTH - 1); i++)
- current_uid[i] = '9';
-
- // Null terminator. Important.
- current_uid[UUID_LENGTH - 1] = '\0';
- }
+ current_uid.resize(UUID_LENGTH, '9');
+ current_uid[0] = sid[0];
+ current_uid[1] = sid[1];
+ current_uid[2] = sid[2];
+}
+/*
+ * Retrieve the next valid UUID that is free for this server.
+ */
+std::string UIDGenerator::GetUID()
+{
while (1)
{
// Add one to the last UID
- this->IncrementUID(UUID_LENGTH - 2);
+ this->IncrementUID(UUID_LENGTH - 1);
- if (this->FindUUID(current_uid))
- {
- /*
- * It's in use. We need to try the loop again.
- */
- continue;
- }
+ if (!ServerInstance->FindUUID(current_uid))
+ break;
- return current_uid;
+ /*
+ * It's in use. We need to try the loop again.
+ */
}
- /* not reached. */
- return "";
+ return current_uid;
}
+void ISupportManager::Build()
+{
+ /**
+ * This is currently the neatest way we can build the initial ISUPPORT map. In
+ * the future we can use an initializer list here.
+ */
+ std::map<std::string, std::string> tokens;
+
+ tokens["AWAYLEN"] = ConvToStr(ServerInstance->Config->Limits.MaxAway);
+ tokens["CASEMAPPING"] = "rfc1459";
+ tokens["CHANMODES"] = ServerInstance->Modes->GiveModeList(MODETYPE_CHANNEL);
+ tokens["CHANNELLEN"] = ConvToStr(ServerInstance->Config->Limits.ChanMax);
+ tokens["CHANTYPES"] = "#";
+ tokens["ELIST"] = "MU";
+ tokens["KICKLEN"] = ConvToStr(ServerInstance->Config->Limits.MaxKick);
+ tokens["MAXBANS"] = "64"; // TODO: make this a config setting.
+ tokens["MAXCHANNELS"] = ConvToStr(ServerInstance->Config->MaxChans);
+ tokens["MAXTARGETS"] = ConvToStr(ServerInstance->Config->MaxTargets);
+ tokens["MODES"] = ConvToStr(ServerInstance->Config->Limits.MaxModes);
+ tokens["NETWORK"] = ServerInstance->Config->Network;
+ tokens["NICKLEN"] = ConvToStr(ServerInstance->Config->Limits.NickMax);
+ tokens["PREFIX"] = ServerInstance->Modes->BuildPrefixes();
+ tokens["STATUSMSG"] = ServerInstance->Modes->BuildPrefixes(false);
+ tokens["TOPICLEN"] = ConvToStr(ServerInstance->Config->Limits.MaxTopic);
+
+ tokens["FNC"] = tokens["VBANLIST"];
+
+ // Modules can add new tokens and also edit or remove existing tokens
+ FOREACH_MOD(On005Numeric, (tokens));
+
+ // EXTBAN is a special case as we need to sort it and prepend a comma.
+ std::map<std::string, std::string>::iterator extban = tokens.find("EXTBAN");
+ if (extban != tokens.end())
+ {
+ std::sort(extban->second.begin(), extban->second.end());
+ extban->second.insert(0, ",");
+ }
+
+ // Transform the map into a list of lines, ready to be sent to clients
+ std::string line;
+ unsigned int token_count = 0;
+ cachedlines.clear();
+
+ for (std::map<std::string, std::string>::const_iterator it = tokens.begin(); it != tokens.end(); ++it)
+ {
+ line.append(it->first);
+
+ // If this token has a value then append a '=' char after the name and then the value itself
+ if (!it->second.empty())
+ line.append(1, '=').append(it->second);
+ // Always append a space, even if it's the last token because all lines will be suffixed
+ line.push_back(' ');
+ token_count++;
+ if (token_count % 13 == 12 || it == --tokens.end())
+ {
+ // Reached maximum number of tokens for this line or the current token
+ // is the last one; finalize the line and store it for later use
+ line.append(":are supported by this server");
+ cachedlines.push_back(line);
+ line.clear();
+ }
+ }
+}
+
+void ISupportManager::SendTo(LocalUser* user)
+{
+ for (std::vector<std::string>::const_iterator i = cachedlines.begin(); i != cachedlines.end(); ++i)
+ user->WriteNumeric(RPL_ISUPPORT, *i);
+}
diff --git a/src/snomasks.cpp b/src/snomasks.cpp
index 4b9c9d86b..fd6a2709a 100644
--- a/src/snomasks.cpp
+++ b/src/snomasks.cpp
@@ -21,7 +21,6 @@
#include "inspircd.h"
-#include <stdarg.h>
void SnomaskManager::FlushSnotices()
{
@@ -47,31 +46,21 @@ void SnomaskManager::WriteGlobalSno(char letter, const std::string& text)
{
WriteToSnoMask(letter, text);
letter = toupper(letter);
- ServerInstance->PI->SendSNONotice(std::string(1, letter), text);
+ ServerInstance->PI->SendSNONotice(letter, text);
}
void SnomaskManager::WriteToSnoMask(char letter, const char* text, ...)
{
- char textbuffer[MAXBUF];
- va_list argsPtr;
-
- va_start(argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
-
- this->WriteToSnoMask(letter, std::string(textbuffer));
+ std::string textbuffer;
+ VAFORMAT(textbuffer, text, text);
+ this->WriteToSnoMask(letter, textbuffer);
}
void SnomaskManager::WriteGlobalSno(char letter, const char* text, ...)
{
- char textbuffer[MAXBUF];
- va_list argsPtr;
-
- va_start(argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
-
- this->WriteGlobalSno(letter, std::string(textbuffer));
+ std::string textbuffer;
+ VAFORMAT(textbuffer, text, text);
+ this->WriteGlobalSno(letter, textbuffer);
}
SnomaskManager::SnomaskManager()
@@ -79,54 +68,42 @@ SnomaskManager::SnomaskManager()
EnableSnomask('c',"CONNECT"); /* Local connect notices */
EnableSnomask('q',"QUIT"); /* Local quit notices */
EnableSnomask('k',"KILL"); /* Kill notices */
- EnableSnomask('l',"LINK"); /* Linking notices */
EnableSnomask('o',"OPER"); /* Oper up/down notices */
EnableSnomask('a',"ANNOUNCEMENT"); /* formerly WriteOpers() - generic notices to all opers */
EnableSnomask('d',"DEBUG"); /* Debug notices */
EnableSnomask('x',"XLINE"); /* Xline notice (g/z/q/k/e) */
EnableSnomask('t',"STATS"); /* Local or remote stats request */
- EnableSnomask('f',"FLOOD"); /* Flooding notices */
}
-/*************************************************************************************/
+bool SnomaskManager::IsSnomaskUsable(char ch) const
+{
+ return ((isalpha(ch)) && (!masks[tolower(ch) - 'a'].Description.empty()));
+}
-void Snomask::SendMessage(const std::string &message, char mysnomask)
+Snomask::Snomask()
+ : Count(0)
{
- if (ServerInstance->Config->NoSnoticeStack || message != LastMessage || mysnomask != LastLetter)
+}
+
+void Snomask::SendMessage(const std::string& message, char letter)
+{
+ if ((!ServerInstance->Config->NoSnoticeStack) && (message == LastMessage) && (letter == LastLetter))
{
- this->Flush();
- LastMessage = message;
- LastLetter = mysnomask;
-
- std::string desc = Description;
- if (desc.empty())
- desc = std::string("SNO-") + (char)tolower(mysnomask);
- if (isupper(mysnomask))
- desc = "REMOTE" + desc;
- ModResult MOD_RESULT;
- ServerInstance->Logs->Log("snomask", DEFAULT, "%s: %s", desc.c_str(), message.c_str());
-
- FIRST_MOD_RESULT(OnSendSnotice, MOD_RESULT, (mysnomask, desc, message));
-
- LastBlocked = (MOD_RESULT == MOD_RES_DENY);
-
- if (!LastBlocked)
- {
- /* Only opers can receive snotices, so we iterate the oper list */
- std::list<User*>::iterator i = ServerInstance->Users->all_opers.begin();
-
- while (i != ServerInstance->Users->all_opers.end())
- {
- User* a = *i;
- if (IS_LOCAL(a) && a->IsModeSet('s') && a->IsNoticeMaskSet(mysnomask) && !a->quitting)
- {
- a->WriteServ("NOTICE %s :*** %s: %s", a->nick.c_str(), desc.c_str(), message.c_str());
- }
-
- i++;
- }
- }
+ Count++;
+ return;
}
+
+ this->Flush();
+
+ std::string desc = GetDescription(letter);
+ ModResult MOD_RESULT;
+ FIRST_MOD_RESULT(OnSendSnotice, MOD_RESULT, (letter, desc, message));
+ if (MOD_RESULT == MOD_RES_DENY)
+ return;
+
+ Snomask::Send(letter, desc, message);
+ LastMessage = message;
+ LastLetter = letter;
Count++;
}
@@ -134,36 +111,44 @@ void Snomask::Flush()
{
if (Count > 1)
{
- std::string desc = Description;
- if (desc.empty())
- desc = std::string("SNO-") + (char)tolower(LastLetter);
- if (isupper(LastLetter))
- desc = "REMOTE" + desc;
- std::string mesg = "(last message repeated "+ConvToStr(Count)+" times)";
-
- ServerInstance->Logs->Log("snomask", DEFAULT, "%s: %s", desc.c_str(), mesg.c_str());
-
- FOREACH_MOD(I_OnSendSnotice, OnSendSnotice(LastLetter, desc, mesg));
-
- if (!LastBlocked)
- {
- /* Only opers can receive snotices, so we iterate the oper list */
- std::list<User*>::iterator i = ServerInstance->Users->all_opers.begin();
-
- while (i != ServerInstance->Users->all_opers.end())
- {
- User* a = *i;
- if (IS_LOCAL(a) && a->IsModeSet('s') && a->IsNoticeMaskSet(LastLetter) && !a->quitting)
- {
- a->WriteServ("NOTICE %s :*** %s: %s", a->nick.c_str(), desc.c_str(), mesg.c_str());
- }
-
- i++;
- }
- }
+ std::string desc = GetDescription(LastLetter);
+ std::string msg = "(last message repeated " + ConvToStr(Count) + " times)";
+ FOREACH_MOD(OnSendSnotice, (LastLetter, desc, msg));
+ Snomask::Send(LastLetter, desc, msg);
}
+
LastMessage.clear();
- LastBlocked = false;
Count = 0;
}
+
+void Snomask::Send(char letter, const std::string& desc, const std::string& msg)
+{
+ std::string log = desc;
+ log.append(": ").append(msg);
+ ServerInstance->Logs->Log("snomask", LOG_DEFAULT, log);
+
+ std::string finalmsg = "*** ";
+ finalmsg.append(log);
+ /* Only opers can receive snotices, so we iterate the oper list */
+ const UserManager::OperList& opers = ServerInstance->Users->all_opers;
+ for (UserManager::OperList::const_iterator i = opers.begin(); i != opers.end(); ++i)
+ {
+ User* user = *i;
+ // IsNoticeMaskSet() returns false for opers who aren't +s, no need to check for it seperately
+ if (IS_LOCAL(user) && user->IsNoticeMaskSet(letter))
+ user->WriteNotice(finalmsg);
+ }
+}
+
+std::string Snomask::GetDescription(char letter) const
+{
+ std::string ret;
+ if (isupper(letter))
+ ret = "REMOTE";
+ if (!Description.empty())
+ ret += Description;
+ else
+ ret += std::string("SNO-") + (char)tolower(letter);
+ return ret;
+}
diff --git a/src/socket.cpp b/src/socket.cpp
index e73d01af9..89c9969ff 100644
--- a/src/socket.cpp
+++ b/src/socket.cpp
@@ -22,8 +22,7 @@
#include "inspircd.h"
-#include "socket.h"
-#include "socketengine.h"
+
using irc::sockets::sockaddrs;
/** This will bind a socket to a port. It works for UDP/TCP.
@@ -46,7 +45,7 @@ bool InspIRCd::BindSocket(int sockfd, int port, const char* addr, bool dolisten)
else if (!irc::sockets::aptosa(addr, port, servaddr))
return false;
- ret = SE->Bind(sockfd, servaddr);
+ ret = SocketEngine::Bind(sockfd, servaddr);
if (ret < 0)
{
@@ -56,21 +55,21 @@ bool InspIRCd::BindSocket(int sockfd, int port, const char* addr, bool dolisten)
{
if (dolisten)
{
- if (SE->Listen(sockfd, Config->MaxConn) == -1)
+ if (SocketEngine::Listen(sockfd, Config->MaxConn) == -1)
{
- this->Logs->Log("SOCKET",DEFAULT,"ERROR in listen(): %s",strerror(errno));
+ this->Logs->Log("SOCKET", LOG_DEFAULT, "ERROR in listen(): %s",strerror(errno));
return false;
}
else
{
- this->Logs->Log("SOCKET",DEBUG,"New socket binding for %d with listen: %s:%d", sockfd, addr, port);
- SE->NonBlocking(sockfd);
+ this->Logs->Log("SOCKET", LOG_DEBUG, "New socket binding for %d with listen: %s:%d", sockfd, addr, port);
+ SocketEngine::NonBlocking(sockfd);
return true;
}
}
else
{
- this->Logs->Log("SOCKET",DEBUG,"New socket binding for %d without listen: %s:%d", sockfd, addr, port);
+ this->Logs->Log("SOCKET", LOG_DEBUG, "New socket binding for %d without listen: %s:%d", sockfd, addr, port);
return true;
}
}
@@ -89,7 +88,7 @@ int InspIRCd::BindPorts(FailedPortList &failed_ports)
std::string Addr = tag->getString("address");
if (strncasecmp(Addr.c_str(), "::ffff:", 7) == 0)
- this->Logs->Log("SOCKET",DEFAULT, "Using 4in6 (::ffff:) isn't recommended. You should bind IPv4 addresses directly instead.");
+ this->Logs->Log("SOCKET", LOG_DEFAULT, "Using 4in6 (::ffff:) isn't recommended. You should bind IPv4 addresses directly instead.");
irc::portparser portrange(porttag, false);
int portno = -1;
@@ -106,6 +105,8 @@ int InspIRCd::BindPorts(FailedPortList &failed_ports)
if ((**n).bind_desc == bind_readable)
{
(*n)->bind_tag = tag; // Replace tag, we know addr and port match, but other info (type, ssl) may not
+ (*n)->ResetIOHookProvider();
+
skip = true;
old_ports.erase(n);
break;
@@ -136,11 +137,11 @@ int InspIRCd::BindPorts(FailedPortList &failed_ports)
n++;
if (n == ports.end())
{
- this->Logs->Log("SOCKET",DEFAULT,"Port bindings slipped out of vector, aborting close!");
+ this->Logs->Log("SOCKET", LOG_DEFAULT, "Port bindings slipped out of vector, aborting close!");
break;
}
- this->Logs->Log("SOCKET",DEFAULT, "Port binding %s was removed from the config file, closing.",
+ this->Logs->Log("SOCKET", LOG_DEFAULT, "Port binding %s was removed from the config file, closing.",
(**n).bind_desc.c_str());
delete *n;
@@ -219,24 +220,22 @@ bool irc::sockets::satoap(const irc::sockets::sockaddrs& sa, std::string& addr,
std::string irc::sockets::sockaddrs::str() const
{
- char buffer[MAXBUF];
if (sa.sa_family == AF_INET)
{
- const uint8_t* bits = reinterpret_cast<const uint8_t*>(&in4.sin_addr);
- sprintf(buffer, "%d.%d.%d.%d:%u", bits[0], bits[1], bits[2], bits[3], ntohs(in4.sin_port));
+ char ipaddr[INET_ADDRSTRLEN];
+ inet_ntop(AF_INET, &in4.sin_addr, ipaddr, sizeof(ipaddr));
+ return InspIRCd::Format("%s:%u", ipaddr, ntohs(in4.sin_port));
}
- else if (sa.sa_family == AF_INET6)
+
+ if (sa.sa_family == AF_INET6)
{
- buffer[0] = '[';
- if (!inet_ntop(AF_INET6, &in6.sin6_addr, buffer+1, MAXBUF - 10))
- return "<unknown>"; // should never happen, buffer is large enough
- int len = strlen(buffer);
- // no need for snprintf, buffer has at least 9 chars left, max short len = 5
- sprintf(buffer + len, "]:%u", ntohs(in6.sin6_port));
+ char ipaddr[INET6_ADDRSTRLEN];
+ inet_ntop(AF_INET6, &in6.sin6_addr, ipaddr, sizeof(ipaddr));
+ return InspIRCd::Format("[%s]:%u", ipaddr, ntohs(in6.sin6_port));
}
- else
- return "<unknown>";
- return std::string(buffer);
+
+ // This should never happen.
+ return "<unknown>";
}
int irc::sockets::sockaddrs::sa_size() const
@@ -367,4 +366,3 @@ bool irc::sockets::cidr_mask::match(const irc::sockets::sockaddrs& addr) const
irc::sockets::cidr_mask tmp(addr, length);
return tmp == *this;
}
-
diff --git a/src/socketengine.cpp b/src/socketengine.cpp
index 4a9a2ef10..1c91ccdea 100644
--- a/src/socketengine.cpp
+++ b/src/socketengine.cpp
@@ -23,6 +23,25 @@
#include "inspircd.h"
+
+/** Reference table, contains all current handlers
+ **/
+std::vector<EventHandler*> SocketEngine::ref;
+
+/** Current number of descriptors in the engine
+ */
+size_t SocketEngine::CurrentSetSize = 0;
+
+/** List of handlers that want a trial read/write
+ */
+std::set<int> SocketEngine::trials;
+
+int SocketEngine::MAX_DESCRIPTORS;
+
+/** Socket engine statistics: count of various events, bandwidth usage
+ */
+SocketEngine::Statistics SocketEngine::stats;
+
EventHandler::EventHandler()
{
fd = -1;
@@ -34,22 +53,6 @@ void EventHandler::SetFd(int FD)
this->fd = FD;
}
-SocketEngine::SocketEngine()
-{
- TotalEvents = WriteEvents = ReadEvents = ErrorEvents = 0;
- lastempty = ServerInstance->Time();
- indata = outdata = 0;
-}
-
-SocketEngine::~SocketEngine()
-{
-}
-
-void SocketEngine::SetEventMask(EventHandler* eh, int mask)
-{
- eh->event_mask = mask;
-}
-
void SocketEngine::ChangeEventMask(EventHandler* eh, int change)
{
int old_m = eh->event_mask;
@@ -60,7 +63,7 @@ void SocketEngine::ChangeEventMask(EventHandler* eh, int change)
new_m &= ~FD_WANT_READ_MASK;
if (change & FD_WANT_WRITE_MASK)
new_m &= ~FD_WANT_WRITE_MASK;
-
+
// if adding a trial read/write, insert it into the set
if (change & FD_TRIAL_NOTE_MASK && !(old_m & FD_TRIAL_NOTE_MASK))
trials.insert(eh->GetFd());
@@ -94,17 +97,38 @@ void SocketEngine::DispatchTrialWrites()
}
}
-bool SocketEngine::HasFd(int fd)
+bool SocketEngine::AddFdRef(EventHandler* eh)
{
- if ((fd < 0) || (fd > GetMaxFds()))
+ int fd = eh->GetFd();
+ if (HasFd(fd))
return false;
- return (ref[fd] != NULL);
+
+ while (static_cast<unsigned int>(fd) >= ref.size())
+ ref.resize(ref.empty() ? 1 : (ref.size() * 2));
+ ref[fd] = eh;
+ CurrentSetSize++;
+ return true;
+}
+
+void SocketEngine::DelFdRef(EventHandler *eh)
+{
+ int fd = eh->GetFd();
+ if (GetRef(fd) == eh)
+ {
+ ref[fd] = NULL;
+ CurrentSetSize--;
+ }
+}
+
+bool SocketEngine::HasFd(int fd)
+{
+ return GetRef(fd) != NULL;
}
EventHandler* SocketEngine::GetRef(int fd)
{
- if ((fd < 0) || (fd > GetMaxFds()))
- return 0;
+ if (fd < 0 || static_cast<unsigned int>(fd) >= ref.size())
+ return NULL;
return ref[fd];
}
@@ -112,7 +136,7 @@ bool SocketEngine::BoundsCheckFd(EventHandler* eh)
{
if (!eh)
return false;
- if ((eh->GetFd() < 0) || (eh->GetFd() > GetMaxFds()))
+ if (eh->GetFd() < 0)
return false;
return true;
}
@@ -123,13 +147,12 @@ int SocketEngine::Accept(EventHandler* fd, sockaddr *addr, socklen_t *addrlen)
return accept(fd->GetFd(), addr, addrlen);
}
-int SocketEngine::Close(EventHandler* fd)
+int SocketEngine::Close(EventHandler* eh)
{
-#ifdef _WIN32
- return closesocket(fd->GetFd());
-#else
- return close(fd->GetFd());
-#endif
+ DelFd(eh);
+ int ret = Close(eh->GetFd());
+ eh->SetFd(-1);
+ return ret;
}
int SocketEngine::Close(int fd)
@@ -173,7 +196,7 @@ int SocketEngine::RecvFrom(EventHandler* fd, void *buf, size_t len, int flags, s
{
int nbRecvd = recvfrom(fd->GetFd(), (char*)buf, len, flags, from, fromlen);
if (nbRecvd > 0)
- this->UpdateStats(nbRecvd, 0);
+ stats.Update(nbRecvd, 0);
return nbRecvd;
}
@@ -181,7 +204,7 @@ int SocketEngine::Send(EventHandler* fd, const void *buf, size_t len, int flags)
{
int nbSent = send(fd->GetFd(), (const char*)buf, len, flags);
if (nbSent > 0)
- this->UpdateStats(0, nbSent);
+ stats.Update(0, nbSent);
return nbSent;
}
@@ -189,7 +212,7 @@ int SocketEngine::Recv(EventHandler* fd, void *buf, size_t len, int flags)
{
int nbRecvd = recv(fd->GetFd(), (char*)buf, len, flags);
if (nbRecvd > 0)
- this->UpdateStats(nbRecvd, 0);
+ stats.Update(nbRecvd, 0);
return nbRecvd;
}
@@ -197,7 +220,7 @@ int SocketEngine::SendTo(EventHandler* fd, const void *buf, size_t len, int flag
{
int nbSent = sendto(fd->GetFd(), (const char*)buf, len, flags, to, tolen);
if (nbSent > 0)
- this->UpdateStats(0, nbSent);
+ stats.Update(0, nbSent);
return nbSent;
}
@@ -231,24 +254,27 @@ int SocketEngine::Shutdown(int fd, int how)
return shutdown(fd, how);
}
-void SocketEngine::RecoverFromFork()
+void SocketEngine::Statistics::Update(size_t len_in, size_t len_out)
{
+ CheckFlush();
+ indata += len_in;
+ outdata += len_out;
}
-void SocketEngine::UpdateStats(size_t len_in, size_t len_out)
+void SocketEngine::Statistics::CheckFlush() const
{
- if (lastempty != ServerInstance->Time())
+ // Reset the in/out byte counters if it has been more than a second
+ time_t now = ServerInstance->Time();
+ if (lastempty != now)
{
- lastempty = ServerInstance->Time();
+ lastempty = now;
indata = outdata = 0;
}
- indata += len_in;
- outdata += len_out;
}
-void SocketEngine::GetStats(float &kbitpersec_in, float &kbitpersec_out, float &kbitpersec_total)
+void SocketEngine::Statistics::GetBandwidth(float& kbitpersec_in, float& kbitpersec_out, float& kbitpersec_total) const
{
- UpdateStats(0, 0); /* Forces emptying of the values if its been more than a second */
+ CheckFlush();
float in_kbit = indata * 8;
float out_kbit = outdata * 8;
kbitpersec_total = ((in_kbit + out_kbit) / 1024);
diff --git a/src/socketengines/socketengine_epoll.cpp b/src/socketengines/socketengine_epoll.cpp
index f2837777a..29404f416 100644
--- a/src/socketengines/socketengine_epoll.cpp
+++ b/src/socketengines/socketengine_epoll.cpp
@@ -18,12 +18,9 @@
*/
-#include <vector>
-#include <string>
-#include <map>
#include "inspircd.h"
#include "exitcodes.h"
-#include "socketengine.h"
+
#include <sys/epoll.h>
#include <ulimit.h>
#include <iostream>
@@ -31,65 +28,41 @@
/** A specialisation of the SocketEngine class, designed to use linux 2.6 epoll().
*/
-class EPollEngine : public SocketEngine
+namespace
{
-private:
- /** These are used by epoll() to hold socket events
- */
- struct epoll_event* events;
int EngineHandle;
-public:
- /** Create a new EPollEngine
- */
- EPollEngine();
- /** Delete an EPollEngine
+
+ /** These are used by epoll() to hold socket events
*/
- virtual ~EPollEngine();
- virtual bool AddFd(EventHandler* eh, int event_mask);
- virtual void OnSetEvent(EventHandler* eh, int old_mask, int new_mask);
- virtual void DelFd(EventHandler* eh);
- virtual int DispatchEvents();
- virtual std::string GetName();
-};
+ std::vector<struct epoll_event> events(1);
+}
-EPollEngine::EPollEngine()
+void SocketEngine::Init()
{
- CurrentSetSize = 0;
- int max = ulimit(4, 0);
- if (max > 0)
- {
- MAX_DESCRIPTORS = max;
- }
- else
- {
- ServerInstance->Logs->Log("SOCKET", DEFAULT, "ERROR: Can't determine maximum number of open sockets!");
- std::cout << "ERROR: Can't determine maximum number of open sockets!" << std::endl;
- ServerInstance->QuickExit(EXIT_STATUS_SOCKETENGINE);
- }
+ // MAX_DESCRIPTORS is mainly used for display purposes, no problem if ulimit() fails and returns a negative number
+ MAX_DESCRIPTORS = ulimit(4, 0);
- // This is not a maximum, just a hint at the eventual number of sockets that may be polled.
- EngineHandle = epoll_create(GetMaxFds() / 4);
+ // 128 is not a maximum, just a hint at the eventual number of sockets that may be polled,
+ // and it is completely ignored by 2.6.8 and later kernels, except it must be larger than zero.
+ EngineHandle = epoll_create(128);
if (EngineHandle == -1)
{
- ServerInstance->Logs->Log("SOCKET",DEFAULT, "ERROR: Could not initialize socket engine: %s", strerror(errno));
- ServerInstance->Logs->Log("SOCKET",DEFAULT, "ERROR: Your kernel probably does not have the proper features. This is a fatal error, exiting now.");
+ ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "ERROR: Could not initialize socket engine: %s", strerror(errno));
+ ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "ERROR: Your kernel probably does not have the proper features. This is a fatal error, exiting now.");
std::cout << "ERROR: Could not initialize epoll socket engine: " << strerror(errno) << std::endl;
std::cout << "ERROR: Your kernel probably does not have the proper features. This is a fatal error, exiting now." << std::endl;
ServerInstance->QuickExit(EXIT_STATUS_SOCKETENGINE);
}
+}
- ref = new EventHandler* [GetMaxFds()];
- events = new struct epoll_event[GetMaxFds()];
-
- memset(ref, 0, GetMaxFds() * sizeof(EventHandler*));
+void SocketEngine::RecoverFromFork()
+{
}
-EPollEngine::~EPollEngine()
+void SocketEngine::Deinit()
{
- this->Close(EngineHandle);
- delete[] ref;
- delete[] events;
+ Close(EngineHandle);
}
static unsigned mask_to_epoll(int event_mask)
@@ -115,41 +88,41 @@ static unsigned mask_to_epoll(int event_mask)
return rv;
}
-bool EPollEngine::AddFd(EventHandler* eh, int event_mask)
+bool SocketEngine::AddFd(EventHandler* eh, int event_mask)
{
int fd = eh->GetFd();
- if ((fd < 0) || (fd > GetMaxFds() - 1))
+ if (fd < 0)
{
- ServerInstance->Logs->Log("SOCKET",DEBUG,"AddFd out of range: (fd: %d, max: %d)", fd, GetMaxFds());
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "AddFd out of range: (fd: %d)", fd);
return false;
}
- if (ref[fd])
+ if (!SocketEngine::AddFdRef(eh))
{
- ServerInstance->Logs->Log("SOCKET",DEBUG,"Attempt to add duplicate fd: %d", fd);
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Attempt to add duplicate fd: %d", fd);
return false;
}
struct epoll_event ev;
- memset(&ev,0,sizeof(ev));
+ memset(&ev, 0, sizeof(ev));
ev.events = mask_to_epoll(event_mask);
- ev.data.fd = fd;
+ ev.data.ptr = static_cast<void*>(eh);
int i = epoll_ctl(EngineHandle, EPOLL_CTL_ADD, fd, &ev);
if (i < 0)
{
- ServerInstance->Logs->Log("SOCKET",DEBUG,"Error adding fd: %d to socketengine: %s", fd, strerror(errno));
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Error adding fd: %d to socketengine: %s", fd, strerror(errno));
return false;
}
- ServerInstance->Logs->Log("SOCKET",DEBUG,"New file descriptor: %d", fd);
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "New file descriptor: %d", fd);
+
+ eh->SetEventMask(event_mask);
+ ResizeDouble(events);
- ref[fd] = eh;
- SocketEngine::SetEventMask(eh, event_mask);
- CurrentSetSize++;
return true;
}
-void EPollEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask)
+void SocketEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask)
{
unsigned old_events = mask_to_epoll(old_mask);
unsigned new_events = mask_to_epoll(new_mask);
@@ -157,75 +130,78 @@ void EPollEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask)
{
// ok, we actually have something to tell the kernel about
struct epoll_event ev;
- memset(&ev,0,sizeof(ev));
+ memset(&ev, 0, sizeof(ev));
ev.events = new_events;
- ev.data.fd = eh->GetFd();
+ ev.data.ptr = static_cast<void*>(eh);
epoll_ctl(EngineHandle, EPOLL_CTL_MOD, eh->GetFd(), &ev);
}
}
-void EPollEngine::DelFd(EventHandler* eh)
+void SocketEngine::DelFd(EventHandler* eh)
{
int fd = eh->GetFd();
- if ((fd < 0) || (fd > GetMaxFds() - 1))
+ if (fd < 0)
{
- ServerInstance->Logs->Log("SOCKET",DEBUG,"DelFd out of range: (fd: %d, max: %d)", fd, GetMaxFds());
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "DelFd out of range: (fd: %d)", fd);
return;
}
+ // Do not initialize epoll_event because for EPOLL_CTL_DEL operations the event is ignored and can be NULL.
+ // In kernel versions before 2.6.9, the EPOLL_CTL_DEL operation required a non-NULL pointer in event,
+ // even though this argument is ignored. Since Linux 2.6.9, event can be specified as NULL when using EPOLL_CTL_DEL.
struct epoll_event ev;
- memset(&ev,0,sizeof(ev));
- ev.data.fd = fd;
int i = epoll_ctl(EngineHandle, EPOLL_CTL_DEL, fd, &ev);
if (i < 0)
{
- ServerInstance->Logs->Log("SOCKET",DEBUG,"epoll_ctl can't remove socket: %s", strerror(errno));
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "epoll_ctl can't remove socket: %s", strerror(errno));
}
- ref[fd] = NULL;
+ SocketEngine::DelFdRef(eh);
- ServerInstance->Logs->Log("SOCKET",DEBUG,"Remove file descriptor: %d", fd);
- CurrentSetSize--;
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Remove file descriptor: %d", fd);
}
-int EPollEngine::DispatchEvents()
+int SocketEngine::DispatchEvents()
{
- socklen_t codesize = sizeof(int);
- int errcode;
- int i = epoll_wait(EngineHandle, events, GetMaxFds() - 1, 1000);
+ int i = epoll_wait(EngineHandle, &events[0], events.size(), 1000);
ServerInstance->UpdateTime();
- TotalEvents += i;
+ stats.TotalEvents += i;
for (int j = 0; j < i; j++)
{
- EventHandler* eh = ref[events[j].data.fd];
- if (!eh)
- {
- ServerInstance->Logs->Log("SOCKET",DEBUG,"Got event on unknown fd: %d", events[j].data.fd);
- epoll_ctl(EngineHandle, EPOLL_CTL_DEL, events[j].data.fd, &events[j]);
+ // Copy these in case the vector gets resized and ev invalidated
+ const epoll_event ev = events[j];
+
+ EventHandler* const eh = static_cast<EventHandler*>(ev.data.ptr);
+ const int fd = eh->GetFd();
+ if (fd < 0)
continue;
- }
- if (events[j].events & EPOLLHUP)
+
+ if (ev.events & EPOLLHUP)
{
- ErrorEvents++;
+ stats.ErrorEvents++;
eh->HandleEvent(EVENT_ERROR, 0);
continue;
}
- if (events[j].events & EPOLLERR)
+
+ if (ev.events & EPOLLERR)
{
- ErrorEvents++;
+ stats.ErrorEvents++;
/* Get error number */
- if (getsockopt(events[j].data.fd, SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0)
+ socklen_t codesize = sizeof(int);
+ int errcode;
+ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0)
errcode = errno;
eh->HandleEvent(EVENT_ERROR, errcode);
continue;
}
+
int mask = eh->GetEventMask();
- if (events[j].events & EPOLLIN)
+ if (ev.events & EPOLLIN)
mask &= ~FD_READ_WILL_BLOCK;
- if (events[j].events & EPOLLOUT)
+ if (ev.events & EPOLLOUT)
{
mask &= ~FD_WRITE_WILL_BLOCK;
if (mask & FD_WANT_SINGLE_WRITE)
@@ -235,31 +211,21 @@ int EPollEngine::DispatchEvents()
mask = nm;
}
}
- SetEventMask(eh, mask);
- if (events[j].events & EPOLLIN)
+ eh->SetEventMask(mask);
+ if (ev.events & EPOLLIN)
{
- ReadEvents++;
+ stats.ReadEvents++;
eh->HandleEvent(EVENT_READ);
- if (eh != ref[events[j].data.fd])
+ if (eh != GetRef(fd))
// whoa! we got deleted, better not give out the write event
continue;
}
- if (events[j].events & EPOLLOUT)
+ if (ev.events & EPOLLOUT)
{
- WriteEvents++;
+ stats.WriteEvents++;
eh->HandleEvent(EVENT_WRITE);
}
}
return i;
}
-
-std::string EPollEngine::GetName()
-{
- return "epoll";
-}
-
-SocketEngine* CreateSocketEngine()
-{
- return new EPollEngine;
-}
diff --git a/src/socketengines/socketengine_kqueue.cpp b/src/socketengines/socketengine_kqueue.cpp
index 8694a0bdd..8cc8a33f9 100644
--- a/src/socketengines/socketengine_kqueue.cpp
+++ b/src/socketengines/socketengine_kqueue.cpp
@@ -24,39 +24,27 @@
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
-#include "socketengine.h"
#include <iostream>
+#include <sys/sysctl.h>
/** A specialisation of the SocketEngine class, designed to use BSD kqueue().
*/
-class KQueueEngine : public SocketEngine
+namespace
{
-private:
int EngineHandle;
+ unsigned int ChangePos = 0;
/** These are used by kqueue() to hold socket events
*/
- struct kevent* ke_list;
- /** This is a specialised time value used by kqueue()
- */
- struct timespec ts;
-public:
- /** Create a new KQueueEngine
- */
- KQueueEngine();
- /** Delete a KQueueEngine
- */
- virtual ~KQueueEngine();
- bool AddFd(EventHandler* eh, int event_mask);
- void OnSetEvent(EventHandler* eh, int old_mask, int new_mask);
- virtual void DelFd(EventHandler* eh);
- virtual int DispatchEvents();
- virtual std::string GetName();
- virtual void RecoverFromFork();
-};
+ std::vector<struct kevent> ke_list(16);
-#include <sys/sysctl.h>
+ /** Pending changes
+ */
+ std::vector<struct kevent> changelist(8);
+}
-KQueueEngine::KQueueEngine()
+/** Initialize the kqueue engine
+ */
+void SocketEngine::Init()
{
MAX_DESCRIPTORS = 0;
int mib[2];
@@ -69,21 +57,13 @@ KQueueEngine::KQueueEngine()
mib[1] = KERN_MAXFILES;
#endif
len = sizeof(MAX_DESCRIPTORS);
+ // MAX_DESCRIPTORS is mainly used for display purposes, no problem if the sysctl() below fails
sysctl(mib, 2, &MAX_DESCRIPTORS, &len, NULL, 0);
- if (MAX_DESCRIPTORS <= 0)
- {
- ServerInstance->Logs->Log("SOCKET", DEFAULT, "ERROR: Can't determine maximum number of open sockets!");
- std::cout << "ERROR: Can't determine maximum number of open sockets!" << std::endl;
- ServerInstance->QuickExit(EXIT_STATUS_SOCKETENGINE);
- }
- this->RecoverFromFork();
- ke_list = new struct kevent[GetMaxFds()];
- ref = new EventHandler* [GetMaxFds()];
- memset(ref, 0, GetMaxFds() * sizeof(EventHandler*));
+ RecoverFromFork();
}
-void KQueueEngine::RecoverFromFork()
+void SocketEngine::RecoverFromFork()
{
/*
* The only bad thing about kqueue is that its fd cant survive a fork and is not inherited.
@@ -93,176 +73,148 @@ void KQueueEngine::RecoverFromFork()
EngineHandle = kqueue();
if (EngineHandle == -1)
{
- ServerInstance->Logs->Log("SOCKET",DEFAULT, "ERROR: Could not initialize socket engine. Your kernel probably does not have the proper features.");
- ServerInstance->Logs->Log("SOCKET",DEFAULT, "ERROR: this is a fatal error, exiting now.");
+ ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "ERROR: Could not initialize socket engine. Your kernel probably does not have the proper features.");
+ ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "ERROR: this is a fatal error, exiting now.");
std::cout << "ERROR: Could not initialize socket engine. Your kernel probably does not have the proper features." << std::endl;
std::cout << "ERROR: this is a fatal error, exiting now." << std::endl;
ServerInstance->QuickExit(EXIT_STATUS_SOCKETENGINE);
}
- CurrentSetSize = 0;
}
-KQueueEngine::~KQueueEngine()
+/** Shutdown the kqueue engine
+ */
+void SocketEngine::Deinit()
{
- this->Close(EngineHandle);
- delete[] ref;
- delete[] ke_list;
+ Close(EngineHandle);
}
-bool KQueueEngine::AddFd(EventHandler* eh, int event_mask)
+static struct kevent* GetChangeKE()
+{
+ if (ChangePos >= changelist.size())
+ changelist.resize(changelist.size() * 2);
+ return &changelist[ChangePos++];
+}
+
+bool SocketEngine::AddFd(EventHandler* eh, int event_mask)
{
int fd = eh->GetFd();
- if ((fd < 0) || (fd > GetMaxFds() - 1))
+ if (fd < 0)
return false;
- if (ref[fd])
+ if (!SocketEngine::AddFdRef(eh))
return false;
// We always want to read from the socket...
- struct kevent ke;
- EV_SET(&ke, fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
+ struct kevent* ke = GetChangeKE();
+ EV_SET(ke, fd, EVFILT_READ, EV_ADD, 0, 0, static_cast<void*>(eh));
- int i = kevent(EngineHandle, &ke, 1, 0, 0, NULL);
- if (i == -1)
- {
- ServerInstance->Logs->Log("SOCKET",DEFAULT,"Failed to add fd: %d %s",
- fd, strerror(errno));
- return false;
- }
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "New file descriptor: %d", fd);
- ref[fd] = eh;
- SocketEngine::SetEventMask(eh, event_mask);
+ eh->SetEventMask(event_mask);
OnSetEvent(eh, 0, event_mask);
- CurrentSetSize++;
+ ResizeDouble(ke_list);
- ServerInstance->Logs->Log("SOCKET",DEBUG,"New file descriptor: %d", fd);
return true;
}
-void KQueueEngine::DelFd(EventHandler* eh)
+void SocketEngine::DelFd(EventHandler* eh)
{
int fd = eh->GetFd();
- if ((fd < 0) || (fd > GetMaxFds() - 1))
+ if (fd < 0)
{
- ServerInstance->Logs->Log("SOCKET",DEFAULT,"DelFd() on invalid fd: %d", fd);
+ ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "DelFd() on invalid fd: %d", fd);
return;
}
- struct kevent ke;
-
// First remove the write filter ignoring errors, since we can't be
// sure if there are actually any write filters registered.
- EV_SET(&ke, eh->GetFd(), EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
- kevent(EngineHandle, &ke, 1, 0, 0, NULL);
+ struct kevent* ke = GetChangeKE();
+ EV_SET(ke, eh->GetFd(), EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
// Then remove the read filter.
- EV_SET(&ke, eh->GetFd(), EVFILT_READ, EV_DELETE, 0, 0, NULL);
- int j = kevent(EngineHandle, &ke, 1, 0, 0, NULL);
+ ke = GetChangeKE();
+ EV_SET(ke, eh->GetFd(), EVFILT_READ, EV_DELETE, 0, 0, NULL);
- if (j < 0)
- {
- ServerInstance->Logs->Log("SOCKET",DEFAULT,"Failed to remove fd: %d %s",
- fd, strerror(errno));
- }
+ SocketEngine::DelFdRef(eh);
- CurrentSetSize--;
- ref[fd] = NULL;
-
- ServerInstance->Logs->Log("SOCKET",DEBUG,"Remove file descriptor: %d", fd);
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Remove file descriptor: %d", fd);
}
-void KQueueEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask)
+void SocketEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask)
{
if ((new_mask & FD_WANT_POLL_WRITE) && !(old_mask & FD_WANT_POLL_WRITE))
{
// new poll-style write
- struct kevent ke;
- EV_SET(&ke, eh->GetFd(), EVFILT_WRITE, EV_ADD, 0, 0, NULL);
- int i = kevent(EngineHandle, &ke, 1, 0, 0, NULL);
- if (i < 0) {
- ServerInstance->Logs->Log("SOCKET",DEFAULT,"Failed to mark for writing: %d %s",
- eh->GetFd(), strerror(errno));
- }
+ struct kevent* ke = GetChangeKE();
+ EV_SET(ke, eh->GetFd(), EVFILT_WRITE, EV_ADD, 0, 0, static_cast<void*>(eh));
}
else if ((old_mask & FD_WANT_POLL_WRITE) && !(new_mask & FD_WANT_POLL_WRITE))
{
// removing poll-style write
- struct kevent ke;
- EV_SET(&ke, eh->GetFd(), EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
- int i = kevent(EngineHandle, &ke, 1, 0, 0, NULL);
- if (i < 0) {
- ServerInstance->Logs->Log("SOCKET",DEFAULT,"Failed to mark for writing: %d %s",
- eh->GetFd(), strerror(errno));
- }
+ struct kevent* ke = GetChangeKE();
+ EV_SET(ke, eh->GetFd(), EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
}
if ((new_mask & (FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE)) && !(old_mask & (FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE)))
{
- // new one-shot write
- struct kevent ke;
- EV_SET(&ke, eh->GetFd(), EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, NULL);
- int i = kevent(EngineHandle, &ke, 1, 0, 0, NULL);
- if (i < 0) {
- ServerInstance->Logs->Log("SOCKET",DEFAULT,"Failed to mark for writing: %d %s",
- eh->GetFd(), strerror(errno));
- }
+ struct kevent* ke = GetChangeKE();
+ EV_SET(ke, eh->GetFd(), EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, static_cast<void*>(eh));
}
}
-int KQueueEngine::DispatchEvents()
+int SocketEngine::DispatchEvents()
{
+ struct timespec ts;
ts.tv_nsec = 0;
ts.tv_sec = 1;
- int i = kevent(EngineHandle, NULL, 0, &ke_list[0], GetMaxFds(), &ts);
+ int i = kevent(EngineHandle, &changelist.front(), ChangePos, &ke_list.front(), ke_list.size(), &ts);
+ ChangePos = 0;
ServerInstance->UpdateTime();
- TotalEvents += i;
+ if (i < 0)
+ return i;
+
+ stats.TotalEvents += i;
for (int j = 0; j < i; j++)
{
- EventHandler* eh = ref[ke_list[j].ident];
+ struct kevent& kev = ke_list[j];
+ EventHandler* eh = static_cast<EventHandler*>(kev.udata);
if (!eh)
continue;
- if (ke_list[j].flags & EV_EOF)
+
+ // Copy these in case the vector gets resized and kev invalidated
+ const int fd = eh->GetFd();
+ const short filter = kev.filter;
+ if (fd < 0)
+ continue;
+
+ if (kev.flags & EV_EOF)
{
- ErrorEvents++;
- eh->HandleEvent(EVENT_ERROR, ke_list[j].fflags);
+ stats.ErrorEvents++;
+ eh->HandleEvent(EVENT_ERROR, kev.fflags);
continue;
}
- if (ke_list[j].filter == EVFILT_WRITE)
+ if (filter == EVFILT_WRITE)
{
- WriteEvents++;
+ stats.WriteEvents++;
/* When mask is FD_WANT_FAST_WRITE or FD_WANT_SINGLE_WRITE,
* we set a one-shot write, so we need to clear that bit
* to detect when it set again.
*/
const int bits_to_clr = FD_WANT_SINGLE_WRITE | FD_WANT_FAST_WRITE | FD_WRITE_WILL_BLOCK;
- SetEventMask(eh, eh->GetEventMask() & ~bits_to_clr);
+ eh->SetEventMask(eh->GetEventMask() & ~bits_to_clr);
eh->HandleEvent(EVENT_WRITE);
-
- if (eh != ref[ke_list[j].ident])
- // whoops, deleted out from under us
- continue;
}
- if (ke_list[j].filter == EVFILT_READ)
+ else if (filter == EVFILT_READ)
{
- ReadEvents++;
- SetEventMask(eh, eh->GetEventMask() & ~FD_READ_WILL_BLOCK);
+ stats.ReadEvents++;
+ eh->SetEventMask(eh->GetEventMask() & ~FD_READ_WILL_BLOCK);
eh->HandleEvent(EVENT_READ);
}
}
return i;
}
-
-std::string KQueueEngine::GetName()
-{
- return "kqueue";
-}
-
-SocketEngine* CreateSocketEngine()
-{
- return new KQueueEngine;
-}
diff --git a/src/socketengines/socketengine_poll.cpp b/src/socketengines/socketengine_poll.cpp
index e38e0fac1..dc63fe0ed 100644
--- a/src/socketengines/socketengine_poll.cpp
+++ b/src/socketengines/socketengine_poll.cpp
@@ -1,6 +1,7 @@
/*
* InspIRCd -- Internet Relay Chat Daemon
*
+ * Copyright (C) 2014 Adam <Adam@anope.org>
* Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
* Copyright (C) 2009 Uli Schlachter <psychon@znc.in>
* Copyright (C) 2009 Craig Edwards <craigedwards@brainbox.cc>
@@ -20,65 +21,26 @@
*/
-#include "inspircd.h"
#include "exitcodes.h"
-
-#ifndef SOCKETENGINE_POLL
-#define SOCKETENGINE_POLL
-
-#include <iostream>
-#include <vector>
-#include <string>
-#include <map>
-#include "inspircd_config.h"
#include "inspircd.h"
-#include "socketengine.h"
-
-#ifndef _WIN32
-# ifndef __USE_XOPEN
-# define __USE_XOPEN /* fuck every fucking OS ever made. needed by poll.h to work.*/
-# endif
-# include <poll.h>
-# include <sys/poll.h>
-# include <sys/resource.h>
-#else
-# define struct pollfd WSAPOLLFD
-# define poll WSAPoll
-#endif
-
-class InspIRCd;
+
+#include <sys/poll.h>
+#include <sys/resource.h>
/** A specialisation of the SocketEngine class, designed to use poll().
*/
-class PollEngine : public SocketEngine
+namespace
{
-private:
/** These are used by poll() to hold socket events
*/
- struct pollfd *events;
- /** This map maps fds to an index in the events array.
- */
- std::map<int, unsigned int> fd_mappings;
-public:
- /** Create a new PollEngine
+ std::vector<struct pollfd> events(16);
+ /** This vector maps fds to an index in the events array.
*/
- PollEngine();
- /** Delete a PollEngine
- */
- virtual ~PollEngine();
- virtual bool AddFd(EventHandler* eh, int event_mask);
- virtual void OnSetEvent(EventHandler* eh, int old_mask, int new_mask);
- virtual EventHandler* GetRef(int fd);
- virtual void DelFd(EventHandler* eh);
- virtual int DispatchEvents();
- virtual std::string GetName();
-};
-
-#endif
-
-PollEngine::PollEngine()
+ std::vector<int> fd_mappings(16);
+}
+
+void SocketEngine::Init()
{
- CurrentSetSize = 0;
struct rlimit limits;
if (!getrlimit(RLIMIT_NOFILE, &limits))
{
@@ -86,23 +48,17 @@ PollEngine::PollEngine()
}
else
{
- ServerInstance->Logs->Log("SOCKET", DEFAULT, "ERROR: Can't determine maximum number of open sockets: %s", strerror(errno));
- std::cout << "ERROR: Can't determine maximum number of open sockets: " << strerror(errno) << std::endl;
- ServerInstance->QuickExit(EXIT_STATUS_SOCKETENGINE);
+ // MAX_DESCRIPTORS is mainly used for display purposes, it's not a problem that getrlimit() failed
+ MAX_DESCRIPTORS = -1;
}
+}
- ref = new EventHandler* [GetMaxFds()];
- events = new struct pollfd[GetMaxFds()];
-
- memset(events, 0, GetMaxFds() * sizeof(struct pollfd));
- memset(ref, 0, GetMaxFds() * sizeof(EventHandler*));
+void SocketEngine::Deinit()
+{
}
-PollEngine::~PollEngine()
+void SocketEngine::RecoverFromFork()
{
- // No destruction required, either.
- delete[] ref;
- delete[] events;
}
static int mask_to_poll(int event_mask)
@@ -115,71 +71,70 @@ static int mask_to_poll(int event_mask)
return rv;
}
-bool PollEngine::AddFd(EventHandler* eh, int event_mask)
+bool SocketEngine::AddFd(EventHandler* eh, int event_mask)
{
int fd = eh->GetFd();
- if ((fd < 0) || (fd > GetMaxFds() - 1))
+ if (fd < 0)
{
- ServerInstance->Logs->Log("SOCKET",DEBUG,"AddFd out of range: (fd: %d, max: %d)", fd, GetMaxFds());
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "AddFd out of range: (fd: %d)", fd);
return false;
}
- if (fd_mappings.find(fd) != fd_mappings.end())
+ if (static_cast<unsigned int>(fd) < fd_mappings.size() && fd_mappings[fd] != -1)
{
- ServerInstance->Logs->Log("SOCKET",DEBUG,"Attempt to add duplicate fd: %d", fd);
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Attempt to add duplicate fd: %d", fd);
return false;
}
unsigned int index = CurrentSetSize;
+ if (!SocketEngine::AddFdRef(eh))
+ {
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Attempt to add duplicate fd: %d", fd);
+ return false;
+ }
+
+ while (static_cast<unsigned int>(fd) >= fd_mappings.size())
+ fd_mappings.resize(fd_mappings.size() * 2, -1);
fd_mappings[fd] = index;
- ref[index] = eh;
+
+ ResizeDouble(events);
events[index].fd = fd;
events[index].events = mask_to_poll(event_mask);
- ServerInstance->Logs->Log("SOCKET", DEBUG,"New file descriptor: %d (%d; index %d)", fd, events[index].events, index);
- SocketEngine::SetEventMask(eh, event_mask);
- CurrentSetSize++;
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "New file descriptor: %d (%d; index %d)", fd, events[index].events, index);
+ eh->SetEventMask(event_mask);
return true;
}
-EventHandler* PollEngine::GetRef(int fd)
+void SocketEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask)
{
- std::map<int, unsigned int>::iterator it = fd_mappings.find(fd);
- if (it == fd_mappings.end())
- return NULL;
- return ref[it->second];
-}
-
-void PollEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask)
-{
- std::map<int, unsigned int>::iterator it = fd_mappings.find(eh->GetFd());
- if (it == fd_mappings.end())
+ int fd = eh->GetFd();
+ if (fd < 0 || static_cast<unsigned int>(fd) >= fd_mappings.size() || fd_mappings[fd] == -1)
{
- ServerInstance->Logs->Log("SOCKET",DEBUG,"SetEvents() on unknown fd: %d", eh->GetFd());
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "SetEvents() on unknown fd: %d", eh->GetFd());
return;
}
- events[it->second].events = mask_to_poll(new_mask);
+ events[fd_mappings[fd]].events = mask_to_poll(new_mask);
}
-void PollEngine::DelFd(EventHandler* eh)
+void SocketEngine::DelFd(EventHandler* eh)
{
int fd = eh->GetFd();
- if ((fd < 0) || (fd > MAX_DESCRIPTORS))
+ if (fd < 0)
{
- ServerInstance->Logs->Log("SOCKET", DEBUG, "DelFd out of range: (fd: %d, max: %d)", fd, GetMaxFds());
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "DelFd out of range: (fd: %d)", fd);
return;
}
- std::map<int, unsigned int>::iterator it = fd_mappings.find(fd);
- if (it == fd_mappings.end())
+ if (static_cast<unsigned int>(fd) >= fd_mappings.size() || fd_mappings[fd] == -1)
{
- ServerInstance->Logs->Log("SOCKET",DEBUG,"DelFd() on unknown fd: %d", fd);
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "DelFd() on unknown fd: %d", fd);
return;
}
- unsigned int index = it->second;
+ unsigned int index = fd_mappings[fd];
unsigned int last_index = CurrentSetSize - 1;
int last_fd = events[last_index].fd;
@@ -193,89 +148,78 @@ void PollEngine::DelFd(EventHandler* eh)
// move last_fd from last_index into index
events[index].fd = last_fd;
events[index].events = events[last_index].events;
-
- ref[index] = ref[last_index];
}
// Now remove all data for the last fd we got into out list.
// Above code made sure this always is right
- fd_mappings.erase(it);
+ fd_mappings[fd] = -1;
events[last_index].fd = 0;
events[last_index].events = 0;
- ref[last_index] = NULL;
- CurrentSetSize--;
+ SocketEngine::DelFdRef(eh);
- ServerInstance->Logs->Log("SOCKET", DEBUG, "Remove file descriptor: %d (index: %d) "
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Remove file descriptor: %d (index: %d) "
"(Filled gap with: %d (index: %d))", fd, index, last_fd, last_index);
}
-int PollEngine::DispatchEvents()
+int SocketEngine::DispatchEvents()
{
- int i = poll(events, CurrentSetSize, 1000);
- int index;
- socklen_t codesize = sizeof(int);
- int errcode;
+ int i = poll(&events[0], CurrentSetSize, 1000);
int processed = 0;
ServerInstance->UpdateTime();
- if (i > 0)
+ for (int index = 0; index < CurrentSetSize && processed < i; index++)
{
- for (index = 0; index < CurrentSetSize && processed != i; index++)
+ struct pollfd& pfd = events[index];
+
+ // Copy these in case the vector gets resized and pfd invalidated
+ const int fd = pfd.fd;
+ const short revents = pfd.revents;
+
+ if (revents)
+ processed++;
+
+ EventHandler* eh = GetRef(fd);
+ if (!eh)
+ continue;
+
+ if (revents & POLLHUP)
{
- if (events[index].revents)
- processed++;
- EventHandler* eh = ref[index];
- if (!eh)
- continue;
+ eh->HandleEvent(EVENT_ERROR, 0);
+ continue;
+ }
+
+ if (revents & POLLERR)
+ {
+ // Get error number
+ socklen_t codesize = sizeof(int);
+ int errcode;
+ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0)
+ errcode = errno;
+ eh->HandleEvent(EVENT_ERROR, errcode);
+ continue;
+ }
- if (events[index].revents & POLLHUP)
- {
- eh->HandleEvent(EVENT_ERROR, 0);
+ if (revents & POLLIN)
+ {
+ eh->SetEventMask(eh->GetEventMask() & ~FD_READ_WILL_BLOCK);
+ eh->HandleEvent(EVENT_READ);
+ if (eh != GetRef(fd))
+ // whoops, deleted out from under us
continue;
- }
+ }
- if (events[index].revents & POLLERR)
- {
- // Get fd
- int fd = events[index].fd;
+ if (revents & POLLOUT)
+ {
+ int mask = eh->GetEventMask();
+ mask &= ~(FD_WRITE_WILL_BLOCK | FD_WANT_SINGLE_WRITE);
+ eh->SetEventMask(mask);
- // Get error number
- if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0)
- errcode = errno;
- eh->HandleEvent(EVENT_ERROR, errcode);
- continue;
- }
-
- if (events[index].revents & POLLIN)
- {
- SetEventMask(eh, eh->GetEventMask() & ~FD_READ_WILL_BLOCK);
- eh->HandleEvent(EVENT_READ);
- if (eh != ref[index])
- // whoops, deleted out from under us
- continue;
- }
-
- if (events[index].revents & POLLOUT)
- {
- int mask = eh->GetEventMask();
- mask &= ~(FD_WRITE_WILL_BLOCK | FD_WANT_SINGLE_WRITE);
- SetEventMask(eh, mask);
- events[index].events = mask_to_poll(mask);
- eh->HandleEvent(EVENT_WRITE);
- }
+ // The vector could've been resized, reference can be invalid by now; don't use it
+ events[index].events = mask_to_poll(mask);
+ eh->HandleEvent(EVENT_WRITE);
}
}
return i;
}
-
-std::string PollEngine::GetName()
-{
- return "poll";
-}
-
-SocketEngine* CreateSocketEngine()
-{
- return new PollEngine;
-}
diff --git a/src/socketengines/socketengine_ports.cpp b/src/socketengines/socketengine_ports.cpp
index f7c547d45..0d77954e4 100644
--- a/src/socketengines/socketengine_ports.cpp
+++ b/src/socketengines/socketengine_ports.cpp
@@ -20,87 +20,54 @@
#include "inspircd.h"
#include "exitcodes.h"
-#include <port.h>
-
-#ifndef SOCKETENGINE_PORTS
-#define SOCKETENGINE_PORTS
#ifndef __sun
# error You need Solaris 10 or later to make use of this code.
#endif
-#include <vector>
-#include <string>
-#include <map>
-#include "inspircd_config.h"
#include "inspircd.h"
-#include "socketengine.h"
#include <port.h>
#include <iostream>
+#include <ulimit.h>
/** A specialisation of the SocketEngine class, designed to use solaris 10 I/O completion ports
*/
-class PortsEngine : public SocketEngine
+namespace
{
-private:
- /** These are used by epoll() to hold socket events
+ /** These are used by ports to hold socket events
*/
- port_event_t* events;
+ std::vector<port_event_t> events(16);
int EngineHandle;
-public:
- /** Create a new PortsEngine
- */
- PortsEngine();
- /** Delete a PortsEngine
- */
- virtual ~PortsEngine();
- virtual bool AddFd(EventHandler* eh, int event_mask);
- virtual void OnSetEvent(EventHandler* eh, int old_mask, int new_mask);
- virtual void DelFd(EventHandler* eh);
- virtual int DispatchEvents();
- virtual std::string GetName();
-};
-
-#endif
-
-
-#include <ulimit.h>
+}
-PortsEngine::PortsEngine()
+/** Initialize ports engine
+ */
+void SocketEngine::Init()
{
- int max = ulimit(4, 0);
- if (max > 0)
- {
- MAX_DESCRIPTORS = max;
- }
- else
- {
- ServerInstance->Logs->Log("SOCKET", DEFAULT, "ERROR: Can't determine maximum number of open sockets!");
- std::cout << "ERROR: Can't determine maximum number of open sockets!" << std::endl;
- ServerInstance->QuickExit(EXIT_STATUS_SOCKETENGINE);
- }
+ // MAX_DESCRIPTORS is mainly used for display purposes, no problem if ulimit() fails and returns a negative number
+ MAX_DESCRIPTORS = ulimit(4, 0);
+
EngineHandle = port_create();
if (EngineHandle == -1)
{
- ServerInstance->Logs->Log("SOCKET",SPARSE,"ERROR: Could not initialize socket engine: %s", strerror(errno));
- ServerInstance->Logs->Log("SOCKET",SPARSE,"ERROR: This is a fatal error, exiting now.");
+ ServerInstance->Logs->Log("SOCKET", LOG_SPARSE, "ERROR: Could not initialize socket engine: %s", strerror(errno));
+ ServerInstance->Logs->Log("SOCKET", LOG_SPARSE, "ERROR: This is a fatal error, exiting now.");
std::cout << "ERROR: Could not initialize socket engine: " << strerror(errno) << std::endl;
std::cout << "ERROR: This is a fatal error, exiting now." << std::endl;
ServerInstance->QuickExit(EXIT_STATUS_SOCKETENGINE);
}
- CurrentSetSize = 0;
+}
- ref = new EventHandler* [GetMaxFds()];
- events = new port_event_t[GetMaxFds()];
- memset(ref, 0, GetMaxFds() * sizeof(EventHandler*));
+/** Shutdown the ports engine
+ */
+void SocketEngine::Deinit()
+{
+ SocketEngine::Close(EngineHandle);
}
-PortsEngine::~PortsEngine()
+void SocketEngine::RecoverFromFork()
{
- this->Close(EngineHandle);
- delete[] ref;
- delete[] events;
}
static int mask_to_events(int event_mask)
@@ -113,45 +80,44 @@ static int mask_to_events(int event_mask)
return rv;
}
-bool PortsEngine::AddFd(EventHandler* eh, int event_mask)
+bool SocketEngine::AddFd(EventHandler* eh, int event_mask)
{
int fd = eh->GetFd();
- if ((fd < 0) || (fd > GetMaxFds() - 1))
+ if (fd < 0)
return false;
- if (ref[fd])
+ if (!SocketEngine::AddFdRef(eh))
return false;
- ref[fd] = eh;
- SocketEngine::SetEventMask(eh, event_mask);
+ eh->SetEventMask(event_mask);
port_associate(EngineHandle, PORT_SOURCE_FD, fd, mask_to_events(event_mask), eh);
- ServerInstance->Logs->Log("SOCKET",DEBUG,"New file descriptor: %d", fd);
- CurrentSetSize++;
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "New file descriptor: %d", fd);
+ ResizeDouble(events);
+
return true;
}
-void PortsEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask)
+void SocketEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask)
{
if (mask_to_events(new_mask) != mask_to_events(old_mask))
port_associate(EngineHandle, PORT_SOURCE_FD, eh->GetFd(), mask_to_events(new_mask), eh);
}
-void PortsEngine::DelFd(EventHandler* eh)
+void SocketEngine::DelFd(EventHandler* eh)
{
int fd = eh->GetFd();
- if ((fd < 0) || (fd > GetMaxFds() - 1))
+ if (fd < 0)
return;
port_dissociate(EngineHandle, PORT_SOURCE_FD, fd);
- CurrentSetSize--;
- ref[fd] = NULL;
+ SocketEngine::DelFdRef(eh);
- ServerInstance->Logs->Log("SOCKET",DEBUG,"Remove file descriptor: %d", fd);
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Remove file descriptor: %d", fd);
}
-int PortsEngine::DispatchEvents()
+int SocketEngine::DispatchEvents()
{
struct timespec poll_time;
@@ -159,62 +125,51 @@ int PortsEngine::DispatchEvents()
poll_time.tv_nsec = 0;
unsigned int nget = 1; // used to denote a retrieve request.
- int ret = port_getn(EngineHandle, this->events, GetMaxFds() - 1, &nget, &poll_time);
+ int ret = port_getn(EngineHandle, &events[0], events.size(), &nget, &poll_time);
ServerInstance->UpdateTime();
// first handle an error condition
if (ret == -1)
return -1;
- TotalEvents += nget;
+ stats.TotalEvents += nget;
unsigned int i;
for (i = 0; i < nget; i++)
{
- switch (this->events[i].portev_source)
+ port_event_t& ev = events[i];
+
+ if (ev.portev_source != PORT_SOURCE_FD)
+ continue;
+
+ // Copy these in case the vector gets resized and ev invalidated
+ const int fd = ev.portev_object;
+ const int portev_events = ev.portev_events;
+ EventHandler* eh = static_cast<EventHandler*>(ev.portev_user);
+ if (eh->GetFd() < 0)
+ continue;
+
+ int mask = eh->GetEventMask();
+ if (portev_events & POLLWRNORM)
+ mask &= ~(FD_WRITE_WILL_BLOCK | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE);
+ if (portev_events & POLLRDNORM)
+ mask &= ~FD_READ_WILL_BLOCK;
+ // reinsert port for next time around, pretending to be one-shot for writes
+ eh->SetEventMask(mask);
+ port_associate(EngineHandle, PORT_SOURCE_FD, fd, mask_to_events(mask), eh);
+ if (portev_events & POLLRDNORM)
{
- case PORT_SOURCE_FD:
- {
- int fd = this->events[i].portev_object;
- EventHandler* eh = ref[fd];
- if (eh)
- {
- int mask = eh->GetEventMask();
- if (events[i].portev_events & POLLWRNORM)
- mask &= ~(FD_WRITE_WILL_BLOCK | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE);
- if (events[i].portev_events & POLLRDNORM)
- mask &= ~FD_READ_WILL_BLOCK;
- // reinsert port for next time around, pretending to be one-shot for writes
- SetEventMask(eh, mask);
- port_associate(EngineHandle, PORT_SOURCE_FD, fd, mask_to_events(mask), eh);
- if (events[i].portev_events & POLLRDNORM)
- {
- ReadEvents++;
- eh->HandleEvent(EVENT_READ);
- if (eh != ref[fd])
- continue;
- }
- if (events[i].portev_events & POLLWRNORM)
- {
- WriteEvents++;
- eh->HandleEvent(EVENT_WRITE);
- }
- }
- }
- default:
- break;
+ stats.ReadEvents++;
+ eh->HandleEvent(EVENT_READ);
+ if (eh != GetRef(fd))
+ continue;
+ }
+ if (portev_events & POLLWRNORM)
+ {
+ stats.WriteEvents++;
+ eh->HandleEvent(EVENT_WRITE);
}
}
return (int)i;
}
-
-std::string PortsEngine::GetName()
-{
- return "ports";
-}
-
-SocketEngine* CreateSocketEngine()
-{
- return new PortsEngine;
-}
diff --git a/src/socketengines/socketengine_select.cpp b/src/socketengines/socketengine_select.cpp
index 0b5abaf30..f44346ad8 100644
--- a/src/socketengines/socketengine_select.cpp
+++ b/src/socketengines/socketengine_select.cpp
@@ -1,6 +1,7 @@
/*
* InspIRCd -- Internet Relay Chat Daemon
*
+ * Copyright (C) 2014 Adam <Adam@anope.org>
* Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
* Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc>
*
@@ -18,10 +19,7 @@
*/
-#include "inspircd_config.h"
-
#include "inspircd.h"
-#include "socketengine.h"
#ifndef _WIN32
#include <sys/select.h>
@@ -29,76 +27,56 @@
/** A specialisation of the SocketEngine class, designed to use traditional select().
*/
-class SelectEngine : public SocketEngine
+namespace
{
fd_set ReadSet, WriteSet, ErrSet;
- int MaxFD;
-
-public:
- /** Create a new SelectEngine
- */
- SelectEngine();
- /** Delete a SelectEngine
- */
- virtual ~SelectEngine();
- virtual bool AddFd(EventHandler* eh, int event_mask);
- virtual void DelFd(EventHandler* eh);
- void OnSetEvent(EventHandler* eh, int, int);
- virtual int DispatchEvents();
- virtual std::string GetName();
-};
-
-SelectEngine::SelectEngine()
+ int MaxFD = 0;
+}
+
+void SocketEngine::Init()
{
MAX_DESCRIPTORS = FD_SETSIZE;
- CurrentSetSize = 0;
-
- ref = new EventHandler* [GetMaxFds()];
- memset(ref, 0, GetMaxFds() * sizeof(EventHandler*));
FD_ZERO(&ReadSet);
FD_ZERO(&WriteSet);
FD_ZERO(&ErrSet);
- MaxFD = 0;
}
-SelectEngine::~SelectEngine()
+void SocketEngine::Deinit()
+{
+}
+
+void SocketEngine::RecoverFromFork()
{
- delete[] ref;
}
-bool SelectEngine::AddFd(EventHandler* eh, int event_mask)
+bool SocketEngine::AddFd(EventHandler* eh, int event_mask)
{
int fd = eh->GetFd();
if ((fd < 0) || (fd > GetMaxFds() - 1))
return false;
- if (ref[fd])
+ if (!SocketEngine::AddFdRef(eh))
return false;
- ref[fd] = eh;
-
- SocketEngine::SetEventMask(eh, event_mask);
+ eh->SetEventMask(event_mask);
OnSetEvent(eh, 0, event_mask);
FD_SET(fd, &ErrSet);
if (fd > MaxFD)
MaxFD = fd;
- CurrentSetSize++;
-
- ServerInstance->Logs->Log("SOCKET",DEBUG,"New file descriptor: %d", fd);
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "New file descriptor: %d", fd);
return true;
}
-void SelectEngine::DelFd(EventHandler* eh)
+void SocketEngine::DelFd(EventHandler* eh)
{
int fd = eh->GetFd();
if ((fd < 0) || (fd > GetMaxFds() - 1))
return;
- CurrentSetSize--;
- ref[fd] = NULL;
+ SocketEngine::DelFdRef(eh);
FD_CLR(fd, &ReadSet);
FD_CLR(fd, &WriteSet);
@@ -106,10 +84,10 @@ void SelectEngine::DelFd(EventHandler* eh)
if (fd == MaxFD)
--MaxFD;
- ServerInstance->Logs->Log("SOCKET",DEBUG,"Remove file descriptor: %d", fd);
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Remove file descriptor: %d", fd);
}
-void SelectEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask)
+void SocketEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask)
{
int fd = eh->GetFd();
int diff = old_mask ^ new_mask;
@@ -130,7 +108,7 @@ void SelectEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask)
}
}
-int SelectEngine::DispatchEvents()
+int SocketEngine::DispatchEvents()
{
timeval tval;
tval.tv_sec = 1;
@@ -141,63 +119,50 @@ int SelectEngine::DispatchEvents()
int sresult = select(MaxFD + 1, &rfdset, &wfdset, &errfdset, &tval);
ServerInstance->UpdateTime();
- /* Nothing to process this time around */
- if (sresult < 1)
- return 0;
-
for (int i = 0, j = sresult; i <= MaxFD && j > 0; i++)
{
int has_read = FD_ISSET(i, &rfdset), has_write = FD_ISSET(i, &wfdset), has_error = FD_ISSET(i, &errfdset);
- if (has_read || has_write || has_error)
- {
- --j;
+ if (!(has_read || has_write || has_error))
+ continue;
- EventHandler* ev = ref[i];
- if (!ev)
- continue;
+ --j;
+
+ EventHandler* ev = GetRef(i);
+ if (!ev)
+ continue;
- if (has_error)
- {
- ErrorEvents++;
+ if (has_error)
+ {
+ stats.ErrorEvents++;
+
+ socklen_t codesize = sizeof(int);
+ int errcode = 0;
+ if (getsockopt(i, SOL_SOCKET, SO_ERROR, (char*)&errcode, &codesize) < 0)
+ errcode = errno;
- socklen_t codesize = sizeof(int);
- int errcode = 0;
- if (getsockopt(i, SOL_SOCKET, SO_ERROR, (char*)&errcode, &codesize) < 0)
- errcode = errno;
+ ev->HandleEvent(EVENT_ERROR, errcode);
+ continue;
+ }
- ev->HandleEvent(EVENT_ERROR, errcode);
+ if (has_read)
+ {
+ stats.ReadEvents++;
+ ev->SetEventMask(ev->GetEventMask() & ~FD_READ_WILL_BLOCK);
+ ev->HandleEvent(EVENT_READ);
+ if (ev != GetRef(i))
continue;
- }
-
- if (has_read)
- {
- ReadEvents++;
- SetEventMask(ev, ev->GetEventMask() & ~FD_READ_WILL_BLOCK);
- ev->HandleEvent(EVENT_READ);
- if (ev != ref[i])
- continue;
- }
- if (has_write)
- {
- WriteEvents++;
- int newmask = (ev->GetEventMask() & ~(FD_WRITE_WILL_BLOCK | FD_WANT_SINGLE_WRITE));
- this->OnSetEvent(ev, ev->GetEventMask(), newmask);
- SetEventMask(ev, newmask);
- ev->HandleEvent(EVENT_WRITE);
- }
+ }
+
+ if (has_write)
+ {
+ stats.WriteEvents++;
+ int newmask = (ev->GetEventMask() & ~(FD_WRITE_WILL_BLOCK | FD_WANT_SINGLE_WRITE));
+ SocketEngine::OnSetEvent(ev, ev->GetEventMask(), newmask);
+ ev->SetEventMask(newmask);
+ ev->HandleEvent(EVENT_WRITE);
}
}
return sresult;
}
-
-std::string SelectEngine::GetName()
-{
- return "select";
-}
-
-SocketEngine* CreateSocketEngine()
-{
- return new SelectEngine;
-}
diff --git a/src/testsuite.cpp b/src/testsuite.cpp
index 58b72ee3e..a7a9ec99b 100644
--- a/src/testsuite.cpp
+++ b/src/testsuite.cpp
@@ -19,11 +19,10 @@
*/
-/* $Core */
+#ifdef INSPIRCD_ENABLE_TESTSUITE
#include "inspircd.h"
#include "testsuite.h"
-#include "threadengine.h"
#include <iostream>
class TestSuiteThread : public Thread
@@ -76,8 +75,12 @@ TestSuite::TestSuite()
switch (choice)
{
case '1':
- FOREACH_MOD(I_OnRunTestSuite, OnRunTestSuite());
+ {
+ const ModuleManager::ModuleMap& mods = ServerInstance->Modules->GetModules();
+ for (ModuleManager::ModuleMap::const_iterator i = mods.begin(); i != mods.end(); ++i)
+ i->second->OnRunTestSuite();
break;
+ }
case '2':
std::cout << "Enter module filename to load: ";
std::cin >> modname;
@@ -331,36 +334,25 @@ bool TestSuite::DoThreadTests()
bool TestSuite::DoGenerateUIDTests()
{
- bool success = RealGenerateUIDTests();
+ const unsigned int UUID_LENGTH = UIDGenerator::UUID_LENGTH;
+ UIDGenerator uidgen;
+ uidgen.init(ServerInstance->Config->GetSID());
+ std::string first_uid = uidgen.GetUID();
- // Reset the UID generation state so running the tests multiple times won't mess things up
- for (unsigned int i = 0; i < 3; i++)
- ServerInstance->current_uid[i] = ServerInstance->Config->sid[i];
- for (unsigned int i = 3; i < UUID_LENGTH-1; i++)
- ServerInstance->current_uid[i] = '9';
-
- ServerInstance->current_uid[UUID_LENGTH-1] = '\0';
-
- return success;
-}
-
-bool TestSuite::RealGenerateUIDTests()
-{
- std::string first_uid = ServerInstance->GetUID();
- if (first_uid.length() != UUID_LENGTH-1)
+ if (first_uid.length() != UUID_LENGTH)
{
std::cout << "GENERATEUID: Generated UID is " << first_uid.length() << " characters long instead of " << UUID_LENGTH-1 << std::endl;
return false;
}
- if (ServerInstance->current_uid[UUID_LENGTH-1] != '\0')
+ if (uidgen.current_uid.c_str()[UUID_LENGTH] != '\0')
{
std::cout << "GENERATEUID: The null terminator is missing from the end of current_uid" << std::endl;
return false;
}
// The correct UID when generating one for the first time is ...AAAAAA
- std::string correct_uid = ServerInstance->Config->sid + std::string(UUID_LENGTH - 4, 'A');
+ std::string correct_uid = ServerInstance->Config->sid + std::string(UUID_LENGTH - 3, 'A');
if (first_uid != correct_uid)
{
std::cout << "GENERATEUID: Generated an invalid first UID: " << first_uid << " instead of " << correct_uid << std::endl;
@@ -368,16 +360,16 @@ bool TestSuite::RealGenerateUIDTests()
}
// Set current_uid to be ...Z99999
- ServerInstance->current_uid[3] = 'Z';
- for (unsigned int i = 4; i < UUID_LENGTH-1; i++)
- ServerInstance->current_uid[i] = '9';
+ uidgen.current_uid[3] = 'Z';
+ for (unsigned int i = 4; i < UUID_LENGTH; i++)
+ uidgen.current_uid[i] = '9';
// Store the UID we'll be incrementing so we can display what's wrong later if necessary
- std::string before_increment(ServerInstance->current_uid);
- std::string generated_uid = ServerInstance->GetUID();
+ std::string before_increment(uidgen.current_uid);
+ std::string generated_uid = uidgen.GetUID();
// Correct UID after incrementing ...Z99999 is ...0AAAAA
- correct_uid = ServerInstance->Config->sid + "0" + std::string(UUID_LENGTH - 5, 'A');
+ correct_uid = ServerInstance->Config->sid + "0" + std::string(UUID_LENGTH - 4, 'A');
if (generated_uid != correct_uid)
{
@@ -386,11 +378,11 @@ bool TestSuite::RealGenerateUIDTests()
}
// Set current_uid to be ...999999 to see if it rolls over correctly
- for (unsigned int i = 3; i < UUID_LENGTH-1; i++)
- ServerInstance->current_uid[i] = '9';
+ for (unsigned int i = 3; i < UUID_LENGTH; i++)
+ uidgen.current_uid[i] = '9';
- before_increment.assign(ServerInstance->current_uid);
- generated_uid = ServerInstance->GetUID();
+ before_increment.assign(uidgen.current_uid);
+ generated_uid = uidgen.GetUID();
// Correct UID after rolling over is the first UID we've generated (...AAAAAA)
if (generated_uid != first_uid)
@@ -407,3 +399,4 @@ TestSuite::~TestSuite()
std::cout << "\n\n*** END OF TEST SUITE ***\n";
}
+#endif
diff --git a/src/threadengine.cpp b/src/threadengine.cpp
index 8f1895c0f..f757aa56c 100644
--- a/src/threadengine.cpp
+++ b/src/threadengine.cpp
@@ -17,14 +17,7 @@
*/
-/* $Core */
-
-/********* DEFAULTS **********/
-/* $ExtraSources: threadengines/threadengine_pthread.cpp */
-/* $ExtraObjects: threadengine_pthread.o */
-
#include "inspircd.h"
-#include "threadengine.h"
void Thread::SetExitFlag()
{
@@ -33,14 +26,5 @@ void Thread::SetExitFlag()
void Thread::join()
{
- state->FreeThread(this);
- delete state;
- state = 0;
-}
-
-/** If this thread has a Creator set, call it to
- * free the thread
- */
-Thread::~Thread()
-{
+ ServerInstance->Threads.Stop(this);
}
diff --git a/src/threadengines/threadengine_pthread.cpp b/src/threadengines/threadengine_pthread.cpp
index e16e401f3..fcb4db444 100644
--- a/src/threadengines/threadengine_pthread.cpp
+++ b/src/threadengines/threadengine_pthread.cpp
@@ -21,13 +21,8 @@
#include "inspircd.h"
#include "threadengines/threadengine_pthread.h"
#include <pthread.h>
-#include <signal.h>
#include <fcntl.h>
-ThreadEngine::ThreadEngine()
-{
-}
-
static void* entry_point(void* parameter)
{
/* Recommended by nenolod, signal safety on a per-thread basis */
@@ -44,25 +39,14 @@ static void* entry_point(void* parameter)
void ThreadEngine::Start(Thread* thread)
{
- ThreadData* data = new ThreadData;
- thread->state = data;
-
- if (pthread_create(&data->pthread_id, NULL, entry_point, thread) != 0)
- {
- thread->state = NULL;
- delete data;
+ if (pthread_create(&thread->state.pthread_id, NULL, entry_point, thread) != 0)
throw CoreException("Unable to create new thread: " + std::string(strerror(errno)));
- }
-}
-
-ThreadEngine::~ThreadEngine()
-{
}
-void ThreadData::FreeThread(Thread* thread)
+void ThreadEngine::Stop(Thread* thread)
{
thread->SetExitFlag();
- pthread_join(pthread_id, NULL);
+ pthread_join(thread->state.pthread_id, NULL);
}
#ifdef HAS_EVENTFD
@@ -75,13 +59,12 @@ class ThreadSignalSocket : public EventHandler
ThreadSignalSocket(SocketThread* p, int newfd) : parent(p)
{
SetFd(newfd);
- ServerInstance->SE->AddFd(this, FD_WANT_FAST_READ | FD_WANT_NO_WRITE);
+ SocketEngine::AddFd(this, FD_WANT_FAST_READ | FD_WANT_NO_WRITE);
}
~ThreadSignalSocket()
{
- ServerInstance->SE->DelFd(this);
- ServerInstance->SE->Close(GetFd());
+ SocketEngine::Close(this);
}
void Notify()
@@ -123,15 +106,14 @@ class ThreadSignalSocket : public EventHandler
parent(p), send_fd(sendfd)
{
SetFd(recvfd);
- ServerInstance->SE->NonBlocking(fd);
- ServerInstance->SE->AddFd(this, FD_WANT_FAST_READ | FD_WANT_NO_WRITE);
+ SocketEngine::NonBlocking(fd);
+ SocketEngine::AddFd(this, FD_WANT_FAST_READ | FD_WANT_NO_WRITE);
}
~ThreadSignalSocket()
{
close(send_fd);
- ServerInstance->SE->DelFd(this);
- ServerInstance->SE->Close(GetFd());
+ SocketEngine::Close(this);
}
void Notify()
diff --git a/src/threadengines/threadengine_win32.cpp b/src/threadengines/threadengine_win32.cpp
index ea37892f8..90fe60b91 100644
--- a/src/threadengines/threadengine_win32.cpp
+++ b/src/threadengines/threadengine_win32.cpp
@@ -21,33 +21,19 @@
#include "inspircd.h"
#include "threadengines/threadengine_win32.h"
-ThreadEngine::ThreadEngine()
-{
-}
-
void ThreadEngine::Start(Thread* thread)
{
- ThreadData* data = new ThreadData;
- thread->state = data;
-
- DWORD ThreadId = 0;
- data->handle = CreateThread(NULL,0,ThreadEngine::Entry,thread,0,&ThreadId);
+ thread->state.handle = CreateThread(NULL, 0, ThreadEngine::Entry, thread, 0, NULL);
- if (data->handle == NULL)
+ if (thread->state.handle == NULL)
{
DWORD lasterr = GetLastError();
- thread->state = NULL;
- delete data;
std::string err = "Unable to create new thread: " + ConvToStr(lasterr);
SetLastError(ERROR_SUCCESS);
throw CoreException(err);
}
}
-ThreadEngine::~ThreadEngine()
-{
-}
-
DWORD WINAPI ThreadEngine::Entry(void* parameter)
{
Thread* pt = static_cast<Thread*>(parameter);
@@ -55,9 +41,10 @@ DWORD WINAPI ThreadEngine::Entry(void* parameter)
return 0;
}
-void ThreadData::FreeThread(Thread* thread)
+void ThreadEngine::Stop(Thread* thread)
{
thread->SetExitFlag();
+ HANDLE handle = thread->state.handle;
WaitForSingleObject(handle,INFINITE);
CloseHandle(handle);
}
@@ -94,20 +81,20 @@ SocketThread::SocketThread()
if (!ServerInstance->BindSocket(listenFD, 0, "127.0.0.1", true))
throw CoreException("Could not create ITC pipe");
- ServerInstance->SE->NonBlocking(connFD);
+ SocketEngine::NonBlocking(connFD);
struct sockaddr_in addr;
socklen_t sz = sizeof(addr);
getsockname(listenFD, reinterpret_cast<struct sockaddr*>(&addr), &sz);
connect(connFD, reinterpret_cast<struct sockaddr*>(&addr), sz);
- ServerInstance->SE->Blocking(listenFD);
+ SocketEngine::Blocking(listenFD);
int nfd = accept(listenFD, reinterpret_cast<struct sockaddr*>(&addr), &sz);
if (nfd < 0)
throw CoreException("Could not create ITC pipe");
new ThreadSignalSocket(this, nfd);
closesocket(listenFD);
- ServerInstance->SE->Blocking(connFD);
+ SocketEngine::Blocking(connFD);
this->signal.connFD = connFD;
}
diff --git a/src/timer.cpp b/src/timer.cpp
index e04a186cf..0b0d8bac3 100644
--- a/src/timer.cpp
+++ b/src/timer.cpp
@@ -20,60 +20,64 @@
*/
-/* $Core */
-
#include "inspircd.h"
-#include "timer.h"
-TimerManager::TimerManager()
+void Timer::SetInterval(time_t newinterval)
{
+ ServerInstance->Timers.DelTimer(this);
+ secs = newinterval;
+ SetTrigger(ServerInstance->Time() + newinterval);
+ ServerInstance->Timers.AddTimer(this);
}
-TimerManager::~TimerManager()
+Timer::Timer(unsigned int secs_from_now, bool repeating)
+ : trigger(ServerInstance->Time() + secs_from_now)
+ , secs(secs_from_now)
+ , repeat(repeating)
{
- for(std::vector<Timer *>::iterator i = Timers.begin(); i != Timers.end(); i++)
- delete *i;
+}
+
+Timer::~Timer()
+{
+ ServerInstance->Timers.DelTimer(this);
}
void TimerManager::TickTimers(time_t TIME)
{
- while ((Timers.size()) && (TIME > (*Timers.begin())->GetTimer()))
+ for (TimerMap::iterator i = Timers.begin(); i != Timers.end(); )
{
- std::vector<Timer *>::iterator i = Timers.begin();
- Timer *t = (*i);
+ Timer* t = i->second;
+ if (t->GetTrigger() > TIME)
+ break;
+
+ Timers.erase(i++);
- // Probable fix: move vector manipulation to *before* we modify the vector.
- Timers.erase(i);
+ if (!t->Tick(TIME))
+ continue;
- t->Tick(TIME);
if (t->GetRepeat())
{
- t->SetTimer(TIME + t->GetSecs());
+ t->SetTrigger(TIME + t->GetInterval());
AddTimer(t);
}
- else
- delete t;
}
}
-void TimerManager::DelTimer(Timer* T)
+void TimerManager::DelTimer(Timer* t)
{
- std::vector<Timer *>::iterator i = std::find(Timers.begin(), Timers.end(), T);
+ std::pair<TimerMap::iterator, TimerMap::iterator> itpair = Timers.equal_range(t->GetTrigger());
- if (i != Timers.end())
+ for (TimerMap::iterator i = itpair.first; i != itpair.second; ++i)
{
- delete (*i);
- Timers.erase(i);
+ if (i->second == t)
+ {
+ Timers.erase(i);
+ break;
+ }
}
}
-void TimerManager::AddTimer(Timer* T)
-{
- Timers.push_back(T);
- std::sort(Timers.begin(), Timers.end(), TimerManager::TimerComparison);
-}
-
-bool TimerManager::TimerComparison( Timer *one, Timer *two)
+void TimerManager::AddTimer(Timer* t)
{
- return (one->GetTimer()) < (two->GetTimer());
+ Timers.insert(std::make_pair(t->GetTrigger(), t));
}
diff --git a/src/user_resolver.cpp b/src/user_resolver.cpp
deleted file mode 100644
index f18fc9a03..000000000
--- a/src/user_resolver.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-UserResolver::UserResolver(LocalUser* user, std::string to_resolve, QueryType qt, bool &cache) :
- Resolver(to_resolve, qt, cache, NULL), uuid(user->uuid)
-{
- this->fwd = (qt == DNS_QUERY_A || qt == DNS_QUERY_AAAA);
-}
-
-void UserResolver::OnLookupComplete(const std::string &result, unsigned int ttl, bool cached)
-{
- UserResolver *res_forward; // for forward-resolution
- LocalUser* bound_user = (LocalUser*)ServerInstance->FindUUID(uuid);
- if (!bound_user)
- {
- ServerInstance->Logs->Log("RESOLVER", DEBUG, "Resolution finished for user '%s' who is gone", uuid.c_str());
- return;
- }
-
- ServerInstance->Logs->Log("RESOLVER", DEBUG, "DNS result for %s: '%s' -> '%s'", uuid.c_str(), input.c_str(), result.c_str());
-
- if (!fwd)
- {
- // first half of resolution is done. We now need to verify that the host matches.
- bound_user->stored_host = result;
- try
- {
- /* Check we didnt time out */
- if (bound_user->registered != REG_ALL)
- {
- bool lcached = false;
- if (bound_user->client_sa.sa.sa_family == AF_INET6)
- {
- /* IPV6 forward lookup */
- res_forward = new UserResolver(bound_user, result, DNS_QUERY_AAAA, lcached);
- }
- else
- {
- /* IPV4 lookup */
- res_forward = new UserResolver(bound_user, result, DNS_QUERY_A, lcached);
- }
- ServerInstance->AddResolver(res_forward, lcached);
- }
- }
- catch (CoreException& e)
- {
- ServerInstance->Logs->Log("RESOLVER", DEBUG,"Error in resolver: %s",e.GetReason());
- }
- }
- else
- {
- /* Both lookups completed */
-
- irc::sockets::sockaddrs* user_ip = &bound_user->client_sa;
- bool rev_match = false;
- if (user_ip->sa.sa_family == AF_INET6)
- {
- struct in6_addr res_bin;
- if (inet_pton(AF_INET6, result.c_str(), &res_bin))
- {
- rev_match = !memcmp(&user_ip->in6.sin6_addr, &res_bin, sizeof(res_bin));
- }
- }
- else
- {
- struct in_addr res_bin;
- if (inet_pton(AF_INET, result.c_str(), &res_bin))
- {
- rev_match = !memcmp(&user_ip->in4.sin_addr, &res_bin, sizeof(res_bin));
- }
- }
-
- if (rev_match)
- {
- std::string hostname = bound_user->stored_host;
- if (hostname.length() < 65)
- {
- /* Check we didnt time out */
- if ((bound_user->registered != REG_ALL) && (!bound_user->dns_done))
- {
- /* Hostnames starting with : are not a good thing (tm) */
- if (hostname[0] == ':')
- hostname.insert(0, "0");
-
- bound_user->WriteServ("NOTICE Auth :*** Found your hostname (%s)%s", hostname.c_str(), (cached ? " -- cached" : ""));
- bound_user->dns_done = true;
- bound_user->dhost.assign(hostname, 0, 64);
- bound_user->host.assign(hostname, 0, 64);
- /* Invalidate cache */
- bound_user->InvalidateCache();
- }
- }
- else
- {
- if (!bound_user->dns_done)
- {
- bound_user->WriteServ("NOTICE Auth :*** Your hostname is longer than the maximum of 64 characters, using your IP address (%s) instead.", bound_user->GetIPString());
- bound_user->dns_done = true;
- }
- }
- }
- else
- {
- if (!bound_user->dns_done)
- {
- bound_user->WriteServ("NOTICE Auth :*** Your hostname does not match up with your IP address. Sorry, using your IP address (%s) instead.", bound_user->GetIPString());
- bound_user->dns_done = true;
- }
- }
-
- // Save some memory by freeing this up; it's never used again in the user's lifetime.
- bound_user->stored_host.resize(0);
- }
-}
-
-void UserResolver::OnError(ResolverError e, const std::string &errormessage)
-{
- LocalUser* bound_user = (LocalUser*)ServerInstance->FindUUID(uuid);
- if (bound_user)
- {
- bound_user->WriteServ("NOTICE Auth :*** Could not resolve your hostname: %s; using your IP address (%s) instead.", errormessage.c_str(), bound_user->GetIPString());
- bound_user->dns_done = true;
- bound_user->stored_host.resize(0);
- ServerInstance->stats->statsDnsBad++;
- }
-}
diff --git a/src/usermanager.cpp b/src/usermanager.cpp
index 076277a33..2dcee852c 100644
--- a/src/usermanager.cpp
+++ b/src/usermanager.cpp
@@ -22,13 +22,21 @@
#include "inspircd.h"
#include "xline.h"
-#include "bancache.h"
+#include "iohook.h"
UserManager::UserManager()
- : unregistered_count(0), local_count(0)
+ : unregistered_count(0)
{
}
+UserManager::~UserManager()
+{
+ for (user_hash::iterator i = clientlist.begin(); i != clientlist.end(); ++i)
+ {
+ delete i->second;
+ }
+}
+
/* add a client connection to the sockets list */
void UserManager::AddUser(int socket, ListenSocket* via, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server)
{
@@ -42,46 +50,33 @@ void UserManager::AddUser(int socket, ListenSocket* via, irc::sockets::sockaddrs
}
catch (...)
{
- ServerInstance->Logs->Log("USERS", DEFAULT,"*** WTF *** Duplicated UUID! -- Crack smoking monkeys have been unleashed.");
+ ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "*** WTF *** Duplicated UUID! -- Crack smoking monkeys have been unleashed.");
ServerInstance->SNO->WriteToSnoMask('a', "WARNING *** Duplicate UUID allocated!");
return;
}
UserIOHandler* eh = &New->eh;
- /* Give each of the modules an attempt to hook the user for I/O */
- FOREACH_MOD(I_OnHookIO, OnHookIO(eh, via));
+ // If this listener has an IO hook provider set then tell it about the connection
+ if (via->iohookprov)
+ via->iohookprov->OnAccept(eh, client, server);
- if (eh->GetIOHook())
- {
- try
- {
- eh->GetIOHook()->OnStreamSocketAccept(eh, client, server);
- }
- catch (CoreException& modexcept)
- {
- ServerInstance->Logs->Log("SOCKET", DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
- }
- }
-
- ServerInstance->Logs->Log("USERS", DEBUG,"New user fd: %d", socket);
+ ServerInstance->Logs->Log("USERS", LOG_DEBUG, "New user fd: %d", socket);
this->unregistered_count++;
/* The users default nick is their UUID */
New->nick = New->uuid;
- (*(this->clientlist))[New->nick] = New;
+ this->clientlist[New->nick] = New;
New->registered = REG_NONE;
New->signon = ServerInstance->Time() + ServerInstance->Config->dns_timeout;
New->lastping = 1;
- ServerInstance->Users->AddLocalClone(New);
- ServerInstance->Users->AddGlobalClone(New);
+ this->AddClone(New);
- New->localuseriter = this->local_users.insert(local_users.end(), New);
- local_count++;
+ this->local_users.push_front(New);
- if ((this->local_users.size() > ServerInstance->Config->SoftLimit) || (this->local_users.size() >= (unsigned int)ServerInstance->SE->GetMaxFds()))
+ if (this->local_users.size() > ServerInstance->Config->SoftLimit)
{
ServerInstance->SNO->WriteToSnoMask('a', "Warning: softlimit value has been reached: %d clients", ServerInstance->Config->SoftLimit);
this->QuitUser(New,"No more connections allowed");
@@ -98,7 +93,7 @@ void UserManager::AddUser(int socket, ListenSocket* via, irc::sockets::sockaddrs
* Check connect class settings and initialise settings into User.
* This will be done again after DNS resolution. -- w00t
*/
- New->CheckClass();
+ New->CheckClass(ServerInstance->Config->CCOnConnect);
if (New->quitting)
return;
@@ -109,20 +104,21 @@ void UserManager::AddUser(int socket, ListenSocket* via, irc::sockets::sockaddrs
*/
New->exempt = (ServerInstance->XLines->MatchesLine("E",New) != NULL);
- if (BanCacheHit *b = ServerInstance->BanCache->GetHit(New->GetIPString()))
+ BanCacheHit* const b = ServerInstance->BanCache.GetHit(New->GetIPString());
+ if (b)
{
if (!b->Type.empty() && !New->exempt)
{
/* user banned */
- ServerInstance->Logs->Log("BANCACHE", DEBUG, std::string("BanCache: Positive hit for ") + New->GetIPString());
- if (!ServerInstance->Config->MoronBanner.empty())
- New->WriteServ("NOTICE %s :*** %s", New->nick.c_str(), ServerInstance->Config->MoronBanner.c_str());
+ ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "BanCache: Positive hit for " + New->GetIPString());
+ if (!ServerInstance->Config->XLineMessage.empty())
+ New->WriteNotice("*** " + ServerInstance->Config->XLineMessage);
this->QuitUser(New, b->Reason);
return;
}
else
{
- ServerInstance->Logs->Log("BANCACHE", DEBUG, std::string("BanCache: Negative hit for ") + New->GetIPString());
+ ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "BanCache: Negative hit for " + New->GetIPString());
}
}
else
@@ -139,260 +135,206 @@ void UserManager::AddUser(int socket, ListenSocket* via, irc::sockets::sockaddrs
}
}
- if (!ServerInstance->SE->AddFd(eh, FD_WANT_FAST_READ | FD_WANT_EDGE_WRITE))
+ if (!SocketEngine::AddFd(eh, FD_WANT_FAST_READ | FD_WANT_EDGE_WRITE))
{
- ServerInstance->Logs->Log("USERS", DEBUG,"Internal error on new connection");
+ ServerInstance->Logs->Log("USERS", LOG_DEBUG, "Internal error on new connection");
this->QuitUser(New, "Internal error handling connection");
}
- /* NOTE: even if dns lookups are *off*, we still need to display this.
- * BOPM and other stuff requires it.
- */
- New->WriteServ("NOTICE Auth :*** Looking up your hostname...");
if (ServerInstance->Config->RawLog)
- New->WriteServ("NOTICE Auth :*** Raw I/O logging is enabled on this server. All messages, passwords, and commands are being recorded.");
+ New->WriteNotice("*** Raw I/O logging is enabled on this server. All messages, passwords, and commands are being recorded.");
- FOREACH_MOD(I_OnSetUserIP,OnSetUserIP(New));
+ FOREACH_MOD(OnSetUserIP, (New));
if (New->quitting)
return;
- FOREACH_MOD(I_OnUserInit,OnUserInit(New));
-
- if (ServerInstance->Config->NoUserDns)
- {
- New->WriteServ("NOTICE %s :*** Skipping host resolution (disabled by server administrator)", New->nick.c_str());
- New->dns_done = true;
- }
- else
- {
- New->StartDNSLookup();
- }
+ FOREACH_MOD(OnUserInit, (New));
}
-void UserManager::QuitUser(User *user, const std::string &quitreason, const char* operreason)
+void UserManager::QuitUser(User* user, const std::string& quitreason, const std::string* operreason)
{
if (user->quitting)
{
- ServerInstance->Logs->Log("USERS", DEFAULT, "ERROR: Tried to quit quitting user: " + user->nick);
+ ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "ERROR: Tried to quit quitting user: " + user->nick);
return;
}
if (IS_SERVER(user))
{
- ServerInstance->Logs->Log("USERS", DEFAULT, "ERROR: Tried to quit server user: " + user->nick);
+ ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "ERROR: Tried to quit server user: " + user->nick);
return;
}
user->quitting = true;
- ServerInstance->Logs->Log("USERS", DEBUG, "QuitUser: %s=%s '%s'", user->uuid.c_str(), user->nick.c_str(), quitreason.c_str());
- user->Write("ERROR :Closing link: (%s@%s) [%s]", user->ident.c_str(), user->host.c_str(), *operreason ? operreason : quitreason.c_str());
+ ServerInstance->Logs->Log("USERS", LOG_DEBUG, "QuitUser: %s=%s '%s'", user->uuid.c_str(), user->nick.c_str(), quitreason.c_str());
+ user->Write("ERROR :Closing link: (%s@%s) [%s]", user->ident.c_str(), user->host.c_str(), operreason ? operreason->c_str() : quitreason.c_str());
std::string reason;
- std::string oper_reason;
reason.assign(quitreason, 0, ServerInstance->Config->Limits.MaxQuit);
- if (operreason && *operreason)
- oper_reason.assign(operreason, 0, ServerInstance->Config->Limits.MaxQuit);
- else
- oper_reason = quitreason;
+ if (!operreason)
+ operreason = &reason;
ServerInstance->GlobalCulls.AddItem(user);
if (user->registered == REG_ALL)
{
- FOREACH_MOD(I_OnUserQuit,OnUserQuit(user, reason, oper_reason));
- user->WriteCommonQuit(reason, oper_reason);
+ FOREACH_MOD(OnUserQuit, (user, reason, *operreason));
+ user->WriteCommonQuit(reason, *operreason);
}
-
- if (user->registered != REG_ALL)
- if (ServerInstance->Users->unregistered_count)
- ServerInstance->Users->unregistered_count--;
+ else
+ unregistered_count--;
if (IS_LOCAL(user))
{
LocalUser* lu = IS_LOCAL(user);
- FOREACH_MOD(I_OnUserDisconnect,OnUserDisconnect(lu));
+ FOREACH_MOD(OnUserDisconnect, (lu));
lu->eh.Close();
- }
- /*
- * this must come before the ServerInstance->SNO->WriteToSnoMaskso that it doesnt try to fill their buffer with anything
- * if they were an oper with +s +qQ.
- */
- if (user->registered == REG_ALL)
- {
- if (IS_LOCAL(user))
- {
- if (!user->quietquit)
- {
- ServerInstance->SNO->WriteToSnoMask('q',"Client exiting: %s (%s) [%s]",
- user->GetFullRealHost().c_str(), user->GetIPString(), oper_reason.c_str());
- }
- }
- else
- {
- if ((!ServerInstance->SilentULine(user->server)) && (!user->quietquit))
- {
- ServerInstance->SNO->WriteToSnoMask('Q',"Client exiting on server %s: %s (%s) [%s]",
- user->server.c_str(), user->GetFullRealHost().c_str(), user->GetIPString(), oper_reason.c_str());
- }
- }
- user->AddToWhoWas();
+ if (lu->registered == REG_ALL)
+ ServerInstance->SNO->WriteToSnoMask('q',"Client exiting: %s (%s) [%s]", user->GetFullRealHost().c_str(), user->GetIPString().c_str(), operreason->c_str());
+ local_users.erase(lu);
}
- user_hash::iterator iter = this->clientlist->find(user->nick);
+ if (!clientlist.erase(user->nick))
+ ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "ERROR: Nick not found in clientlist, cannot remove: " + user->nick);
- if (iter != this->clientlist->end())
- this->clientlist->erase(iter);
- else
- ServerInstance->Logs->Log("USERS", DEFAULT, "ERROR: Nick not found in clientlist, cannot remove: " + user->nick);
-
- ServerInstance->Users->uuidlist->erase(user->uuid);
-}
-
-
-void UserManager::AddLocalClone(User *user)
-{
- local_clones[user->GetCIDRMask()]++;
+ uuidlist.erase(user->uuid);
+ user->PurgeEmptyChannels();
}
-void UserManager::AddGlobalClone(User *user)
+void UserManager::AddClone(User* user)
{
- global_clones[user->GetCIDRMask()]++;
+ CloneCounts& counts = clonemap[user->GetCIDRMask()];
+ counts.global++;
+ if (IS_LOCAL(user))
+ counts.local++;
}
void UserManager::RemoveCloneCounts(User *user)
{
- if (IS_LOCAL(user))
+ CloneMap::iterator it = clonemap.find(user->GetCIDRMask());
+ if (it != clonemap.end())
{
- clonemap::iterator x = local_clones.find(user->GetCIDRMask());
- if (x != local_clones.end())
+ CloneCounts& counts = it->second;
+ counts.global--;
+ if (counts.global == 0)
{
- x->second--;
- if (!x->second)
- {
- local_clones.erase(x);
- }
+ // No more users from this IP, remove entry from the map
+ clonemap.erase(it);
+ return;
}
- }
- clonemap::iterator y = global_clones.find(user->GetCIDRMask());
- if (y != global_clones.end())
- {
- y->second--;
- if (!y->second)
- {
- global_clones.erase(y);
- }
+ if (IS_LOCAL(user))
+ counts.local--;
}
}
-unsigned long UserManager::GlobalCloneCount(User *user)
-{
- clonemap::iterator x = global_clones.find(user->GetCIDRMask());
- if (x != global_clones.end())
- return x->second;
- else
- return 0;
-}
-
-unsigned long UserManager::LocalCloneCount(User *user)
+const UserManager::CloneCounts& UserManager::GetCloneCounts(User* user) const
{
- clonemap::iterator x = local_clones.find(user->GetCIDRMask());
- if (x != local_clones.end())
- return x->second;
+ CloneMap::const_iterator it = clonemap.find(user->GetCIDRMask());
+ if (it != clonemap.end())
+ return it->second;
else
- return 0;
-}
-
-/* this function counts all users connected, wether they are registered or NOT. */
-unsigned int UserManager::UserCount()
-{
- /*
- * XXX: Todo:
- * As part of this restructuring, move clientlist/etc fields into usermanager.
- * -- w00t
- */
- return this->clientlist->size();
-}
-
-/* this counts only registered users, so that the percentages in /MAP don't mess up */
-unsigned int UserManager::RegisteredUserCount()
-{
- return this->clientlist->size() - this->UnregisteredUserCount();
-}
-
-/* return how many users are opered */
-unsigned int UserManager::OperCount()
-{
- return this->all_opers.size();
-}
-
-/* return how many users are unregistered */
-unsigned int UserManager::UnregisteredUserCount()
-{
- return this->unregistered_count;
-}
-
-/* return how many local registered users there are */
-unsigned int UserManager::LocalUserCount()
-{
- /* Doesnt count unregistered clients */
- return (this->local_count - this->UnregisteredUserCount());
+ return zeroclonecounts;
}
void UserManager::ServerNoticeAll(const char* text, ...)
{
- if (!text)
- return;
-
- char textbuffer[MAXBUF];
- char formatbuffer[MAXBUF];
- va_list argsPtr;
- va_start (argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
+ std::string message;
+ VAFORMAT(message, text, text);
+ message = "NOTICE $" + ServerInstance->Config->ServerName + " :" + message;
- snprintf(formatbuffer,MAXBUF,"NOTICE $%s :%s", ServerInstance->Config->ServerName.c_str(), textbuffer);
-
- for (LocalUserList::const_iterator i = local_users.begin(); i != local_users.end(); i++)
+ for (LocalList::const_iterator i = local_users.begin(); i != local_users.end(); ++i)
{
User* t = *i;
- t->WriteServ(std::string(formatbuffer));
+ t->WriteServ(message);
}
}
-void UserManager::ServerPrivmsgAll(const char* text, ...)
+void UserManager::GarbageCollect()
{
- if (!text)
- return;
-
- char textbuffer[MAXBUF];
- char formatbuffer[MAXBUF];
- va_list argsPtr;
- va_start (argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
-
- snprintf(formatbuffer,MAXBUF,"PRIVMSG $%s :%s", ServerInstance->Config->ServerName.c_str(), textbuffer);
-
- for (LocalUserList::const_iterator i = local_users.begin(); i != local_users.end(); i++)
+ // Reset the already_sent IDs so we don't wrap it around and drop a message
+ LocalUser::already_sent_id = 0;
+ for (LocalList::const_iterator i = local_users.begin(); i != local_users.end(); ++i)
{
- User* t = *i;
- t->WriteServ(std::string(formatbuffer));
+ (**i).already_sent = 0;
+ (**i).RemoveExpiredInvites();
}
}
+/* this returns true when all modules are satisfied that the user should be allowed onto the irc server
+ * (until this returns true, a user will block in the waiting state, waiting to connect up to the
+ * registration timeout maximum seconds)
+ */
+bool UserManager::AllModulesReportReady(LocalUser* user)
+{
+ ModResult res;
+ FIRST_MOD_RESULT(OnCheckReady, res, (user));
+ return (res == MOD_RES_PASSTHRU);
+}
-/* return how many users have a given mode e.g. 'a' */
-int UserManager::ModeCount(const char mode)
+/**
+ * This function is called once a second from the mainloop.
+ * It is intended to do background checking on all the user structs, e.g.
+ * stuff like ping checks, registration timeouts, etc.
+ */
+void UserManager::DoBackgroundUserStuff()
{
- int c = 0;
- for(user_hash::iterator i = clientlist->begin(); i != clientlist->end(); ++i)
+ /*
+ * loop over all local users..
+ */
+ for (LocalList::iterator i = local_users.begin(); i != local_users.end(); ++i)
{
- User* u = i->second;
- if (u->modes[mode-65])
- c++;
+ LocalUser* curr = *i;
+
+ if (curr->CommandFloodPenalty || curr->eh.getSendQSize())
+ {
+ unsigned int rate = curr->MyClass->GetCommandRate();
+ if (curr->CommandFloodPenalty > rate)
+ curr->CommandFloodPenalty -= rate;
+ else
+ curr->CommandFloodPenalty = 0;
+ curr->eh.OnDataReady();
+ }
+
+ switch (curr->registered)
+ {
+ case REG_ALL:
+ if (ServerInstance->Time() > curr->nping)
+ {
+ // This user didn't answer the last ping, remove them
+ if (!curr->lastping)
+ {
+ time_t time = ServerInstance->Time() - (curr->nping - curr->MyClass->GetPingTime());
+ const std::string message = "Ping timeout: " + ConvToStr(time) + (time != 1 ? " seconds" : " second");
+ this->QuitUser(curr, message);
+ continue;
+ }
+
+ curr->Write("PING :" + ServerInstance->Config->ServerName);
+ curr->lastping = 0;
+ curr->nping = ServerInstance->Time() + curr->MyClass->GetPingTime();
+ }
+ break;
+ case REG_NICKUSER:
+ if (AllModulesReportReady(curr))
+ {
+ /* User has sent NICK/USER, modules are okay, DNS finished. */
+ curr->FullConnect();
+ continue;
+ }
+ break;
+ }
+
+ if (curr->registered != REG_ALL && (ServerInstance->Time() > (curr->age + curr->MyClass->GetRegTimeout())))
+ {
+ /*
+ * registration timeout -- didnt send USER/NICK/HOST
+ * in the time specified in their connection class.
+ */
+ this->QuitUser(curr, "Registration timeout");
+ continue;
+ }
}
- return c;
}
diff --git a/src/userprocess.cpp b/src/userprocess.cpp
deleted file mode 100644
index 9cc2e7df7..000000000
--- a/src/userprocess.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2006-2008 Robin Burchell <robin+git@viroteck.net>
- * Copyright (C) 2005-2007 Craig Edwards <craigedwards@brainbox.cc>
- * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
- * Copyright (C) 2006 Craig McLure <craig@chatspike.net>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-/* $Core */
-
-#include "inspircd.h"
-#include "xline.h"
-#include "socketengine.h"
-#include "command_parse.h"
-
-void FloodQuitUserHandler::Call(User* current)
-{
- ServerInstance->Logs->Log("USERS",DEFAULT,"Excess flood from: %s@%s", current->ident.c_str(), current->host.c_str());
- ServerInstance->SNO->WriteToSnoMask('f',"Excess flood from: %s%s%s@%s",
- current->registered == REG_ALL ? current->nick.c_str() : "",
- current->registered == REG_ALL ? "!" : "", current->ident.c_str(), current->host.c_str());
- ServerInstance->Users->QuitUser(current, "Excess flood");
-
- if (current->registered != REG_ALL)
- {
- ZLine* zl = new ZLine(ServerInstance->Time(), 0, ServerInstance->Config->ServerName, "Flood from unregistered connection", current->GetIPString());
- if (ServerInstance->XLines->AddLine(zl,NULL))
- ServerInstance->XLines->ApplyLines();
- else
- delete zl;
- }
-}
-
-/**
- * This function is called once a second from the mainloop.
- * It is intended to do background checking on all the user structs, e.g.
- * stuff like ping checks, registration timeouts, etc.
- */
-void InspIRCd::DoBackgroundUserStuff()
-{
- /*
- * loop over all local users..
- */
- LocalUserList::reverse_iterator count2 = this->Users->local_users.rbegin();
- while (count2 != this->Users->local_users.rend())
- {
- LocalUser *curr = *count2;
- count2++;
-
- if (curr->quitting)
- continue;
-
- if (curr->CommandFloodPenalty || curr->eh.getSendQSize())
- {
- unsigned int rate = curr->MyClass->GetCommandRate();
- if (curr->CommandFloodPenalty > rate)
- curr->CommandFloodPenalty -= rate;
- else
- curr->CommandFloodPenalty = 0;
- curr->eh.OnDataReady();
- }
-
- switch (curr->registered)
- {
- case REG_ALL:
- if (Time() > curr->nping)
- {
- // This user didn't answer the last ping, remove them
- if (!curr->lastping)
- {
- time_t time = this->Time() - (curr->nping - curr->MyClass->GetPingTime());
- char message[MAXBUF];
- snprintf(message, MAXBUF, "Ping timeout: %ld second%s", (long)time, time > 1 ? "s" : "");
- curr->lastping = 1;
- curr->nping = Time() + curr->MyClass->GetPingTime();
- this->Users->QuitUser(curr, message);
- continue;
- }
-
- curr->Write("PING :%s",this->Config->ServerName.c_str());
- curr->lastping = 0;
- curr->nping = Time() +curr->MyClass->GetPingTime();
- }
- break;
- case REG_NICKUSER:
- if (AllModulesReportReady(curr) && curr->dns_done)
- {
- /* User has sent NICK/USER, modules are okay, DNS finished. */
- curr->FullConnect();
- continue;
- }
- break;
- }
-
- if (curr->registered != REG_ALL && (Time() > (curr->age + curr->MyClass->GetRegTimeout())))
- {
- /*
- * registration timeout -- didnt send USER/NICK/HOST
- * in the time specified in their connection class.
- */
- this->Users->QuitUser(curr, "Registration timeout");
- continue;
- }
- }
-}
-
diff --git a/src/users.cpp b/src/users.cpp
index 91db5200a..8d22d166c 100644
--- a/src/users.cpp
+++ b/src/users.cpp
@@ -24,112 +24,10 @@
#include "inspircd.h"
-#include <stdarg.h>
-#include "socketengine.h"
#include "xline.h"
-#include "bancache.h"
-#include "commands/cmd_whowas.h"
already_sent_t LocalUser::already_sent_id = 0;
-std::string User::ProcessNoticeMasks(const char *sm)
-{
- bool adding = true, oldadding = false;
- const char *c = sm;
- std::string output;
-
- while (c && *c)
- {
- switch (*c)
- {
- case '+':
- adding = true;
- break;
- case '-':
- adding = false;
- break;
- case '*':
- for (unsigned char d = 'a'; d <= 'z'; d++)
- {
- if (!ServerInstance->SNO->masks[d - 'a'].Description.empty())
- {
- if ((!IsNoticeMaskSet(d) && adding) || (IsNoticeMaskSet(d) && !adding))
- {
- if ((oldadding != adding) || (!output.length()))
- output += (adding ? '+' : '-');
-
- this->SetNoticeMask(d, adding);
-
- output += d;
- }
- oldadding = adding;
- char u = toupper(d);
- if ((!IsNoticeMaskSet(u) && adding) || (IsNoticeMaskSet(u) && !adding))
- {
- if ((oldadding != adding) || (!output.length()))
- output += (adding ? '+' : '-');
-
- this->SetNoticeMask(u, adding);
-
- output += u;
- }
- oldadding = adding;
- }
- }
- break;
- default:
- if (isalpha(*c))
- {
- if ((!IsNoticeMaskSet(*c) && adding) || (IsNoticeMaskSet(*c) && !adding))
- {
- if ((oldadding != adding) || (!output.length()))
- output += (adding ? '+' : '-');
-
- this->SetNoticeMask(*c, adding);
-
- output += *c;
- oldadding = adding;
- }
- }
- else
- this->WriteNumeric(ERR_UNKNOWNSNOMASK, "%s %c :is unknown snomask char to me", this->nick.c_str(), *c);
-
- break;
- }
-
- c++;
- }
-
- std::string s = this->FormatNoticeMasks();
- if (s.length() == 0)
- {
- this->modes[UM_SNOMASK] = false;
- }
-
- return output;
-}
-
-void LocalUser::StartDNSLookup()
-{
- try
- {
- bool cached = false;
- const char* sip = this->GetIPString();
- UserResolver *res_reverse;
-
- QueryType resolvtype = this->client_sa.sa.sa_family == AF_INET6 ? DNS_QUERY_PTR6 : DNS_QUERY_PTR4;
- res_reverse = new UserResolver(this, sip, resolvtype, cached);
-
- ServerInstance->AddResolver(res_reverse, cached);
- }
- catch (CoreException& e)
- {
- ServerInstance->Logs->Log("USERS", DEBUG,"Error in resolver: %s",e.GetReason());
- dns_done = true;
- ServerInstance->stats->statsDnsBad++;
- }
-}
-
bool User::IsNoticeMaskSet(unsigned char sm)
{
if (!isalpha(sm))
@@ -137,55 +35,25 @@ bool User::IsNoticeMaskSet(unsigned char sm)
return (snomasks[sm-65]);
}
-void User::SetNoticeMask(unsigned char sm, bool value)
-{
- if (!isalpha(sm))
- return;
- snomasks[sm-65] = value;
-}
-
-const char* User::FormatNoticeMasks()
-{
- static char data[MAXBUF];
- int offset = 0;
-
- for (int n = 0; n < 64; n++)
- {
- if (snomasks[n])
- data[offset++] = n+65;
- }
-
- data[offset] = 0;
- return data;
-}
-
bool User::IsModeSet(unsigned char m)
{
- if (!isalpha(m))
- return false;
- return (modes[m-65]);
-}
-
-void User::SetMode(unsigned char m, bool value)
-{
- if (!isalpha(m))
- return;
- modes[m-65] = value;
+ ModeHandler* mh = ServerInstance->Modes->FindMode(m, MODETYPE_USER);
+ return (mh && modes[mh->GetId()]);
}
const char* User::FormatModes(bool showparameters)
{
- static char data[MAXBUF];
+ static std::string data;
std::string params;
- int offset = 0;
+ data.clear();
for (unsigned char n = 0; n < 64; n++)
{
- if (modes[n])
+ ModeHandler* mh = ServerInstance->Modes->FindMode(n + 65, MODETYPE_USER);
+ if (mh && IsModeSet(mh))
{
- data[offset++] = n + 65;
- ModeHandler* mh = ServerInstance->Modes->FindMode(n + 65, MODETYPE_USER);
- if (showparameters && mh && mh->GetNumParams(true))
+ data.push_back(n + 65);
+ if (showparameters && mh->GetNumParams(true))
{
std::string p = mh->GetUserParameter(this);
if (p.length())
@@ -193,36 +61,32 @@ const char* User::FormatModes(bool showparameters)
}
}
}
- data[offset] = 0;
- strlcat(data, params.c_str(), MAXBUF);
- return data;
+ data += params;
+ return data.c_str();
}
-User::User(const std::string &uid, const std::string& sid, int type)
- : uuid(uid), server(sid), usertype(type)
+User::User(const std::string& uid, Server* srv, int type)
+ : uuid(uid), server(srv), usertype(type)
{
age = ServerInstance->Time();
- signon = idle_lastmsg = 0;
+ signon = 0;
registered = 0;
- quietquit = quitting = exempt = dns_done = false;
- quitting_sendq = false;
+ quitting = false;
client_sa.sa.sa_family = AF_UNSPEC;
- ServerInstance->Logs->Log("USERS", DEBUG, "New UUID for user: %s", uuid.c_str());
+ ServerInstance->Logs->Log("USERS", LOG_DEBUG, "New UUID for user: %s", uuid.c_str());
- user_hash::iterator finduuid = ServerInstance->Users->uuidlist->find(uuid);
- if (finduuid == ServerInstance->Users->uuidlist->end())
- (*ServerInstance->Users->uuidlist)[uuid] = this;
- else
+ if (!ServerInstance->Users->uuidlist.insert(std::make_pair(uuid, this)).second)
throw CoreException("Duplicate UUID "+std::string(uuid)+" in User constructor");
}
LocalUser::LocalUser(int myfd, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* servaddr)
- : User(ServerInstance->GetUID(), ServerInstance->Config->ServerName, USERTYPE_LOCAL), eh(this),
- localuseriter(ServerInstance->Users->local_users.end()),
+ : User(ServerInstance->UIDGen.GetUID(), ServerInstance->FakeClient->server, USERTYPE_LOCAL), eh(this),
bytes_in(0), bytes_out(0), cmds_in(0), cmds_out(0), nping(0), CommandFloodPenalty(0),
already_sent(0)
{
+ exempt = quitting_sendq = false;
+ idle_lastmsg = 0;
ident = "unknown";
lastping = 0;
eh.SetFd(myfd);
@@ -233,8 +97,8 @@ LocalUser::LocalUser(int myfd, irc::sockets::sockaddrs* client, irc::sockets::so
User::~User()
{
- if (ServerInstance->Users->uuidlist->find(uuid) != ServerInstance->Users->uuidlist->end())
- ServerInstance->Logs->Log("USERS", DEFAULT, "User destructor for %s called without cull", uuid.c_str());
+ if (ServerInstance->FindUUID(uuid))
+ ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "User destructor for %s called without cull", uuid.c_str());
}
const std::string& User::MakeHost()
@@ -242,18 +106,8 @@ const std::string& User::MakeHost()
if (!this->cached_makehost.empty())
return this->cached_makehost;
- char nhost[MAXBUF];
- /* This is much faster than snprintf */
- char* t = nhost;
- for(const char* n = ident.c_str(); *n; n++)
- *t++ = *n;
- *t++ = '@';
- for(const char* n = host.c_str(); *n; n++)
- *t++ = *n;
- *t = 0;
-
- this->cached_makehost.assign(nhost);
-
+ // XXX: Is there really a need to cache this?
+ this->cached_makehost = ident + "@" + host;
return this->cached_makehost;
}
@@ -262,18 +116,8 @@ const std::string& User::MakeHostIP()
if (!this->cached_hostip.empty())
return this->cached_hostip;
- char ihost[MAXBUF];
- /* This is much faster than snprintf */
- char* t = ihost;
- for(const char* n = ident.c_str(); *n; n++)
- *t++ = *n;
- *t++ = '@';
- for(const char* n = this->GetIPString(); *n; n++)
- *t++ = *n;
- *t = 0;
-
- this->cached_hostip = ihost;
-
+ // XXX: Is there really a need to cache this?
+ this->cached_hostip = ident + "@" + this->GetIPString();
return this->cached_hostip;
}
@@ -282,91 +126,36 @@ const std::string& User::GetFullHost()
if (!this->cached_fullhost.empty())
return this->cached_fullhost;
- char result[MAXBUF];
- char* t = result;
- for(const char* n = nick.c_str(); *n; n++)
- *t++ = *n;
- *t++ = '!';
- for(const char* n = ident.c_str(); *n; n++)
- *t++ = *n;
- *t++ = '@';
- for(const char* n = dhost.c_str(); *n; n++)
- *t++ = *n;
- *t = 0;
-
- this->cached_fullhost = result;
-
+ // XXX: Is there really a need to cache this?
+ this->cached_fullhost = nick + "!" + ident + "@" + dhost;
return this->cached_fullhost;
}
-char* User::MakeWildHost()
-{
- static char nresult[MAXBUF];
- char* t = nresult;
- *t++ = '*'; *t++ = '!';
- *t++ = '*'; *t++ = '@';
- for(const char* n = dhost.c_str(); *n; n++)
- *t++ = *n;
- *t = 0;
- return nresult;
-}
-
const std::string& User::GetFullRealHost()
{
if (!this->cached_fullrealhost.empty())
return this->cached_fullrealhost;
- char fresult[MAXBUF];
- char* t = fresult;
- for(const char* n = nick.c_str(); *n; n++)
- *t++ = *n;
- *t++ = '!';
- for(const char* n = ident.c_str(); *n; n++)
- *t++ = *n;
- *t++ = '@';
- for(const char* n = host.c_str(); *n; n++)
- *t++ = *n;
- *t = 0;
-
- this->cached_fullrealhost = fresult;
-
+ // XXX: Is there really a need to cache this?
+ this->cached_fullrealhost = nick + "!" + ident + "@" + host;
return this->cached_fullrealhost;
}
-bool LocalUser::IsInvited(const irc::string &channel)
-{
- Channel* chan = ServerInstance->FindChan(channel.c_str());
- if (!chan)
- return false;
-
- return (Invitation::Find(chan, this) != NULL);
-}
-
InviteList& LocalUser::GetInviteList()
{
RemoveExpiredInvites();
return invites;
}
-void LocalUser::InviteTo(const irc::string &channel, time_t invtimeout)
-{
- Channel* chan = ServerInstance->FindChan(channel.c_str());
- if (chan)
- Invitation::Create(chan, this, invtimeout);
-}
-
-void LocalUser::RemoveInvite(const irc::string &channel)
+bool LocalUser::RemoveInvite(Channel* chan)
{
- Channel* chan = ServerInstance->FindChan(channel.c_str());
- if (chan)
+ Invitation* inv = Invitation::Find(chan, this);
+ if (inv)
{
- Invitation* inv = Invitation::Find(chan, this);
- if (inv)
- {
- inv->cull();
- delete inv;
- }
+ delete inv;
+ return true;
}
+ return false;
}
void LocalUser::RemoveExpiredInvites()
@@ -381,7 +170,7 @@ bool User::HasModePermission(unsigned char, ModeType)
bool LocalUser::HasModePermission(unsigned char mode, ModeType type)
{
- if (!IS_OPER(this))
+ if (!this->IsOper())
return false;
if (mode < 'A' || mode > ('A' + 64)) return false;
@@ -404,7 +193,7 @@ bool User::HasPermission(const std::string&)
bool LocalUser::HasPermission(const std::string &command)
{
// are they even an oper at all?
- if (!IS_OPER(this))
+ if (!this->IsOper())
{
return false;
}
@@ -424,10 +213,10 @@ bool User::HasPrivPermission(const std::string &privstr, bool noisy)
bool LocalUser::HasPrivPermission(const std::string &privstr, bool noisy)
{
- if (!IS_OPER(this))
+ if (!this->IsOper())
{
if (noisy)
- this->WriteServ("NOTICE %s :You are not an oper", this->nick.c_str());
+ this->WriteNotice("You are not an oper");
return false;
}
@@ -441,7 +230,8 @@ bool LocalUser::HasPrivPermission(const std::string &privstr, bool noisy)
}
if (noisy)
- this->WriteServ("NOTICE %s :Oper type %s does not have access to priv %s", this->nick.c_str(), oper->NameStr(), privstr.c_str());
+ this->WriteNotice("Oper type " + oper->name + " does not have access to priv " + privstr);
+
return false;
}
@@ -467,7 +257,7 @@ void UserIOHandler::OnDataReady()
while (user->CommandFloodPenalty < penaltymax && getSendQSize() < sendqmax)
{
std::string line;
- line.reserve(MAXBUF);
+ line.reserve(ServerInstance->Config->Limits.MaxLine);
std::string::size_type qpos = 0;
while (qpos < recvq.length())
{
@@ -482,7 +272,7 @@ void UserIOHandler::OnDataReady()
case '\n':
goto eol_found;
}
- if (line.length() < MAXBUF - 2)
+ if (line.length() < ServerInstance->Config->Limits.MaxLine - 2)
line.push_back(c);
}
// if we got here, the recvq ran out before we found a newline
@@ -492,11 +282,11 @@ eol_found:
recvq = recvq.substr(qpos);
// TODO should this be moved to when it was inserted in recvq?
- ServerInstance->stats->statsRecv += qpos;
+ ServerInstance->stats.Recv += qpos;
user->bytes_in += qpos;
user->cmds_in++;
- ServerInstance->Parser->ProcessBuffer(line, user);
+ ServerInstance->Parser.ProcessBuffer(line, user);
if (user->quitting)
return;
}
@@ -531,7 +321,6 @@ CullResult User::cull()
{
if (!quitting)
ServerInstance->Users->QuitUser(this, "Culled without QuitUser");
- PurgeEmptyChannels();
if (client_sa.sa.sa_family != AF_UNSPEC)
ServerInstance->Users->RemoveCloneCounts(this);
@@ -541,17 +330,6 @@ CullResult User::cull()
CullResult LocalUser::cull()
{
- // The iterator is initialized to local_users.end() in the constructor. It is
- // overwritten in UserManager::AddUser() with the real iterator so this check
- // is only a precaution currently.
- if (localuseriter != ServerInstance->Users->local_users.end())
- {
- ServerInstance->Users->local_count--;
- ServerInstance->Users->local_users.erase(localuseriter);
- }
- else
- ServerInstance->Logs->Log("USERS", DEFAULT, "ERROR: LocalUserIter does not point to a valid entry for " + this->nick);
-
ClearInvites();
eh.cull();
return User::cull();
@@ -561,20 +339,21 @@ CullResult FakeUser::cull()
{
// Fake users don't quit, they just get culled.
quitting = true;
- ServerInstance->Users->clientlist->erase(nick);
- ServerInstance->Users->uuidlist->erase(uuid);
+ // Fake users are not inserted into UserManager::clientlist, they're only in the uuidlist
+ ServerInstance->Users->uuidlist.erase(uuid);
return User::cull();
}
void User::Oper(OperInfo* info)
{
- if (this->IsModeSet('o'))
+ ModeHandler* opermh = ServerInstance->Modes->FindMode('o', MODETYPE_USER);
+ if (this->IsModeSet(opermh))
this->UnOper();
- this->modes[UM_OPERATOR] = 1;
+ this->SetMode(opermh, true);
this->oper = info;
- this->WriteServ("MODE %s :+o", this->nick.c_str());
- FOREACH_MOD(I_OnOper, OnOper(this, info->name));
+ this->WriteCommand("MODE", "+o");
+ FOREACH_MOD(OnOper, (this, info->name));
std::string opername;
if (info->oper_block)
@@ -592,17 +371,17 @@ void User::Oper(OperInfo* info)
}
ServerInstance->SNO->WriteToSnoMask('o',"%s (%s@%s) is now an IRC operator of type %s (using oper '%s')",
- nick.c_str(), ident.c_str(), host.c_str(), oper->NameStr(), opername.c_str());
- this->WriteNumeric(381, "%s :You are now %s %s", nick.c_str(), strchr("aeiouAEIOU", oper->name[0]) ? "an" : "a", oper->NameStr());
+ nick.c_str(), ident.c_str(), host.c_str(), oper->name.c_str(), opername.c_str());
+ this->WriteNumeric(RPL_YOUAREOPER, ":You are now %s %s", strchr("aeiouAEIOU", oper->name[0]) ? "an" : "a", oper->name.c_str());
- ServerInstance->Logs->Log("OPER", DEFAULT, "%s opered as type: %s", GetFullRealHost().c_str(), oper->NameStr());
+ ServerInstance->Logs->Log("OPER", LOG_DEFAULT, "%s opered as type: %s", GetFullRealHost().c_str(), oper->name.c_str());
ServerInstance->Users->all_opers.push_back(this);
// Expand permissions from config for faster lookup
if (IS_LOCAL(this))
oper->init();
- FOREACH_MOD(I_OnPostOper,OnPostOper(this, oper->name, opername));
+ FOREACH_MOD(OnPostOper, (this, oper->name, opername));
}
void OperInfo::init()
@@ -660,7 +439,7 @@ void OperInfo::init()
void User::UnOper()
{
- if (!IS_OPER(this))
+ if (!this->IsOper())
return;
/*
@@ -686,30 +465,19 @@ void User::UnOper()
parameters.push_back(this->nick);
parameters.push_back(moderemove);
- ServerInstance->Parser->CallHandler("MODE", parameters, this);
+ ServerInstance->Modes->Process(parameters, this);
- /* remove the user from the oper list. Will remove multiple entries as a safeguard against bug #404 */
- ServerInstance->Users->all_opers.remove(this);
-
- this->modes[UM_OPERATOR] = 0;
-}
+ // Remove the user from the oper list
+ stdalgo::vector::swaperase(ServerInstance->Users->all_opers, this);
-/* adds or updates an entry in the whowas list */
-void User::AddToWhoWas()
-{
- Module* whowas = ServerInstance->Modules->Find("cmd_whowas.so");
- if (whowas)
- {
- WhowasRequest req(NULL, whowas, WhowasRequest::WHOWAS_ADD);
- req.user = this;
- req.Send();
- }
+ ModeHandler* opermh = ServerInstance->Modes->FindMode('o', MODETYPE_USER);
+ this->SetMode(opermh, false);
}
/*
* Check class restrictions
*/
-void LocalUser::CheckClass()
+void LocalUser::CheckClass(bool clone_count)
{
ConnectClass* a = this->MyClass;
@@ -723,25 +491,29 @@ void LocalUser::CheckClass()
ServerInstance->Users->QuitUser(this, a->config->getString("reason", "Unauthorised connection"));
return;
}
- else if ((a->GetMaxLocal()) && (ServerInstance->Users->LocalCloneCount(this) > a->GetMaxLocal()))
+ else if (clone_count)
{
- ServerInstance->Users->QuitUser(this, "No more connections allowed from your host via this connect class (local)");
- if (a->maxconnwarn)
- ServerInstance->SNO->WriteToSnoMask('a', "WARNING: maximum LOCAL connections (%ld) exceeded for IP %s", a->GetMaxLocal(), this->GetIPString());
- return;
- }
- else if ((a->GetMaxGlobal()) && (ServerInstance->Users->GlobalCloneCount(this) > a->GetMaxGlobal()))
- {
- ServerInstance->Users->QuitUser(this, "No more connections allowed from your host via this connect class (global)");
- if (a->maxconnwarn)
- ServerInstance->SNO->WriteToSnoMask('a', "WARNING: maximum GLOBAL connections (%ld) exceeded for IP %s", a->GetMaxGlobal(), this->GetIPString());
- return;
+ const UserManager::CloneCounts& clonecounts = ServerInstance->Users->GetCloneCounts(this);
+ if ((a->GetMaxLocal()) && (clonecounts.local > a->GetMaxLocal()))
+ {
+ ServerInstance->Users->QuitUser(this, "No more connections allowed from your host via this connect class (local)");
+ if (a->maxconnwarn)
+ ServerInstance->SNO->WriteToSnoMask('a', "WARNING: maximum LOCAL connections (%ld) exceeded for IP %s", a->GetMaxLocal(), this->GetIPString().c_str());
+ return;
+ }
+ else if ((a->GetMaxGlobal()) && (clonecounts.global > a->GetMaxGlobal()))
+ {
+ ServerInstance->Users->QuitUser(this, "No more connections allowed from your host via this connect class (global)");
+ if (a->maxconnwarn)
+ ServerInstance->SNO->WriteToSnoMask('a', "WARNING: maximum GLOBAL connections (%ld) exceeded for IP %s", a->GetMaxGlobal(), this->GetIPString().c_str());
+ return;
+ }
}
this->nping = ServerInstance->Time() + a->GetPingTime() + ServerInstance->Config->dns_timeout;
}
-bool User::CheckLines(bool doZline)
+bool LocalUser::CheckLines(bool doZline)
{
const char* check[] = { "G" , "K", (doZline) ? "Z" : NULL, NULL };
@@ -764,7 +536,7 @@ bool User::CheckLines(bool doZline)
void LocalUser::FullConnect()
{
- ServerInstance->stats->statsConnects++;
+ ServerInstance->stats.Connects++;
this->idle_lastmsg = ServerInstance->Time();
/*
@@ -781,19 +553,14 @@ void LocalUser::FullConnect()
if (quitting)
return;
- if (ServerInstance->Config->WelcomeNotice)
- this->WriteServ("NOTICE Auth :Welcome to \002%s\002!",ServerInstance->Config->Network.c_str());
- this->WriteNumeric(RPL_WELCOME, "%s :Welcome to the %s IRC Network %s",this->nick.c_str(), ServerInstance->Config->Network.c_str(), GetFullRealHost().c_str());
- this->WriteNumeric(RPL_YOURHOSTIS, "%s :Your host is %s, running version %s",this->nick.c_str(),ServerInstance->Config->ServerName.c_str(),BRANCH);
- this->WriteNumeric(RPL_SERVERCREATED, "%s :This server was created %s %s", this->nick.c_str(), __TIME__, __DATE__);
+ this->WriteNumeric(RPL_WELCOME, ":Welcome to the %s IRC Network %s", ServerInstance->Config->Network.c_str(), GetFullRealHost().c_str());
+ this->WriteNumeric(RPL_YOURHOSTIS, ":Your host is %s, running version %s", ServerInstance->Config->ServerName.c_str(), INSPIRCD_BRANCH);
+ this->WriteNumeric(RPL_SERVERCREATED, ":This server was created %s %s", __TIME__, __DATE__);
- std::string umlist = ServerInstance->Modes->UserModeList();
- std::string cmlist = ServerInstance->Modes->ChannelModeList();
- std::string pmlist = ServerInstance->Modes->ParaModeList();
- this->WriteNumeric(RPL_SERVERVERSION, "%s %s %s %s %s %s", this->nick.c_str(), ServerInstance->Config->ServerName.c_str(), BRANCH, umlist.c_str(), cmlist.c_str(), pmlist.c_str());
+ const std::string& modelist = ServerInstance->Modes->GetModeListFor004Numeric();
+ this->WriteNumeric(RPL_SERVERVERSION, "%s %s %s", ServerInstance->Config->ServerName.c_str(), INSPIRCD_BRANCH, modelist.c_str());
- ServerInstance->Config->Send005(this);
- this->WriteNumeric(RPL_YOURUUID, "%s %s :your unique ID", this->nick.c_str(), this->uuid.c_str());
+ ServerInstance->ISupport.SendTo(this);
/* Now registered */
if (ServerInstance->Users->unregistered_count)
@@ -801,17 +568,17 @@ void LocalUser::FullConnect()
/* Trigger MOTD and LUSERS output, give modules a chance too */
ModResult MOD_RESULT;
- std::string command("MOTD");
+ std::string command("LUSERS");
std::vector<std::string> parameters;
FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, parameters, this, true, command));
if (!MOD_RESULT)
- ServerInstance->Parser->CallHandler(command, parameters, this);
+ ServerInstance->Parser.CallHandler(command, parameters, this);
MOD_RESULT = MOD_RES_PASSTHRU;
- command = "LUSERS";
+ command = "MOTD";
FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, parameters, this, true, command));
if (!MOD_RESULT)
- ServerInstance->Parser->CallHandler(command, parameters, this);
+ ServerInstance->Parser.CallHandler(command, parameters, this);
if (ServerInstance->Config->RawLog)
WriteServ("PRIVMSG %s :*** Raw I/O logging is enabled on this server. All messages, passwords, and commands are being recorded.", nick.c_str());
@@ -820,16 +587,16 @@ void LocalUser::FullConnect()
* We don't set REG_ALL until triggering OnUserConnect, so some module events don't spew out stuff
* for a user that doesn't exist yet.
*/
- FOREACH_MOD(I_OnUserConnect,OnUserConnect(this));
+ FOREACH_MOD(OnUserConnect, (this));
this->registered = REG_ALL;
- FOREACH_MOD(I_OnPostConnect,OnPostConnect(this));
+ FOREACH_MOD(OnPostConnect, (this));
ServerInstance->SNO->WriteToSnoMask('c',"Client connecting on port %d (class %s): %s (%s) [%s]",
- this->GetServerPort(), this->MyClass->name.c_str(), GetFullRealHost().c_str(), this->GetIPString(), this->fullname.c_str());
- ServerInstance->Logs->Log("BANCACHE", DEBUG, "BanCache: Adding NEGATIVE hit for %s", this->GetIPString());
- ServerInstance->BanCache->AddHit(this->GetIPString(), "", "");
+ this->GetServerPort(), this->MyClass->name.c_str(), GetFullRealHost().c_str(), this->GetIPString().c_str(), this->fullname.c_str());
+ ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "BanCache: Adding NEGATIVE hit for " + this->GetIPString());
+ ServerInstance->BanCache.AddHit(this->GetIPString(), "", "");
// reset the flood penalty (which could have been raised due to things like auto +x)
CommandFloodPenalty = 0;
}
@@ -843,73 +610,26 @@ void User::InvalidateCache()
cached_fullrealhost.clear();
}
-bool User::ChangeNick(const std::string& newnick, bool force)
+bool User::ChangeNick(const std::string& newnick, time_t newts)
{
if (quitting)
{
- ServerInstance->Logs->Log("USERS", DEFAULT, "ERROR: Attempted to change nick of a quitting user: " + this->nick);
+ ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "ERROR: Attempted to change nick of a quitting user: " + this->nick);
return false;
}
- ModResult MOD_RESULT;
-
- if (force)
- ServerInstance->NICKForced.set(this, 1);
- FIRST_MOD_RESULT(OnUserPreNick, MOD_RESULT, (this, newnick));
- ServerInstance->NICKForced.set(this, 0);
-
- if (MOD_RESULT == MOD_RES_DENY)
+ User* const InUse = ServerInstance->FindNickOnly(newnick);
+ if (InUse == this)
{
- ServerInstance->stats->statsCollisions++;
- return false;
- }
-
- if (assign(newnick) == assign(nick))
- {
- // case change, don't need to check Q:lines and such
+ // case change, don't need to check campers
// and, if it's identical including case, we can leave right now
+ // We also don't update the nick TS if it's a case change, either
if (newnick == nick)
return true;
}
else
{
/*
- * Don't check Q:Lines if it's a server-enforced change, just on the off-chance some fucking *moron*
- * tries to Q:Line SIDs, also, this means we just get our way period, as it really should be.
- * Thanks Kein for finding this. -- w00t
- *
- * Also don't check Q:Lines for remote nickchanges, they should have our Q:Lines anyway to enforce themselves.
- * -- w00t
- */
- if (IS_LOCAL(this) && !force)
- {
- XLine* mq = ServerInstance->XLines->MatchesLine("Q",newnick);
- if (mq)
- {
- if (this->registered == REG_ALL)
- {
- ServerInstance->SNO->WriteGlobalSno('a', "Q-Lined nickname %s from %s: %s",
- newnick.c_str(), GetFullRealHost().c_str(), mq->reason.c_str());
- }
- this->WriteNumeric(432, "%s %s :Invalid nickname: %s",this->nick.c_str(), newnick.c_str(), mq->reason.c_str());
- return false;
- }
-
- if (ServerInstance->Config->RestrictBannedUsers)
- {
- for (UCListIter i = this->chans.begin(); i != this->chans.end(); i++)
- {
- Channel *chan = *i;
- if (chan->GetPrefixValue(this) < VOICE_VALUE && chan->IsBanned(this))
- {
- this->WriteNumeric(404, "%s %s :Cannot send to channel (you're banned)", this->nick.c_str(), chan->name.c_str());
- return false;
- }
- }
- }
- }
-
- /*
* Uh oh.. if the nickname is in use, and it's not in use by the person using it (doh) --
* then we have a potential collide. Check whether someone else is camping on the nick
* (i.e. connect -> send NICK, don't send USER.) If they are camping, force-change the
@@ -918,29 +638,26 @@ bool User::ChangeNick(const std::string& newnick, bool force)
* If the guy using the nick is already using it, tell the incoming nick change to gtfo,
* because the nick is already (rightfully) in use. -- w00t
*/
- User* InUse = ServerInstance->FindNickOnly(newnick);
- if (InUse && (InUse != this))
+ if (InUse)
{
if (InUse->registered != REG_ALL)
{
/* force the camper to their UUID, and ask them to re-send a NICK. */
- InUse->WriteTo(InUse, "NICK %s", InUse->uuid.c_str());
- InUse->WriteNumeric(433, "%s %s :Nickname overruled.", InUse->nick.c_str(), InUse->nick.c_str());
-
- ServerInstance->Users->clientlist->erase(InUse->nick);
- (*(ServerInstance->Users->clientlist))[InUse->uuid] = InUse;
+ InUse->WriteFrom(InUse, "NICK %s", InUse->uuid.c_str());
+ InUse->WriteNumeric(ERR_NICKNAMEINUSE, "%s :Nickname overruled.", InUse->nick.c_str());
- InUse->nick = InUse->uuid;
- InUse->InvalidateCache();
InUse->registered &= ~REG_NICK;
+ InUse->ChangeNick(InUse->uuid);
}
else
{
/* No camping, tell the incoming user to stop trying to change nick ;p */
- this->WriteNumeric(433, "%s %s :Nickname is already in use.", this->registered >= REG_NICK ? this->nick.c_str() : "*", newnick.c_str());
+ this->WriteNumeric(ERR_NICKNAMEINUSE, "%s :Nickname is already in use.", newnick.c_str());
return false;
}
}
+
+ age = newts ? newts : ServerInstance->Time();
}
if (this->registered == REG_ALL)
@@ -949,11 +666,11 @@ bool User::ChangeNick(const std::string& newnick, bool force)
nick = newnick;
InvalidateCache();
- ServerInstance->Users->clientlist->erase(oldnick);
- (*(ServerInstance->Users->clientlist))[newnick] = this;
+ ServerInstance->Users->clientlist.erase(oldnick);
+ ServerInstance->Users->clientlist[newnick] = this;
if (registered == REG_ALL)
- FOREACH_MOD(I_OnUserPostNick,OnUserPostNick(this,oldnick));
+ FOREACH_MOD(OnUserPostNick, (this,oldnick));
return true;
}
@@ -970,18 +687,18 @@ int LocalUser::GetServerPort()
return 0;
}
-const char* User::GetIPString()
+const std::string& User::GetIPString()
{
int port;
if (cachedip.empty())
{
irc::sockets::satoap(client_sa, cachedip, port);
/* IP addresses starting with a : on irc are a Bad Thing (tm) */
- if (cachedip.c_str()[0] == ':')
+ if (cachedip[0] == ':')
cachedip.insert(cachedip.begin(),1,'0');
}
- return cachedip.c_str();
+ return cachedip;
}
irc::sockets::cidr_mask User::GetCIDRMask()
@@ -1032,7 +749,7 @@ void LocalUser::SetClientIP(const irc::sockets::sockaddrs& sa, bool recheck_elin
if (recheck_eline)
this->exempt = (ServerInstance->XLines->MatchesLine("E", this) != NULL);
- FOREACH_MOD(I_OnSetUserIP,OnSetUserIP(this));
+ FOREACH_MOD(OnSetUserIP, (this));
}
}
@@ -1048,23 +765,23 @@ void User::Write(const char *text, ...)
void LocalUser::Write(const std::string& text)
{
- if (!ServerInstance->SE->BoundsCheckFd(&eh))
+ if (!SocketEngine::BoundsCheckFd(&eh))
return;
- if (text.length() > MAXBUF - 2)
+ if (text.length() > ServerInstance->Config->Limits.MaxLine - 2)
{
// this should happen rarely or never. Crop the string at 512 and try again.
- std::string try_again = text.substr(0, MAXBUF - 2);
+ std::string try_again = text.substr(0, ServerInstance->Config->Limits.MaxLine - 2);
Write(try_again);
return;
}
- ServerInstance->Logs->Log("USEROUTPUT", RAWIO, "C[%s] O %s", uuid.c_str(), text.c_str());
+ ServerInstance->Logs->Log("USEROUTPUT", LOG_RAWIO, "C[%s] O %s", uuid.c_str(), text.c_str());
eh.AddWriteBuf(text);
eh.AddWriteBuf(wide_newline);
- ServerInstance->stats->statsSent += text.length() + 2;
+ ServerInstance->stats.Sent += text.length() + 2;
this->bytes_out += text.length() + 2;
this->cmds_out++;
}
@@ -1073,14 +790,9 @@ void LocalUser::Write(const std::string& text)
*/
void LocalUser::Write(const char *text, ...)
{
- va_list argsPtr;
- char textbuffer[MAXBUF];
-
- va_start(argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
-
- this->Write(std::string(textbuffer));
+ std::string textbuffer;
+ VAFORMAT(textbuffer, text, text);
+ this->Write(textbuffer);
}
void User::WriteServ(const std::string& text)
@@ -1093,32 +805,25 @@ void User::WriteServ(const std::string& text)
*/
void User::WriteServ(const char* text, ...)
{
- va_list argsPtr;
- char textbuffer[MAXBUF];
-
- va_start(argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
-
- this->WriteServ(std::string(textbuffer));
+ std::string textbuffer;
+ VAFORMAT(textbuffer, text, text);
+ this->WriteServ(textbuffer);
}
+void User::WriteCommand(const char* command, const std::string& text)
+{
+ this->WriteServ(command + (this->registered & REG_NICK ? " " + this->nick : " *") + " " + text);
+}
void User::WriteNumeric(unsigned int numeric, const char* text, ...)
{
- va_list argsPtr;
- char textbuffer[MAXBUF];
-
- va_start(argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
-
- this->WriteNumeric(numeric, std::string(textbuffer));
+ std::string textbuffer;
+ VAFORMAT(textbuffer, text, text);
+ this->WriteNumeric(numeric, textbuffer);
}
void User::WriteNumeric(unsigned int numeric, const std::string &text)
{
- char textbuffer[MAXBUF];
ModResult MOD_RESULT;
FIRST_MOD_RESULT(OnNumeric, MOD_RESULT, (this, numeric, text));
@@ -1126,17 +831,15 @@ void User::WriteNumeric(unsigned int numeric, const std::string &text)
if (MOD_RESULT == MOD_RES_DENY)
return;
- snprintf(textbuffer,MAXBUF,":%s %03u %s",ServerInstance->Config->ServerName.c_str(), numeric, text.c_str());
- this->Write(std::string(textbuffer));
+ const std::string message = InspIRCd::Format(":%s %03u %s %s", ServerInstance->Config->ServerName.c_str(),
+ numeric, this->registered & REG_NICK ? this->nick.c_str() : "*", text.c_str());
+ this->Write(message);
}
void User::WriteFrom(User *user, const std::string &text)
{
- char tb[MAXBUF];
-
- snprintf(tb,MAXBUF,":%s %s",user->GetFullHost().c_str(),text.c_str());
-
- this->Write(std::string(tb));
+ const std::string message = ":" + user->GetFullHost() + " " + text;
+ this->Write(message);
}
@@ -1144,68 +847,20 @@ void User::WriteFrom(User *user, const std::string &text)
void User::WriteFrom(User *user, const char* text, ...)
{
- va_list argsPtr;
- char textbuffer[MAXBUF];
-
- va_start(argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
-
- this->WriteFrom(user, std::string(textbuffer));
-}
-
-
-/* write text to an destination user from a source user (e.g. user privmsg) */
-
-void User::WriteTo(User *dest, const char *data, ...)
-{
- char textbuffer[MAXBUF];
- va_list argsPtr;
-
- va_start(argsPtr, data);
- vsnprintf(textbuffer, MAXBUF, data, argsPtr);
- va_end(argsPtr);
-
- this->WriteTo(dest, std::string(textbuffer));
-}
-
-void User::WriteTo(User *dest, const std::string &data)
-{
- dest->WriteFrom(this, data);
+ std::string textbuffer;
+ VAFORMAT(textbuffer, text, text);
+ this->WriteFrom(user, textbuffer);
}
void User::WriteCommon(const char* text, ...)
{
- char textbuffer[MAXBUF];
- va_list argsPtr;
-
if (this->registered != REG_ALL || quitting)
return;
- int len = snprintf(textbuffer,MAXBUF,":%s ",this->GetFullHost().c_str());
-
- va_start(argsPtr, text);
- vsnprintf(textbuffer + len, MAXBUF - len, text, argsPtr);
- va_end(argsPtr);
-
- this->WriteCommonRaw(std::string(textbuffer), true);
-}
-
-void User::WriteCommonExcept(const char* text, ...)
-{
- char textbuffer[MAXBUF];
- va_list argsPtr;
-
- if (this->registered != REG_ALL || quitting)
- return;
-
- int len = snprintf(textbuffer,MAXBUF,":%s ",this->GetFullHost().c_str());
-
- va_start(argsPtr, text);
- vsnprintf(textbuffer + len, MAXBUF - len, text, argsPtr);
- va_end(argsPtr);
-
- this->WriteCommonRaw(std::string(textbuffer), false);
+ std::string textbuffer;
+ VAFORMAT(textbuffer, text, text);
+ textbuffer = ":" + this->GetFullHost() + " " + textbuffer;
+ this->WriteCommonRaw(textbuffer, true);
}
void User::WriteCommonRaw(const std::string &line, bool include_self)
@@ -1215,12 +870,12 @@ void User::WriteCommonRaw(const std::string &line, bool include_self)
LocalUser::already_sent_id++;
- UserChanList include_c(chans);
+ IncludeChanList include_c(chans.begin(), chans.end());
std::map<User*,bool> exceptions;
exceptions[this] = include_self;
- FOREACH_MOD(I_OnBuildNeighborList,OnBuildNeighborList(this, include_c, exceptions));
+ FOREACH_MOD(OnBuildNeighborList, (this, include_c, exceptions));
for (std::map<User*,bool>::iterator i = exceptions.begin(); i != exceptions.end(); ++i)
{
@@ -1232,14 +887,14 @@ void User::WriteCommonRaw(const std::string &line, bool include_self)
u->Write(line);
}
}
- for (UCListIter v = include_c.begin(); v != include_c.end(); ++v)
+ for (IncludeChanList::const_iterator v = include_c.begin(); v != include_c.end(); ++v)
{
- Channel* c = *v;
- const UserMembList* ulist = c->GetUsers();
- for (UserMembList::const_iterator i = ulist->begin(); i != ulist->end(); i++)
+ Channel* c = (*v)->chan;
+ const Channel::MemberMap& ulist = c->GetUsers();
+ for (Channel::MemberMap::const_iterator i = ulist.begin(); i != ulist.end(); ++i)
{
LocalUser* u = IS_LOCAL(i->first);
- if (u && !u->quitting && u->already_sent != LocalUser::already_sent_id)
+ if (u && u->already_sent != LocalUser::already_sent_id)
{
u->already_sent = LocalUser::already_sent_id;
u->Write(line);
@@ -1250,23 +905,18 @@ void User::WriteCommonRaw(const std::string &line, bool include_self)
void User::WriteCommonQuit(const std::string &normal_text, const std::string &oper_text)
{
- char tb1[MAXBUF];
- char tb2[MAXBUF];
-
if (this->registered != REG_ALL)
return;
already_sent_t uniq_id = ++LocalUser::already_sent_id;
- snprintf(tb1,MAXBUF,":%s QUIT :%s",this->GetFullHost().c_str(),normal_text.c_str());
- snprintf(tb2,MAXBUF,":%s QUIT :%s",this->GetFullHost().c_str(),oper_text.c_str());
- std::string out1 = tb1;
- std::string out2 = tb2;
+ const std::string normalMessage = ":" + this->GetFullHost() + " QUIT :" + normal_text;
+ const std::string operMessage = ":" + this->GetFullHost() + " QUIT :" + oper_text;
- UserChanList include_c(chans);
+ IncludeChanList include_c(chans.begin(), chans.end());
std::map<User*,bool> exceptions;
- FOREACH_MOD(I_OnBuildNeighborList,OnBuildNeighborList(this, include_c, exceptions));
+ FOREACH_MOD(OnBuildNeighborList, (this, include_c, exceptions));
for (std::map<User*,bool>::iterator i = exceptions.begin(); i != exceptions.end(); ++i)
{
@@ -1275,19 +925,19 @@ void User::WriteCommonQuit(const std::string &normal_text, const std::string &op
{
u->already_sent = uniq_id;
if (i->second)
- u->Write(IS_OPER(u) ? out2 : out1);
+ u->Write(u->IsOper() ? operMessage : normalMessage);
}
}
- for (UCListIter v = include_c.begin(); v != include_c.end(); ++v)
+ for (IncludeChanList::const_iterator v = include_c.begin(); v != include_c.end(); ++v)
{
- const UserMembList* ulist = (*v)->GetUsers();
- for (UserMembList::const_iterator i = ulist->begin(); i != ulist->end(); i++)
+ const Channel::MemberMap& ulist = (*v)->chan->GetUsers();
+ for (Channel::MemberMap::const_iterator i = ulist.begin(); i != ulist.end(); i++)
{
LocalUser* u = IS_LOCAL(i->first);
- if (u && !u->quitting && (u->already_sent != uniq_id))
+ if (u && (u->already_sent != uniq_id))
{
u->already_sent = uniq_id;
- u->Write(IS_OPER(u) ? out2 : out1);
+ u->Write(u->IsOper() ? operMessage : normalMessage);
}
}
}
@@ -1309,38 +959,26 @@ void FakeUser::SendText(const std::string& line)
void User::SendText(const char *text, ...)
{
- va_list argsPtr;
- char line[MAXBUF];
-
- va_start(argsPtr, text);
- vsnprintf(line, MAXBUF, text, argsPtr);
- va_end(argsPtr);
-
- SendText(std::string(line));
+ std::string line;
+ VAFORMAT(line, text, text);
+ SendText(line);
}
-void User::SendText(const std::string &LinePrefix, std::stringstream &TextStream)
+void User::SendText(const std::string& linePrefix, std::stringstream& textStream)
{
- char line[MAXBUF];
- int start_pos = LinePrefix.length();
- int pos = start_pos;
- memcpy(line, LinePrefix.data(), pos);
- std::string Word;
- while (TextStream >> Word)
+ std::string line;
+ std::string word;
+ while (textStream >> word)
{
- int len = Word.length();
- if (pos + len + 12 > MAXBUF)
+ size_t lineLength = linePrefix.length() + line.length() + word.length() + 3; // "\s\n\r"
+ if (lineLength > ServerInstance->Config->Limits.MaxLine)
{
- line[pos] = '\0';
- SendText(std::string(line));
- pos = start_pos;
+ SendText(linePrefix + line);
+ line.clear();
}
- line[pos] = ' ';
- memcpy(line + pos + 1, Word.data(), len);
- pos += len + 1;
+ line += " " + word;
}
- line[pos] = '\0';
- SendText(std::string(line));
+ SendText(linePrefix + line);
}
/* return 0 or 1 depending if users u and u2 share one or more common channels
@@ -1357,22 +995,19 @@ void User::SendText(const std::string &LinePrefix, std::stringstream &TextStream
*/
bool User::SharesChannelWith(User *other)
{
- if ((!other) || (this->registered != REG_ALL) || (other->registered != REG_ALL))
- return false;
-
/* Outer loop */
- for (UCListIter i = this->chans.begin(); i != this->chans.end(); i++)
+ for (User::ChanList::iterator i = this->chans.begin(); i != this->chans.end(); ++i)
{
/* Eliminate the inner loop (which used to be ~equal in size to the outer loop)
* by replacing it with a map::find which *should* be more efficient
*/
- if ((*i)->HasUser(other))
+ if ((*i)->chan->HasUser(other))
return true;
}
return false;
}
-bool User::ChangeName(const char* gecos)
+bool User::ChangeName(const std::string& gecos)
{
if (!this->fullname.compare(gecos))
return true;
@@ -1383,83 +1018,14 @@ bool User::ChangeName(const char* gecos)
FIRST_MOD_RESULT(OnChangeLocalUserGECOS, MOD_RESULT, (IS_LOCAL(this),gecos));
if (MOD_RESULT == MOD_RES_DENY)
return false;
- FOREACH_MOD(I_OnChangeName,OnChangeName(this,gecos));
+ FOREACH_MOD(OnChangeName, (this,gecos));
}
this->fullname.assign(gecos, 0, ServerInstance->Config->Limits.MaxGecos);
return true;
}
-void User::DoHostCycle(const std::string &quitline)
-{
- char buffer[MAXBUF];
-
- if (!ServerInstance->Config->CycleHosts)
- return;
-
- already_sent_t silent_id = ++LocalUser::already_sent_id;
- already_sent_t seen_id = ++LocalUser::already_sent_id;
-
- UserChanList include_c(chans);
- std::map<User*,bool> exceptions;
-
- FOREACH_MOD(I_OnBuildNeighborList,OnBuildNeighborList(this, include_c, exceptions));
-
- for (std::map<User*,bool>::iterator i = exceptions.begin(); i != exceptions.end(); ++i)
- {
- LocalUser* u = IS_LOCAL(i->first);
- if (u && !u->quitting)
- {
- if (i->second)
- {
- u->already_sent = seen_id;
- u->Write(quitline);
- }
- else
- {
- u->already_sent = silent_id;
- }
- }
- }
- for (UCListIter v = include_c.begin(); v != include_c.end(); ++v)
- {
- Channel* c = *v;
- snprintf(buffer, MAXBUF, ":%s JOIN %s", GetFullHost().c_str(), c->name.c_str());
- std::string joinline(buffer);
- Membership* memb = c->GetUser(this);
- std::string modeline = memb->modes;
- if (modeline.length() > 0)
- {
- for(unsigned int i=0; i < memb->modes.length(); i++)
- modeline.append(" ").append(nick);
- snprintf(buffer, MAXBUF, ":%s MODE %s +%s",
- ServerInstance->Config->CycleHostsFromUser ? GetFullHost().c_str() : ServerInstance->Config->ServerName.c_str(),
- c->name.c_str(), modeline.c_str());
- modeline = buffer;
- }
-
- const UserMembList *ulist = c->GetUsers();
- for (UserMembList::const_iterator i = ulist->begin(); i != ulist->end(); i++)
- {
- LocalUser* u = IS_LOCAL(i->first);
- if (u == NULL || u == this)
- continue;
- if (u->already_sent == silent_id)
- continue;
-
- if (u->already_sent != seen_id)
- {
- u->Write(quitline);
- u->already_sent = seen_id;
- }
- u->Write(joinline);
- if (modeline.length() > 0)
- u->Write(modeline);
- }
- }
-}
-
-bool User::ChangeDisplayedHost(const char* shost)
+bool User::ChangeDisplayedHost(const std::string& shost)
{
if (dhost == shost)
return true;
@@ -1472,106 +1038,30 @@ bool User::ChangeDisplayedHost(const char* shost)
return false;
}
- FOREACH_MOD(I_OnChangeHost, OnChangeHost(this,shost));
-
- std::string quitstr = ":" + GetFullHost() + " QUIT :Changing host";
-
- /* Fix by Om: User::dhost is 65 long, this was truncating some long hosts */
- this->dhost.assign(shost, 0, 64);
+ FOREACH_MOD(OnChangeHost, (this,shost));
+ this->dhost.assign(shost, 0, ServerInstance->Config->Limits.MaxHost);
this->InvalidateCache();
- this->DoHostCycle(quitstr);
-
if (IS_LOCAL(this))
- this->WriteNumeric(RPL_YOURDISPLAYEDHOST, "%s %s :is now your displayed host",this->nick.c_str(),this->dhost.c_str());
+ this->WriteNumeric(RPL_YOURDISPLAYEDHOST, "%s :is now your displayed host", this->dhost.c_str());
return true;
}
-bool User::ChangeIdent(const char* newident)
+bool User::ChangeIdent(const std::string& newident)
{
if (this->ident == newident)
return true;
- FOREACH_MOD(I_OnChangeIdent, OnChangeIdent(this,newident));
-
- std::string quitstr = ":" + GetFullHost() + " QUIT :Changing ident";
+ FOREACH_MOD(OnChangeIdent, (this,newident));
this->ident.assign(newident, 0, ServerInstance->Config->Limits.IdentMax);
-
this->InvalidateCache();
- this->DoHostCycle(quitstr);
-
return true;
}
-void User::SendAll(const char* command, const char* text, ...)
-{
- char textbuffer[MAXBUF];
- char formatbuffer[MAXBUF];
- va_list argsPtr;
-
- va_start(argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
-
- snprintf(formatbuffer,MAXBUF,":%s %s $* :%s", this->GetFullHost().c_str(), command, textbuffer);
- std::string fmt = formatbuffer;
-
- for (LocalUserList::const_iterator i = ServerInstance->Users->local_users.begin(); i != ServerInstance->Users->local_users.end(); i++)
- {
- if ((*i)->registered == REG_ALL)
- (*i)->Write(fmt);
- }
-}
-
-
-std::string User::ChannelList(User* source, bool spy)
-{
- std::string list;
-
- for (UCListIter i = this->chans.begin(); i != this->chans.end(); i++)
- {
- Channel* c = *i;
- /* If the target is the sender, neither +p nor +s is set, or
- * the channel contains the user, it is not a spy channel
- */
- if (spy != (source == this || !(c->IsModeSet('p') || c->IsModeSet('s')) || c->HasUser(source)))
- list.append(c->GetPrefixChar(this)).append(c->name).append(" ");
- }
-
- return list;
-}
-
-void User::SplitChanList(User* dest, const std::string &cl)
-{
- std::string line;
- std::ostringstream prefix;
- std::string::size_type start, pos;
-
- prefix << this->nick << " " << dest->nick << " :";
- line = prefix.str();
- int namelen = ServerInstance->Config->ServerName.length() + 6;
-
- for (start = 0; (pos = cl.find(' ', start)) != std::string::npos; start = pos+1)
- {
- if (line.length() + namelen + pos - start > 510)
- {
- ServerInstance->SendWhoisLine(this, dest, 319, "%s", line.c_str());
- line = prefix.str();
- }
-
- line.append(cl.substr(start, pos - start + 1));
- }
-
- if (line.length() != prefix.str().length())
- {
- ServerInstance->SendWhoisLine(this, dest, 319, "%s", line.c_str());
- }
-}
-
/*
* Sets a user's connection class.
* If the class name is provided, it will be used. Otherwise, the class will be guessed using host/ip/ident/etc.
@@ -1583,27 +1073,27 @@ void LocalUser::SetClass(const std::string &explicit_name)
{
ConnectClass *found = NULL;
- ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "Setting connect class for UID %s", this->uuid.c_str());
+ ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Setting connect class for UID %s", this->uuid.c_str());
if (!explicit_name.empty())
{
- for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++)
+ for (ServerConfig::ClassVector::const_iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); ++i)
{
ConnectClass* c = *i;
if (explicit_name == c->name)
{
- ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "Explicitly set to %s", explicit_name.c_str());
+ ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Explicitly set to %s", explicit_name.c_str());
found = c;
}
}
}
else
{
- for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++)
+ for (ServerConfig::ClassVector::const_iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); ++i)
{
ConnectClass* c = *i;
- ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "Checking %s", c->GetName().c_str());
+ ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Checking %s", c->GetName().c_str());
ModResult MOD_RESULT;
FIRST_MOD_RESULT(OnSetConnectClass, MOD_RESULT, (this,c));
@@ -1611,7 +1101,7 @@ void LocalUser::SetClass(const std::string &explicit_name)
continue;
if (MOD_RESULT == MOD_RES_ALLOW)
{
- ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "Class forced by module to %s", c->GetName().c_str());
+ ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Class forced by module to %s", c->GetName().c_str());
found = c;
break;
}
@@ -1627,7 +1117,7 @@ void LocalUser::SetClass(const std::string &explicit_name)
if (!InspIRCd::MatchCIDR(this->GetIPString(), c->GetHost(), NULL) &&
!InspIRCd::MatchCIDR(this->host, c->GetHost(), NULL))
{
- ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "No host match (for %s)", c->GetHost().c_str());
+ ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "No host match (for %s)", c->GetHost().c_str());
continue;
}
@@ -1637,7 +1127,7 @@ void LocalUser::SetClass(const std::string &explicit_name)
*/
if (c->limit && (c->GetReferenceCount() >= c->limit))
{
- ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "OOPS: Connect class limit (%lu) hit, denying", c->limit);
+ ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "OOPS: Connect class limit (%lu) hit, denying", c->limit);
continue;
}
@@ -1645,7 +1135,7 @@ void LocalUser::SetClass(const std::string &explicit_name)
int port = c->config->getInt("port");
if (port)
{
- ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "Requires port (%d)", port);
+ ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Requires port (%d)", port);
/* and our port doesn't match, fail. */
if (this->GetServerPort() != port)
@@ -1654,9 +1144,9 @@ void LocalUser::SetClass(const std::string &explicit_name)
if (regdone && !c->config->getString("password").empty())
{
- if (ServerInstance->PassCompare(this, c->config->getString("password"), password, c->config->getString("hash")))
+ if (!ServerInstance->PassCompare(this, c->config->getString("password"), password, c->config->getString("hash")))
{
- ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "Bad password, skipping");
+ ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Bad password, skipping");
continue;
}
}
@@ -1676,27 +1166,13 @@ void LocalUser::SetClass(const std::string &explicit_name)
}
}
-/* looks up a users password for their connection class (<ALLOW>/<DENY> tags)
- * NOTE: If the <ALLOW> or <DENY> tag specifies an ip, and this user resolves,
- * then their ip will be taken as 'priority' anyway, so for example,
- * <connect allow="127.0.0.1"> will match joe!bloggs@localhost
- */
-ConnectClass* LocalUser::GetClass()
-{
- return MyClass;
-}
-
-ConnectClass* User::GetClass()
-{
- return NULL;
-}
-
void User::PurgeEmptyChannels()
{
// firstly decrement the count on each channel
- for (UCListIter f = this->chans.begin(); f != this->chans.end(); f++)
+ for (User::ChanList::iterator i = this->chans.begin(); i != this->chans.end(); )
{
- Channel* c = *f;
+ Channel* c = (*i)->chan;
+ ++i;
c->DelUser(this);
}
@@ -1707,20 +1183,21 @@ const std::string& FakeUser::GetFullHost()
{
if (!ServerInstance->Config->HideWhoisServer.empty())
return ServerInstance->Config->HideWhoisServer;
- return server;
+ return server->GetName();
}
const std::string& FakeUser::GetFullRealHost()
{
if (!ServerInstance->Config->HideWhoisServer.empty())
return ServerInstance->Config->HideWhoisServer;
- return server;
+ return server->GetName();
}
ConnectClass::ConnectClass(ConfigTag* tag, char t, const std::string& mask)
: config(tag), type(t), fakelag(true), name("unnamed"), registration_timeout(0), host(mask),
pingtime(0), softsendqmax(0), hardsendqmax(0), recvqmax(0),
- penaltythreshold(0), commandrate(0), maxlocal(0), maxglobal(0), maxconnwarn(true), maxchans(0), limit(0)
+ penaltythreshold(0), commandrate(0), maxlocal(0), maxglobal(0), maxconnwarn(true), maxchans(ServerInstance->Config->MaxChans),
+ limit(0), resolvehostnames(true)
{
}
@@ -1730,7 +1207,7 @@ ConnectClass::ConnectClass(ConfigTag* tag, char t, const std::string& mask, cons
softsendqmax(parent.softsendqmax), hardsendqmax(parent.hardsendqmax), recvqmax(parent.recvqmax),
penaltythreshold(parent.penaltythreshold), commandrate(parent.commandrate),
maxlocal(parent.maxlocal), maxglobal(parent.maxglobal), maxconnwarn(parent.maxconnwarn), maxchans(parent.maxchans),
- limit(parent.limit)
+ limit(parent.limit), resolvehostnames(parent.resolvehostnames)
{
}
@@ -1753,4 +1230,5 @@ void ConnectClass::Update(const ConnectClass* src)
maxconnwarn = src->maxconnwarn;
maxchans = src->maxchans;
limit = src->limit;
+ resolvehostnames = src->resolvehostnames;
}
diff --git a/src/version.sh b/src/version.sh
index 8246485b1..d307082f4 100755
--- a/src/version.sh
+++ b/src/version.sh
@@ -1,2 +1,2 @@
#!/bin/sh
-echo "InspIRCd-2.0.17"
+echo "InspIRCd-2.2.0+pre"
diff --git a/src/whois.cpp b/src/whois.cpp
deleted file mode 100644
index bec9c7ea9..000000000
--- a/src/whois.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-
-void InspIRCd::DoWhois(User* user, User* dest,unsigned long signon, unsigned long idle, const char* nick)
-{
- this->SendWhoisLine(user, dest, 311, "%s %s %s %s * :%s",user->nick.c_str(), dest->nick.c_str(), dest->ident.c_str(), dest->dhost.c_str(), dest->fullname.c_str());
- if (user == dest || user->HasPrivPermission("users/auspex"))
- {
- this->SendWhoisLine(user, dest, 378, "%s %s :is connecting from %s@%s %s", user->nick.c_str(), dest->nick.c_str(), dest->ident.c_str(), dest->host.c_str(), dest->GetIPString());
- }
-
- std::string cl = dest->ChannelList(user, false);
- const ServerConfig::OperSpyWhoisState state = user->HasPrivPermission("users/auspex") ? ServerInstance->Config->OperSpyWhois : ServerConfig::SPYWHOIS_NONE;
-
- if (state == ServerConfig::SPYWHOIS_SINGLEMSG)
- cl.append(dest->ChannelList(user, true));
-
- user->SplitChanList(dest,cl);
-
- if (state == ServerConfig::SPYWHOIS_SPLITMSG)
- {
- std::string scl = dest->ChannelList(user, true);
- if (scl.length())
- {
- SendWhoisLine(user, dest, 336, "%s %s :is on private/secret channels:",user->nick.c_str(), dest->nick.c_str());
- user->SplitChanList(dest,scl);
- }
- }
- if (user != dest && !this->Config->HideWhoisServer.empty() && !user->HasPrivPermission("servers/auspex"))
- {
- this->SendWhoisLine(user, dest, 312, "%s %s %s :%s",user->nick.c_str(), dest->nick.c_str(), this->Config->HideWhoisServer.c_str(), this->Config->Network.c_str());
- }
- else
- {
- std::string serverdesc = GetServerDescription(dest->server);
- this->SendWhoisLine(user, dest, 312, "%s %s %s :%s",user->nick.c_str(), dest->nick.c_str(), dest->server.c_str(), serverdesc.c_str());
- }
-
- if (IS_AWAY(dest))
- {
- this->SendWhoisLine(user, dest, 301, "%s %s :%s",user->nick.c_str(), dest->nick.c_str(), dest->awaymsg.c_str());
- }
-
- if (IS_OPER(dest))
- {
- if (this->Config->GenericOper)
- this->SendWhoisLine(user, dest, 313, "%s %s :is an IRC operator",user->nick.c_str(), dest->nick.c_str());
- else
- this->SendWhoisLine(user, dest, 313, "%s %s :is %s %s on %s",user->nick.c_str(), dest->nick.c_str(), (strchr("AEIOUaeiou",dest->oper->name[0]) ? "an" : "a"),dest->oper->NameStr(), this->Config->Network.c_str());
- }
-
- if (user == dest || user->HasPrivPermission("users/auspex"))
- {
- if (dest->IsModeSet('s') != 0)
- {
- this->SendWhoisLine(user, dest, 379, "%s %s :is using modes +%s +%s", user->nick.c_str(), dest->nick.c_str(), dest->FormatModes(), dest->FormatNoticeMasks());
- }
- else
- {
- this->SendWhoisLine(user, dest, 379, "%s %s :is using modes +%s", user->nick.c_str(), dest->nick.c_str(), dest->FormatModes());
- }
- }
-
- FOREACH_MOD(I_OnWhois,OnWhois(user,dest));
-
- /*
- * We only send these if we've been provided them. That is, if hidewhois is turned off, and user is local, or
- * if remote whois is queried, too. This is to keep the user hidden, and also since you can't reliably tell remote time. -- w00t
- */
- if ((idle) || (signon))
- {
- this->SendWhoisLine(user, dest, 317, "%s %s %lu %lu :seconds idle, signon time",user->nick.c_str(), dest->nick.c_str(), idle, signon);
- }
-
- this->SendWhoisLine(user, dest, 318, "%s %s :End of /WHOIS list.",user->nick.c_str(), dest->nick.c_str());
-}
-
-
-
diff --git a/src/wildcard.cpp b/src/wildcard.cpp
index eb9151293..6711f953a 100644
--- a/src/wildcard.cpp
+++ b/src/wildcard.cpp
@@ -19,15 +19,12 @@
*/
-/* $Core */
-
#include "inspircd.h"
-#include "hashcomp.h"
-#include "inspstring.h"
-static bool match_internal(const unsigned char *str, const unsigned char *mask, unsigned const char *map)
+static bool MatchInternal(const unsigned char* str, const unsigned char* mask, unsigned const char* map)
{
- unsigned char *cp = NULL, *mp = NULL;
+ unsigned char* cp = NULL;
+ unsigned char* mp = NULL;
unsigned char* string = (unsigned char*)str;
unsigned char* wild = (unsigned char*)mask;
@@ -74,46 +71,53 @@ static bool match_internal(const unsigned char *str, const unsigned char *mask,
return !*wild;
}
-/********************************************************************
- * Below here is all wrappers around match_internal
- ********************************************************************/
+// Below here is all wrappers around MatchInternal
-CoreExport bool InspIRCd::Match(const std::string &str, const std::string &mask, unsigned const char *map)
+bool InspIRCd::Match(const std::string& str, const std::string& mask, unsigned const char* map)
{
if (!map)
map = national_case_insensitive_map;
- return match_internal((const unsigned char *)str.c_str(), (const unsigned char *)mask.c_str(), map);
+ return MatchInternal((const unsigned char*)str.c_str(), (const unsigned char*)mask.c_str(), map);
}
-CoreExport bool InspIRCd::Match(const char *str, const char *mask, unsigned const char *map)
+bool InspIRCd::Match(const char* str, const char* mask, unsigned const char* map)
{
if (!map)
map = national_case_insensitive_map;
- return match_internal((const unsigned char *)str, (const unsigned char *)mask, map);
+
+ return MatchInternal((const unsigned char*)str, (const unsigned char*)mask, map);
}
-CoreExport bool InspIRCd::MatchCIDR(const std::string &str, const std::string &mask, unsigned const char *map)
+bool InspIRCd::MatchCIDR(const std::string& str, const std::string& mask, unsigned const char* map)
{
if (irc::sockets::MatchCIDR(str, mask, true))
return true;
- if (!map)
- map = national_case_insensitive_map;
-
// Fall back to regular match
return InspIRCd::Match(str, mask, map);
}
-CoreExport bool InspIRCd::MatchCIDR(const char *str, const char *mask, unsigned const char *map)
+bool InspIRCd::MatchCIDR(const char* str, const char* mask, unsigned const char* map)
{
if (irc::sockets::MatchCIDR(str, mask, true))
return true;
- if (!map)
- map = national_case_insensitive_map;
-
// Fall back to regular match
return InspIRCd::Match(str, mask, map);
}
+bool InspIRCd::MatchMask(const std::string& masks, const std::string& hostname, const std::string& ipaddr)
+{
+ std::stringstream masklist(masks);
+ std::string mask;
+ while (masklist >> mask)
+ {
+ if (InspIRCd::Match(hostname, mask, ascii_case_insensitive_map) ||
+ InspIRCd::MatchCIDR(ipaddr, mask, ascii_case_insensitive_map))
+ {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/src/xline.cpp b/src/xline.cpp
index 66d24f439..3eb556234 100644
--- a/src/xline.cpp
+++ b/src/xline.cpp
@@ -23,7 +23,6 @@
#include "inspircd.h"
#include "xline.h"
-#include "bancache.h"
/** An XLineFactory specialized to generate GLine* pointers
*/
@@ -156,9 +155,10 @@ void XLineManager::CheckELines()
if (ELines.empty())
return;
- for (LocalUserList::const_iterator u2 = ServerInstance->Users->local_users.begin(); u2 != ServerInstance->Users->local_users.end(); u2++)
+ const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers();
+ for (UserManager::LocalList::const_iterator u2 = list.begin(); u2 != list.end(); u2++)
{
- User* u = (User*)(*u2);
+ LocalUser* u = *u2;
/* This uses safe iteration to ensure that if a line expires here, it doenst trash the iterator */
LookupIter safei;
@@ -259,7 +259,7 @@ bool XLineManager::AddLine(XLine* line, User* user)
ContainerIter x = lookup_lines.find(line->type);
if (x != lookup_lines.end())
{
- LookupIter i = x->second.find(line->Displayable());
+ LookupIter i = x->second.find(line->Displayable().c_str());
if (i != x->second.end())
{
// XLine propagation bug was here, if the line to be added already exists and
@@ -276,15 +276,15 @@ bool XLineManager::AddLine(XLine* line, User* user)
if (!xlf)
return false;
- ServerInstance->BanCache->RemoveEntries(line->type, false); // XXX perhaps remove ELines here?
+ ServerInstance->BanCache.RemoveEntries(line->type, false); // XXX perhaps remove ELines here?
if (xlf->AutoApplyToUserList(line))
pending_lines.push_back(line);
- lookup_lines[line->type][line->Displayable()] = line;
+ lookup_lines[line->type][line->Displayable().c_str()] = line;
line->OnAdd();
- FOREACH_MOD(I_OnAddLine,OnAddLine(user, line));
+ FOREACH_MOD(OnAddLine, (user, line));
return true;
}
@@ -306,9 +306,9 @@ bool XLineManager::DelLine(const char* hostmask, const std::string &type, User*
if (simulate)
return true;
- ServerInstance->BanCache->RemoveEntries(y->second->type, true);
+ ServerInstance->BanCache.RemoveEntries(y->second->type, true);
- FOREACH_MOD(I_OnDelLine,OnDelLine(user, y->second));
+ FOREACH_MOD(OnDelLine, (user, y->second));
y->second->Unset();
@@ -326,9 +326,10 @@ bool XLineManager::DelLine(const char* hostmask, const std::string &type, User*
void ELine::Unset()
{
/* remove exempt from everyone and force recheck after deleting eline */
- for (LocalUserList::const_iterator u2 = ServerInstance->Users->local_users.begin(); u2 != ServerInstance->Users->local_users.end(); u2++)
+ const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers();
+ for (UserManager::LocalList::const_iterator u2 = list.begin(); u2 != list.end(); u2++)
{
- User* u = (User*)(*u2);
+ LocalUser* u = *u2;
u->exempt = false;
}
@@ -409,7 +410,7 @@ XLine* XLineManager::MatchesLine(const std::string &type, const std::string &pat
// removes lines that have expired
void XLineManager::ExpireLine(ContainerIter container, LookupIter item)
{
- FOREACH_MOD(I_OnExpireLine, OnExpireLine(item->second));
+ FOREACH_MOD(OnExpireLine, (item->second));
item->second->DisplayExpiry();
item->second->Unset();
@@ -430,10 +431,10 @@ void XLineManager::ExpireLine(ContainerIter container, LookupIter item)
// applies lines, removing clients and changing nicks etc as applicable
void XLineManager::ApplyLines()
{
- LocalUserList::reverse_iterator u2 = ServerInstance->Users->local_users.rbegin();
- while (u2 != ServerInstance->Users->local_users.rend())
+ const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers();
+ for (UserManager::LocalList::const_iterator j = list.begin(); j != list.end(); ++j)
{
- User* u = *u2++;
+ LocalUser* u = *j;
// Don't ban people who are exempt.
if (u->exempt)
@@ -471,7 +472,7 @@ void XLineManager::InvokeStats(const std::string &type, int numeric, User* user,
ExpireLine(n, i);
}
else
- results.push_back(ServerInstance->Config->ServerName+" "+ConvToStr(numeric)+" "+user->nick+" :"+i->second->Displayable()+" "+
+ results.push_back(ConvToStr(numeric)+" "+user->nick+" :"+i->second->Displayable()+" "+
ConvToStr(i->second->set_time)+" "+ConvToStr(i->second->duration)+" "+i->second->source+" :"+i->second->reason);
i = safei;
}
@@ -531,30 +532,28 @@ bool XLine::IsBurstable()
void XLine::DefaultApply(User* u, const std::string &line, bool bancache)
{
- char sreason[MAXBUF];
- snprintf(sreason, MAXBUF, "%s-Lined: %s", line.c_str(), this->reason.c_str());
- if (!ServerInstance->Config->MoronBanner.empty())
- u->WriteServ("NOTICE %s :*** %s", u->nick.c_str(), ServerInstance->Config->MoronBanner.c_str());
+ const std::string banReason = line + "-Lined: " + reason;
+
+ if (!ServerInstance->Config->XLineMessage.empty())
+ u->WriteNotice("*** " + ServerInstance->Config->XLineMessage);
if (ServerInstance->Config->HideBans)
- ServerInstance->Users->QuitUser(u, line + "-Lined", sreason);
+ ServerInstance->Users->QuitUser(u, line + "-Lined", &banReason);
else
- ServerInstance->Users->QuitUser(u, sreason);
+ ServerInstance->Users->QuitUser(u, banReason);
if (bancache)
{
- ServerInstance->Logs->Log("BANCACHE", DEBUG, "BanCache: Adding positive hit (" + line + ") for " + u->GetIPString());
- if (this->duration > 0)
- ServerInstance->BanCache->AddHit(u->GetIPString(), this->type, line + "-Lined: " + this->reason, this->duration);
- else
- ServerInstance->BanCache->AddHit(u->GetIPString(), this->type, line + "-Lined: " + this->reason);
+ ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "BanCache: Adding positive hit (" + line + ") for " + u->GetIPString());
+ ServerInstance->BanCache.AddHit(u->GetIPString(), this->type, banReason, this->duration);
}
}
bool KLine::Matches(User *u)
{
- if (u->exempt)
+ LocalUser* lu = IS_LOCAL(u);
+ if (lu && lu->exempt)
return false;
if (InspIRCd::Match(u->ident, this->identmask, ascii_case_insensitive_map))
@@ -576,7 +575,8 @@ void KLine::Apply(User* u)
bool GLine::Matches(User *u)
{
- if (u->exempt)
+ LocalUser* lu = IS_LOCAL(u);
+ if (lu && lu->exempt)
return false;
if (InspIRCd::Match(u->ident, this->identmask, ascii_case_insensitive_map))
@@ -598,7 +598,8 @@ void GLine::Apply(User* u)
bool ELine::Matches(User *u)
{
- if (u->exempt)
+ LocalUser* lu = IS_LOCAL(u);
+ if (lu && lu->exempt)
return false;
if (InspIRCd::Match(u->ident, this->identmask, ascii_case_insensitive_map))
@@ -615,7 +616,8 @@ bool ELine::Matches(User *u)
bool ZLine::Matches(User *u)
{
- if (u->exempt)
+ LocalUser* lu = IS_LOCAL(u);
+ if (lu && lu->exempt)
return false;
if (InspIRCd::MatchCIDR(u->GetIPString(), this->ipaddr))
@@ -641,7 +643,7 @@ bool QLine::Matches(User *u)
void QLine::Apply(User* u)
{
/* Force to uuid on apply of qline, no need to disconnect any more :) */
- u->ForceNickChange(u->uuid.c_str());
+ u->ChangeNick(u->uuid);
}
@@ -679,67 +681,45 @@ bool GLine::Matches(const std::string &str)
void ELine::OnAdd()
{
/* When adding one eline, only check the one eline */
- for (LocalUserList::const_iterator u2 = ServerInstance->Users->local_users.begin(); u2 != ServerInstance->Users->local_users.end(); u2++)
+ const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers();
+ for (UserManager::LocalList::const_iterator u2 = list.begin(); u2 != list.end(); u2++)
{
- User* u = (User*)(*u2);
+ LocalUser* u = *u2;
if (this->Matches(u))
u->exempt = true;
}
}
-void ELine::DisplayExpiry()
-{
- ServerInstance->SNO->WriteToSnoMask('x',"Removing expired E-Line %s@%s (set by %s %ld seconds ago)",
- identmask.c_str(),hostmask.c_str(),source.c_str(),(long)(ServerInstance->Time() - this->set_time));
-}
-
-void QLine::DisplayExpiry()
-{
- ServerInstance->SNO->WriteToSnoMask('x',"Removing expired Q-Line %s (set by %s %ld seconds ago)",
- nick.c_str(),source.c_str(),(long)(ServerInstance->Time() - this->set_time));
-}
-
-void ZLine::DisplayExpiry()
-{
- ServerInstance->SNO->WriteToSnoMask('x',"Removing expired Z-Line %s (set by %s %ld seconds ago)",
- ipaddr.c_str(),source.c_str(),(long)(ServerInstance->Time() - this->set_time));
-}
-
-void KLine::DisplayExpiry()
-{
- ServerInstance->SNO->WriteToSnoMask('x',"Removing expired K-Line %s@%s (set by %s %ld seconds ago)",
- identmask.c_str(),hostmask.c_str(),source.c_str(),(long)(ServerInstance->Time() - this->set_time));
-}
-
-void GLine::DisplayExpiry()
+void XLine::DisplayExpiry()
{
- ServerInstance->SNO->WriteToSnoMask('x',"Removing expired G-Line %s@%s (set by %s %ld seconds ago)",
- identmask.c_str(),hostmask.c_str(),source.c_str(),(long)(ServerInstance->Time() - this->set_time));
+ bool onechar = (type.length() == 1);
+ ServerInstance->SNO->WriteToSnoMask('x', "Removing expired %s%s %s (set by %s %ld seconds ago)",
+ type.c_str(), (onechar ? "-Line" : ""), Displayable().c_str(), source.c_str(), (long)(ServerInstance->Time() - set_time));
}
-const char* ELine::Displayable()
+const std::string& ELine::Displayable()
{
- return matchtext.c_str();
+ return matchtext;
}
-const char* KLine::Displayable()
+const std::string& KLine::Displayable()
{
- return matchtext.c_str();
+ return matchtext;
}
-const char* GLine::Displayable()
+const std::string& GLine::Displayable()
{
- return matchtext.c_str();
+ return matchtext;
}
-const char* ZLine::Displayable()
+const std::string& ZLine::Displayable()
{
- return ipaddr.c_str();
+ return ipaddr;
}
-const char* QLine::Displayable()
+const std::string& QLine::Displayable()
{
- return nick.c_str();
+ return nick;
}
bool KLine::IsBurstable()