forked from ptt/pttbbs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathangel.c
249 lines (218 loc) · 7.22 KB
/
angel.c
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
#include "bbs.h"
#include "daemons.h"
#define QUOTE(x) #x
#define EXPAND_AND_QUOTE(x) QUOTE(x)
#define STR_ANGELBEATS_PERF_MIN_PERIOD \
EXPAND_AND_QUOTE(ANGELBEATS_PERF_MIN_PERIOD)
#define die(format...) { fprintf(stderr, format); exit(1); }
#define REPORT_AUTHOR "[天使公會]"
#define REPORT_SUBJECT "小天使統計資料"
#ifndef PLAY_ANGEL
int main(){ return 0; }
#else
void slurp(FILE* to, FILE* from) {
char buf[4096]; // 4K block
int count;
while ((count = fread(buf, 1, sizeof(buf), from)) > 0) {
char * p = buf;
while (count > 0) {
int i = fwrite(p, 1, count, to);
if (i <= 0) return;
p += i;
count -= i;
}
}
}
void appendLogFile(FILE *output,
const char *filename,
const char *prefix,
int delete_file) {
FILE *fp = fopen(filename, "r");
if (!fp)
return;
if (delete_file)
remove(filename);
fputs(prefix, output);
slurp(output, fp);
fclose(fp);
}
typedef struct {
int uid;
int is_angel;
int masters;
int masters_week;
int masters_month;
int masters_quarter;
int masters_season;
int masters_period;
} AngelRecord;
int buildMasterInfo(AngelRecord *rec, int num_recs) {
userec_t user;
int uid = 0, angel_uid;
FILE *fp;
int count = 0;
time4_t now = time4(NULL);
memset(rec, 0, sizeof(*rec) * num_recs);
fp = fopen(FN_PASSWD, "rb");
while (fread(&user, sizeof(user), 1, fp) == 1) {
AngelRecord *r = rec + uid, *angel = NULL;
uid++;
r->uid = uid;
assert(uid <= num_recs);
if (!*user.userid)
continue;
if (user.role & ROLE_ANGEL_ACTIVITY)
continue;
if (user.userlevel & PERM_ANGEL) {
r->is_angel = 1;
count++;
}
if (!*user.myangel)
continue;
angel_uid = searchuser(user.myangel, NULL);
if (!angel_uid)
continue;
angel = rec + (angel_uid - 1);
angel->masters++;
if (now - user.timeplayangel < DAY_SECONDS * 7)
angel->masters_week++;
if (now - user.timeplayangel < DAY_SECONDS * 30)
angel->masters_month++;
if (now - user.timeplayangel < DAY_SECONDS * 90)
angel->masters_quarter++;
if (now - user.timeplayangel < DAY_SECONDS * 120)
angel->masters_season++;
if (now - user.timeplayangel < DAY_SECONDS * 180)
angel->masters_period++;
}
fclose(fp);
return count;
}
int sortAngelRecord(const void *pb, const void *pa) {
const AngelRecord *a = (const AngelRecord *)pa,
*b = (const AngelRecord *)pb;
assert(a->is_angel == b->is_angel);
if (a->masters_month != b->masters_month)
return a->masters_month - b->masters_month;
return a->masters - b->masters;
}
int generateReport(FILE *fp, AngelRecord *rec, int num_recs, int delete_file) {
time4_t t = time4(NULL);
int i;
fprintf(fp, "作者: %s\n標題: %s\n時間: %s\n",
REPORT_AUTHOR, REPORT_SUBJECT, ctime4(&t));
fprintf(fp, "現在全站小天使有 %d 位:\n", num_recs);
fprintf(fp,
" (後面數字為全部小主人數 | 7天內 | 30天內 | 90天內 | 120天 | 180天\n"
" 的活躍小主人數(在該段時間內有傳送訊息給任一小天使的主人)\n"
" 但注意目前活躍小主人僅統計「主人有送訊息」,無法得知小天使\n"
" 是否掛站 - 所以請配合抽查結果評估。)\n");
for (i = 0; i < num_recs; i++)
fprintf(fp, "%15s | %6d | %6d | %6d | %6d | %6d | %6d\n",
getuserid(rec[i].uid),
rec[i].masters,
rec[i].masters_week,
rec[i].masters_month,
rec[i].masters_quarter,
rec[i].masters_season,
rec[i].masters_period
);
fputs("\n", fp);
appendLogFile(fp, "log/angel_perf.txt",
"\n== 本周小天使活動資料記錄 ==\n"
" (說明: Start 是開始統計的時間\n"
" Duration 是幾秒統計一次\n"
" Sample 指的是每次統計時天使在線上的次數\n"
" Pause1 指的是 Sample 中有幾次神諭呼叫器設停收\n"
" Pause2 指的是 Sample 中有幾次神諭呼叫器設關閉)\n",
delete_file);
appendLogFile(fp, "log/change_angel_nick.log",
"\n== 本周小天使暱稱變更記錄 ==\n",
delete_file);
appendLogFile(fp, "log/changeangel.log",
"\n== 本周更換小天使記錄 ==\n",
delete_file);
fprintf(fp, "\n--\n 本資料由%s%s自動產生\n\n", BBSNAME, REPORT_AUTHOR);
return 0;
}
void usage(const char *myname) {
fprintf(stderr, "Usage: %s [-m user][-b board]\n", myname);
exit(1);
}
int main(int argc, char *argv[]){
AngelRecord *rec, *angels;
int count, i, iangel;
int uid, bid;
const char *myname = argv[0];
const char *target = NULL;
int target_is_user = 0;
char target_name[PATHLEN];
char output_path[PATHLEN] = "", output_dir[PATHLEN] = "";
struct fileheader_t fhdr;
FILE *fp = stdout;
chdir(BBSHOME);
attach_SHM();
while (argc > 2) {
if (strcmp(argv[1], "-m") == 0) {
target = argv[2];
target_is_user = 1;
argc -= 2, argv += 2;
if ((uid = searchuser(target, target_name)) < 1)
die("Invalid user: %s\n", target);
target = target_name;
sethomepath(output_path, target);
sethomedir(output_dir, target);
} else if (strcmp(argv[1], "-b") == 0) {
boardheader_t *bp;
target = argv[2];
target_is_user = 0;
argc -= 2, argv += 2;
if ((bid = getbnum(target)) < 1)
die("Invalid board: %s\n", target);
bp = getbcache(bid);
strlcpy(target_name, bp->brdname, sizeof(target_name));
target = target_name;
setbpath(output_path, target);
setbfile(output_dir, target, ".DIR");
} else {
usage(myname);
}
}
if (argc != 1)
usage(myname);
if (target) {
stampfile(output_path, &fhdr);
fp = fopen(output_path, "wt");
if (!fp)
die("Failed to create: %s\n", output_path);
}
rec = (AngelRecord *)malloc(sizeof(AngelRecord) * MAX_USERS);
assert(rec);
count = buildMasterInfo(rec, MAX_USERS);
// TODO remove expired angels.
angels = (AngelRecord *)malloc(sizeof(AngelRecord) * count);
assert(angels);
for (i = 0, iangel = 0; i < MAX_USERS; i++) {
if (!rec[i].is_angel)
continue;
memcpy(angels + iangel, rec + i, sizeof(AngelRecord));
iangel++;
}
qsort(angels, count, sizeof(AngelRecord), sortAngelRecord);
generateReport(fp, angels, count, target ? 1 : 0);
if (target) {
fclose(fp);
strlcpy(fhdr.title, REPORT_SUBJECT, sizeof(fhdr.title));
strlcpy(fhdr.owner, REPORT_AUTHOR, sizeof(fhdr.owner));
append_record(output_dir, &fhdr, sizeof(fhdr));
if (target_is_user) {
userinfo_t *uentp = search_ulistn(uid, 1);
if (uentp)
uentp->alerts |= ALERT_NEW_MAIL;
} else {
touchbtotal(bid);
}
}
return 0;
}
#endif /* defined PLAY_ANGEL */