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
|
/*
* Copyright (c) 2026 Nakidai Perumenei <nakidai at disroot dot org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __IRCD_H__
#define __IRCD_H__
#include <stddef.h>
#include <time.h>
#define min(A, B) ((A) < (B) ? (A) : (B))
#include "config.h"
#define BIT(x) x##_BIT, x = 1 << x##_BIT, x##_BIT_ = x##_BIT
#define lengthof(X) (sizeof(X) / sizeof(*(X)))
/* when `ensure' is used, it's better to think of it like it's the condition under which code
* below "exists" (so, ensure that `cond' evaluates to true), and not like it's a condition when
* to stop, trying to invert cond */
#define ensure(cond, iffalse, doexit) if (!(cond)) { iffalse; if (doexit >= 0) return doexit; }
struct Message
{
char *nick, *user, *host, *command, *params[PARAM_MAX];
};
struct Peer
{
int fd;
enum ClientType { UNREGD, CLIENT, CONFIG, SERVER, SERVICE } type;
char nick[PEER_NICK_MAX], user[PEER_USER_MAX], real[PEER_REAL_MAX], host[PEER_HOST_MAX];
struct Channel *channels[PEER_CHANNELS_MAX];
enum PeerStatus {
BIT(DELETE),
BIT(ANNOUNCE),
} flags;
enum PeerMode {
BIT(AWAY),
BIT(INVISIBLE),
BIT(WALLOPS),
BIT(RESTRICTED),
BIT(OPER),
BIT(LOCALOPER),
BIT(SNOTICE),
} modes;
char buf[MESSAGE_MAX];
char quit[PEER_QUIT_MAX];
size_t recvd, channels_c;
time_t last, ping;
};
struct ChannelModeParam
{
char *param;
int set;
char mode;
};
struct Channel
{
enum { GLOBAL, LOCAL, MODELESS, SAFE } type;
char name[CHANNEL_NAME_MAX];
struct ChannelPeer {
struct Peer *p;
enum ChannelPeerMode {
BIT(CHANNEL_OPER),
BIT(CHANNEL_VOICE),
} modes;
} peers[CHANNEL_PEERS_MAX];
size_t peers_c;
enum ChannelMode
{
BIT(CHANNEL_SECRET),
} modes;
};
struct Oper
{
char nick[PEER_NICK_MAX];
char pass[OPER_PASS_MAX];
};
typedef int Handler(struct Message *msg, struct Peer *peer);
extern struct Channel channels[CHANNELS_MAX];
extern struct Peer peers[PEERS_MAX];
extern size_t channels_c, peers_c;
extern const char *hostname;
extern const char *host;
extern unsigned long port;
extern char creation[CREATION_MAX];
extern char info[INFO_MAX];
int readcfg(const char *path);
const char *getnick(const struct Peer *peer);
enum PeerMode user_mode(char m);
void user_reg(struct Peer *peer, const char *nick, const char *user, const char *real, const char *mode);
void user_remove(size_t pid);
int channel_join(struct Channel *channel, struct Peer *peer);
int channel_exit(struct Channel *channel, struct Peer *peer);
const struct ChannelModeParam *channel_modes_parse(const struct Message *msg);
void channel_remove(size_t cid);
int parse_message(char *buf, struct Message *msg);
int handle(struct Peer *peer);
int reply(const struct Peer *peer, int number, ...);
Handler *find(const char *command);
void announce(struct Peer *peer, const char *fmt, ...);
int writef(int fd, const char *fmt, ...);
int writechanf(const struct Peer *except, const struct Channel *channel, const char *fmt, ...);
void ircd(void);
#endif /* __IRCD_H__ */
|