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
|
/*
* 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>
#define PARAM_MAX 15
#define MESSAGE_MAX 512
#define PEERS_MAX 512
#define CHANNELS_MAX 512
#define USERS_PER_CHANNEL 512
#define MODES_MAX 512
#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, SERVER, SERVICE } type;
char nick[16], user[16], real[32], host[64];
struct Channel *channels[32];
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];
size_t recvd, channels_c;
};
struct Channel
{
enum { GLOBAL, LOCAL, MODELESS, SAFE } type;
char name[64];
struct {
char mode;
char param[MESSAGE_MAX - 1];
} modes[MODES_MAX];
struct Peer *users[USERS_PER_CHANNEL];
size_t modes_c, users_c;
};
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;
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);
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);
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__ */
|