|
@@ -1311,6 +1311,300 @@ func lusersHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Re
|
1311
|
1311
|
return false
|
1312
|
1312
|
}
|
1313
|
1313
|
|
|
1314
|
+// METADATA * SUB <key>{ <key>}
|
|
1315
|
+// METADATA * SUBS
|
|
1316
|
+// METADATA * UNSUB <key>{ <key>}
|
|
1317
|
+// METADATA <target> CLEAR
|
|
1318
|
+// METADATA <target> GET <key>{ <key>}
|
|
1319
|
+// METADATA <target> LIST
|
|
1320
|
+// METADATA <target> SET <key> [<value>]
|
|
1321
|
+// METADATA <target> SYNC
|
|
1322
|
+func metadataHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
|
1323
|
+ handler, exists := metadataSubcommands[strings.ToLower(msg.Params[1])]
|
|
1324
|
+
|
|
1325
|
+ if !exists {
|
|
1326
|
+ rb.Add(nil, server.name, ERR_UNKNOWNERROR, client.Nick(), "METADATA", client.t("Unknown subcommand"))
|
|
1327
|
+ return false
|
|
1328
|
+ }
|
|
1329
|
+
|
|
1330
|
+ return handler(server, client, msg, rb)
|
|
1331
|
+}
|
|
1332
|
+
|
|
1333
|
+// METADATA <target> CLEAR
|
|
1334
|
+func metadataClearHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
|
1335
|
+ var mm *MetadataManager
|
|
1336
|
+
|
|
1337
|
+ targetString := msg.Params[0]
|
|
1338
|
+ target, err := CasefoldChannel(targetString)
|
|
1339
|
+ if err == nil {
|
|
1340
|
+ channel := server.channels.Get(target)
|
|
1341
|
+ if channel == nil {
|
|
1342
|
+ rb.Add(nil, server.name, ERR_TARGETINVALID, client.nick, target, client.t("Invalid metadata target"))
|
|
1343
|
+ return false
|
|
1344
|
+ }
|
|
1345
|
+ if !channel.ClientIsAtLeast(client, modes.ChannelOperator) {
|
|
1346
|
+ rb.Add(nil, server.name, ERR_CHANOPRIVSNEEDED, client.nick, targetString, client.t("You're not a channel operator"))
|
|
1347
|
+ return false
|
|
1348
|
+ }
|
|
1349
|
+ mm = channel.metadata
|
|
1350
|
+ } else {
|
|
1351
|
+ target, err = CasefoldName(targetString)
|
|
1352
|
+ user := server.clients.Get(target)
|
|
1353
|
+ if err != nil || user == nil {
|
|
1354
|
+ if len(target) > 0 {
|
|
1355
|
+ rb.Add(nil, server.name, ERR_TARGETINVALID, client.nick, target, client.t("Invalid metadata target"))
|
|
1356
|
+ } else {
|
|
1357
|
+ rb.Add(nil, server.name, ERR_UNKNOWNERROR, client.Nick(), "METADATA", client.t("Unknown error"))
|
|
1358
|
+ }
|
|
1359
|
+ return false
|
|
1360
|
+ }
|
|
1361
|
+ if user != client {
|
|
1362
|
+ rb.Add(nil, server.name, ERR_KEYNOPERMISSION, client.nick, target, "*", client.t("Permission denied"))
|
|
1363
|
+ return false
|
|
1364
|
+ }
|
|
1365
|
+ mm = user.metadata
|
|
1366
|
+ }
|
|
1367
|
+
|
|
1368
|
+ for _, key := range mm.Clear() {
|
|
1369
|
+ rb.Add(nil, server.name, RPL_KEYVALUE, client.nick, target, key, "*")
|
|
1370
|
+ }
|
|
1371
|
+ rb.Add(nil, server.name, RPL_METADATAEND, client.nick, client.t("End of metadata"))
|
|
1372
|
+
|
|
1373
|
+ return false
|
|
1374
|
+}
|
|
1375
|
+
|
|
1376
|
+// METADATA <target> GET <key>{ <key>}
|
|
1377
|
+func metadataGetHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
|
1378
|
+ if len(msg.Params) < 3 {
|
|
1379
|
+ rb.Add(nil, server.name, ERR_NEEDMOREPARAMS, client.Nick(), msg.Command, client.t("Not enough parameters"))
|
|
1380
|
+ return false
|
|
1381
|
+ }
|
|
1382
|
+
|
|
1383
|
+ var mm *MetadataManager
|
|
1384
|
+
|
|
1385
|
+ targetString := msg.Params[0]
|
|
1386
|
+ target, err := CasefoldChannel(targetString)
|
|
1387
|
+ if err == nil {
|
|
1388
|
+ channel := server.channels.Get(target)
|
|
1389
|
+ if channel == nil {
|
|
1390
|
+ rb.Add(nil, server.name, ERR_TARGETINVALID, client.nick, target, client.t("Invalid metadata target"))
|
|
1391
|
+ return false
|
|
1392
|
+ }
|
|
1393
|
+ if !channel.hasClient(client) {
|
|
1394
|
+ rb.Add(nil, server.name, ERR_KEYNOPERMISSION, client.nick, target, client.t("You're not on that channel!"))
|
|
1395
|
+ return false
|
|
1396
|
+ }
|
|
1397
|
+ mm = channel.metadata
|
|
1398
|
+ } else {
|
|
1399
|
+ target, err = CasefoldName(targetString)
|
|
1400
|
+ user := server.clients.Get(target)
|
|
1401
|
+ if err != nil || user == nil {
|
|
1402
|
+ if len(target) > 0 {
|
|
1403
|
+ rb.Add(nil, server.name, ERR_TARGETINVALID, client.nick, target, client.t("Invalid metadata target"))
|
|
1404
|
+ } else {
|
|
1405
|
+ rb.Add(nil, server.name, ERR_UNKNOWNERROR, client.Nick(), "METADATA", client.t("Unknown error"))
|
|
1406
|
+ }
|
|
1407
|
+ return false
|
|
1408
|
+ }
|
|
1409
|
+ mm = user.metadata
|
|
1410
|
+ }
|
|
1411
|
+
|
|
1412
|
+ for i, key := range msg.Params {
|
|
1413
|
+ // only process actual keys, skip target and (sub)command name
|
|
1414
|
+ if 1 < i {
|
|
1415
|
+ key = strings.TrimSpace(strings.ToLower(key))
|
|
1416
|
+ if !metadataKeyValid(key) {
|
|
1417
|
+ rb.Add(nil, server.name, ERR_KEYINVALID, client.nick, key)
|
|
1418
|
+ continue
|
|
1419
|
+ }
|
|
1420
|
+ value, exists := mm.Get(key)
|
|
1421
|
+ if !exists {
|
|
1422
|
+ rb.Add(nil, server.name, ERR_NOMATCHINGKEY, client.nick, target, key, client.t("No matching key"))
|
|
1423
|
+ continue
|
|
1424
|
+ }
|
|
1425
|
+
|
|
1426
|
+ rb.Add(nil, server.name, RPL_KEYVALUE, client.nick, target, key, "*", value)
|
|
1427
|
+ }
|
|
1428
|
+ }
|
|
1429
|
+ return false
|
|
1430
|
+}
|
|
1431
|
+
|
|
1432
|
+// METADATA <target> LIST
|
|
1433
|
+func metadataListHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
|
1434
|
+ var mm *MetadataManager
|
|
1435
|
+
|
|
1436
|
+ targetString := msg.Params[0]
|
|
1437
|
+ target, err := CasefoldChannel(targetString)
|
|
1438
|
+ if err == nil {
|
|
1439
|
+ channel := server.channels.Get(target)
|
|
1440
|
+ if channel == nil {
|
|
1441
|
+ rb.Add(nil, server.name, ERR_TARGETINVALID, client.nick, target, client.t("Invalid metadata target"))
|
|
1442
|
+ return false
|
|
1443
|
+ }
|
|
1444
|
+ if !channel.hasClient(client) {
|
|
1445
|
+ rb.Add(nil, server.name, ERR_KEYNOPERMISSION, client.nick, target, client.t("You're not on that channel!"))
|
|
1446
|
+ return false
|
|
1447
|
+ }
|
|
1448
|
+ mm = channel.metadata
|
|
1449
|
+ } else {
|
|
1450
|
+ target, err = CasefoldName(targetString)
|
|
1451
|
+ user := server.clients.Get(target)
|
|
1452
|
+ if err != nil || user == nil {
|
|
1453
|
+ if len(target) > 0 {
|
|
1454
|
+ rb.Add(nil, server.name, ERR_TARGETINVALID, client.nick, target, client.t("Invalid metadata target"))
|
|
1455
|
+ } else {
|
|
1456
|
+ rb.Add(nil, server.name, ERR_UNKNOWNERROR, client.Nick(), "METADATA", client.t("Unknown error"))
|
|
1457
|
+ }
|
|
1458
|
+ return false
|
|
1459
|
+ }
|
|
1460
|
+ mm = user.metadata
|
|
1461
|
+ }
|
|
1462
|
+
|
|
1463
|
+ for key, value := range mm.List() {
|
|
1464
|
+ rb.Add(nil, server.name, RPL_KEYVALUE, client.nick, target, key, "*", value)
|
|
1465
|
+ }
|
|
1466
|
+ rb.Add(nil, server.name, RPL_METADATAEND, client.nick, client.t("End of metadata"))
|
|
1467
|
+
|
|
1468
|
+ return false
|
|
1469
|
+}
|
|
1470
|
+
|
|
1471
|
+// METADATA <target> SET <key> [<value>]
|
|
1472
|
+func metadataSetHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
|
1473
|
+ if len(msg.Params) < 3 {
|
|
1474
|
+ rb.Add(nil, server.name, ERR_NEEDMOREPARAMS, client.Nick(), msg.Command, client.t("Not enough parameters"))
|
|
1475
|
+ return false
|
|
1476
|
+ }
|
|
1477
|
+
|
|
1478
|
+ // retrieve key/value
|
|
1479
|
+ key := strings.TrimSpace(strings.ToLower(msg.Params[2]))
|
|
1480
|
+ if !metadataKeyValid(key) {
|
|
1481
|
+ rb.Add(nil, server.name, ERR_KEYINVALID, client.nick, key)
|
|
1482
|
+ return false
|
|
1483
|
+ }
|
|
1484
|
+
|
|
1485
|
+ var settingValue bool
|
|
1486
|
+ var value string
|
|
1487
|
+ if 3 < len(msg.Params) {
|
|
1488
|
+ settingValue = true
|
|
1489
|
+ value = msg.Params[3]
|
|
1490
|
+ }
|
|
1491
|
+
|
|
1492
|
+ // work on target
|
|
1493
|
+ targetString := msg.Params[0]
|
|
1494
|
+ target, err := CasefoldChannel(targetString)
|
|
1495
|
+ if err == nil {
|
|
1496
|
+ channel := server.channels.Get(target)
|
|
1497
|
+ if channel == nil {
|
|
1498
|
+ rb.Add(nil, server.name, ERR_TARGETINVALID, client.nick, target, client.t("Invalid metadata target"))
|
|
1499
|
+ return false
|
|
1500
|
+ }
|
|
1501
|
+ if !channel.ClientIsAtLeast(client, modes.ChannelOperator) {
|
|
1502
|
+ rb.Add(nil, server.name, ERR_CHANOPRIVSNEEDED, client.nick, targetString, client.t("You're not a channel operator"))
|
|
1503
|
+ return false
|
|
1504
|
+ }
|
|
1505
|
+ if settingValue {
|
|
1506
|
+ err := channel.metadata.Set(key, value, server.MetadataKeysLimit())
|
|
1507
|
+ if err == errTooManyKeys {
|
|
1508
|
+ rb.Add(nil, server.name, ERR_METADATALIMIT, client.nick, target, client.t("Metadata limit reached"))
|
|
1509
|
+ return false
|
|
1510
|
+ }
|
|
1511
|
+ } else {
|
|
1512
|
+ channel.metadata.Delete(key)
|
|
1513
|
+ }
|
|
1514
|
+ } else {
|
|
1515
|
+ target, err = CasefoldName(targetString)
|
|
1516
|
+ user := server.clients.Get(target)
|
|
1517
|
+ if err != nil || user == nil {
|
|
1518
|
+ if len(target) > 0 {
|
|
1519
|
+ rb.Add(nil, server.name, ERR_TARGETINVALID, client.nick, target, client.t("Invalid metadata target"))
|
|
1520
|
+ } else {
|
|
1521
|
+ rb.Add(nil, server.name, ERR_UNKNOWNERROR, client.Nick(), "METADATA", client.t("Unknown error"))
|
|
1522
|
+ }
|
|
1523
|
+ return false
|
|
1524
|
+ }
|
|
1525
|
+ if user != client {
|
|
1526
|
+ rb.Add(nil, server.name, ERR_KEYNOPERMISSION, client.nick, target, "*", client.t("Permission denied"))
|
|
1527
|
+ return false
|
|
1528
|
+ }
|
|
1529
|
+ if settingValue {
|
|
1530
|
+ err := user.metadata.Set(key, value, server.MetadataKeysLimit())
|
|
1531
|
+ if err == errTooManyKeys {
|
|
1532
|
+ rb.Add(nil, server.name, ERR_METADATALIMIT, client.nick, target, client.t("Metadata limit reached"))
|
|
1533
|
+ return false
|
|
1534
|
+ }
|
|
1535
|
+ } else {
|
|
1536
|
+ user.metadata.Delete(key)
|
|
1537
|
+ }
|
|
1538
|
+ }
|
|
1539
|
+
|
|
1540
|
+ if settingValue {
|
|
1541
|
+ rb.Add(nil, server.name, RPL_KEYVALUE, client.nick, target, key, "*", value)
|
|
1542
|
+ } else {
|
|
1543
|
+ rb.Add(nil, server.name, RPL_KEYVALUE, client.nick, target, key, "*")
|
|
1544
|
+ }
|
|
1545
|
+ rb.Add(nil, server.name, RPL_METADATAEND, client.nick, client.t("End of metadata"))
|
|
1546
|
+
|
|
1547
|
+ return false
|
|
1548
|
+}
|
|
1549
|
+
|
|
1550
|
+func metadataSubHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
|
1551
|
+ client.Notice("METADATA SUB not yet implemented")
|
|
1552
|
+ return false
|
|
1553
|
+}
|
|
1554
|
+
|
|
1555
|
+func metadataSubsHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
|
1556
|
+ client.Notice("METADATA SUBS not yet implemented")
|
|
1557
|
+ return false
|
|
1558
|
+}
|
|
1559
|
+
|
|
1560
|
+// METADATA <target> SYNC
|
|
1561
|
+//TODO(dan): SYNC also returns e.g. metadata keys of friends in the given channel, etc.
|
|
1562
|
+//Note:
|
|
1563
|
+// One difference with list is that you can’t get a whole channel full of members metadata with it.
|
|
1564
|
+// With sync you can, you get targets you didn’t explicitly request. It’s more of a trigger than a request.
|
|
1565
|
+// And it’s mainly only useful for the delayed synchronisation function.
|
|
1566
|
+func metadataSyncHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
|
1567
|
+ var mm *MetadataManager
|
|
1568
|
+
|
|
1569
|
+ targetString := msg.Params[0]
|
|
1570
|
+ target, err := CasefoldChannel(targetString)
|
|
1571
|
+ if err == nil {
|
|
1572
|
+ channel := server.channels.Get(target)
|
|
1573
|
+ if channel == nil {
|
|
1574
|
+ rb.Add(nil, server.name, ERR_TARGETINVALID, client.nick, target, client.t("Invalid metadata target"))
|
|
1575
|
+ return false
|
|
1576
|
+ }
|
|
1577
|
+ if !channel.hasClient(client) {
|
|
1578
|
+ rb.Add(nil, server.name, ERR_KEYNOPERMISSION, client.nick, target, client.t("You're not on that channel!"))
|
|
1579
|
+ return false
|
|
1580
|
+ }
|
|
1581
|
+ mm = channel.metadata
|
|
1582
|
+ } else {
|
|
1583
|
+ target, err = CasefoldName(targetString)
|
|
1584
|
+ user := server.clients.Get(target)
|
|
1585
|
+ if err != nil || user == nil {
|
|
1586
|
+ if len(target) > 0 {
|
|
1587
|
+ rb.Add(nil, server.name, ERR_TARGETINVALID, client.nick, target, client.t("Invalid metadata target"))
|
|
1588
|
+ } else {
|
|
1589
|
+ rb.Add(nil, server.name, ERR_UNKNOWNERROR, client.Nick(), "METADATA", client.t("Unknown error"))
|
|
1590
|
+ }
|
|
1591
|
+ return false
|
|
1592
|
+ }
|
|
1593
|
+ mm = user.metadata
|
|
1594
|
+ }
|
|
1595
|
+
|
|
1596
|
+ for key, value := range mm.List() {
|
|
1597
|
+ rb.Add(nil, server.name, "METADATA", target, key, "*", value)
|
|
1598
|
+ }
|
|
1599
|
+
|
|
1600
|
+ return false
|
|
1601
|
+}
|
|
1602
|
+
|
|
1603
|
+func metadataUnsubHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
|
1604
|
+ client.Notice("METADATA UNSUB not yet implemented")
|
|
1605
|
+ return false
|
|
1606
|
+}
|
|
1607
|
+
|
1314
|
1608
|
// MODE <target> [<modestring> [<mode arguments>...]]
|
1315
|
1609
|
func modeHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
1316
|
1610
|
_, errChan := CasefoldChannel(msg.Params[0])
|
|
@@ -1448,7 +1742,7 @@ func monitorHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *R
|
1448
|
1742
|
handler, exists := monitorSubcommands[strings.ToLower(msg.Params[0])]
|
1449
|
1743
|
|
1450
|
1744
|
if !exists {
|
1451
|
|
- rb.Add(nil, server.name, ERR_UNKNOWNERROR, client.Nick(), "MONITOR", msg.Params[0], client.t("Unknown subcommand"))
|
|
1745
|
+ rb.Add(nil, server.name, ERR_UNKNOWNERROR, client.Nick(), "MONITOR", client.t("Unknown subcommand"))
|
1452
|
1746
|
return false
|
1453
|
1747
|
}
|
1454
|
1748
|
|