I'm trying to mark a message/list of messages as "\SEEN" (permanently) using IMAP . However unlike fetch, search and friends there seem to be no Flag function on the imap package. Should I send raw commands with the UIDs ?
You have to select the mailbox as writable
youImapConnection.Select(mailboxName, false) // true would be for readonly
And then simply do the following
seq, _ := imap.NewSeqSet("")
err := seq.AddNum(612) // 612 is your UID
_, err = imap.Wait(youImapConnection.UIDStore(seq, "+FLAGS", imap.NewFlagSet(`\Seen`))) // Here you tell to add the flag \Seen
Finally you will have to expunge:
_, err := imap.Wait(youImapConnection.Close(true)) // Here you tell to apply changes, necessary if you mark an Email as deleted
And you should be good :-)
And do not hesitate to browse the doc/source code, it's easy to understand and you'll find all you need.
IMAP uses the STORE command to set flags on messages, e.g.:
foo UID STORE 135211 +FLAGS (\Seen)
So I'd guess that you should use the Store or UIDStore functions to set flags.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 months ago.
Improve this question
I'm trying to build a tui client for WhatsApp using whatsmeow.
After half a day of searching and reading through the docs, I still can't find a way to get the conversation data of individual contacts. Any help is appreciated.
I found ParseWebMessage but I'm not really sure how to use this.
chatJID, err := types.ParseJID(conv.GetId())
for _, historyMsg := range conv.GetMessages() {
evt, err := cli.ParseWebMessage(chatJID, historyMsg.GetMessage())
yourNormalEventHandler(evt)
}
Matter of fact I'm not even sure if this is what I'm looking for
Well, you basically linked to the part of the docs that contains the information you're looking for. The return type of the ParseWebMessage call is events.Message, documented here. It contains an Info field of type MessageInfo (again, documented here). In turn, this MessageInfo type embeds the MessageSource type see docs here which looks like this:
type MessageSource struct {
Chat JID // The chat where the message was sent.
Sender JID // The user who sent the message.
IsFromMe bool // Whether the message was sent by the current user instead of someone else.
IsGroup bool // Whether the chat is a group chat or broadcast list.
// When sending a read receipt to a broadcast list message, the Chat is the broadcast list
// and Sender is you, so this field contains the recipient of the read receipt.
BroadcastListOwner JID
}
So to get the contact who sent a given message, given your code evt, err := cli.ParseWebMessage(), you need to check:
evt, err := cli.ParseWebMessage(chatJID, historyMsg.GetMessage())
if err != nil {
// handle error, of course
}
fmt.Printf("Sender ID: %s\nSent in Chat: %s\n", evt.Info.Sender, evt.Info.Chat)
if evt.Info.IsGroup {
fmt.Printf("%s is a group chat\n", evt.Info.Chat)
}
You can also skip messages you sent by simply doing this:
if evt.Info.IsFromMe {
continue
}
The evt.Info.Chat and evt.Info.Sender fields are all of type JID, documented here. There essentially are 2 variations of this ID type: user and server JID's and AD-JIDs (user, agent, and device). You can distinguish between the two by checking the JID.AD flag.
I haven't used this module at all, I only scanned through the docs briefly, but as I understand it, this module allows you to write a handler which will receive an events.Message type for everything you receive. By checking the evt.Info.IsGroup, you can work out whether the message we sent in a group chat, or in your person-to-person conversation thing. Based on evt.Info.Sender and evt.Info.Chat, you can work out who sent the message. The evt.Info.Sender being a JID in turn allows you to call the GetUserInfo method, passing in the JID, which gets you a UserInfo object in return as documented here, showing the name, picture, status, etc...
So I guess you're looking for something along these lines:
// some map of all messages from a given person, sent directly to you
contacts := cli.GetAllContacts() // returns map[JID]ContactInfo
personMsg := map[string][]*events.Message
evt, err := cli.ParseWebMessage(chatJID, historyMsg.GetMessage())
if err != nil {
// handle
}
if !evt.Info.IsFromMe && !evt.Info.IsGroup {// not a group, not sent by me
info, _ := cli.GetUserInfo([]types.JID{evt.Info.Sender})
if contact, ok := contacts[info[evt.Info.Sender]; ok {
msgs, ok := personMsg[contact.PushName]
if !ok {
msgs := []*events.Message{}
}
personMsg[contact.PushName] = append(msgs, evt)
}
}
Note the ContatInfo type didn't show up in the docs right away, but I stumbled across it in the repo.
Either way, I'm not quite sure what you're trying to do, and how/why you're stuck. All it took to find this information was to check the return type of the ParseWebMessage method you mentioned, check a couple of types, and scroll through some of the listed/documented methods to get a rough idea of how you can get all the data you could possibly need...
I want to start a child process (i'm on windows 10) and I would like to be able to suspend and resume the process at will.
I found this neat undocumented windows function NtSuspendProcess from ntdll.dll that should do the job but now I need to get the handle of the process to issue the suspend command.
this is an example:
modntdll = syscall.NewLazyDLL("ntdll.dll")
procNtSuspendProcess = modntdll.NewProc("NtSuspendProcess")
procNtResumeProcess = modntdll.NewProc("NtResumeProcess")
_, _, err = procNtSuspendProcess.Call(uintptr(handle))
_, _, err = procNtResumeProcess.Call(uintptr(handle))
To start the process I would normally use the exec.Command function but I can't find a way to retrieve the handle of the process.
Is there a way to get the handle when starting a process?
If not with exec.Command, what other library should I use to start a process that returns also the process handle?
As a side note:
I've looked into syscall.StartProcess but it's quite low level and I don't feel able to handle such a raw implementation.
_, handle, err := syscall.StartProcess("C:\\WINDOWS\\system32\\cmd.exe", []string{}, procAttr)
Go does not publicly expose the handle in exec.Command, you will have to access it either by.
Reflection
cmd := exec.Command("cmd.exe")
cmd.Start()
handle := uintptr(reflect.ValueOf(cmd.Process).Elem().FieldByName("handle").Uint())
or by creating an identical Process type and casting the Cmd.Process to your own type to access the private fields.
type Process struct {
Pid int
handle uintptr
isdone uint32
sigMu sync.RWMutex
}
cmd := exec.Command("cmd.exe")
cmd.Start()
proc := (*Process)(unsafe.Pointer(cmd.Process))
println(proc.handle)
The answer by "Make that 4" were both flawless, being simple and well explained.
I would just add an additional method that I found, just for completeness (requires the import of golang.org/x/sys/windows)
Update: apparently this method might lead to bugs/errors and it's probably better not to implement it (check the comments)
cmd := exec.Command("cmd.exe")
cmd.Start()
// using PROCESS_SUSPEND_RESUME since I want to call NtSuspendProcess function
handle, _ := windows.OpenProcess(windows.PROCESS_SUSPEND_RESUME, false, uint32(cmd.Process.Pid))
defer windows.CloseHandle(handle)
fmt.Println(handle)
I would love to be able to set my executable to handle custom Url Scheme (aaa:) so that I can handle deep linking with my program.
You need to modify Windows registry, in order to tell os which protocol to open with which executable.
There are multiple ways you can go about it, depending if you want to add your url scheme handler for all users or for current user.
Easiest way to handle it is to make Windows pass custom url as argument to default executable.
That way both chrome and edge will ask user to open your installed app.
Here is a minimal Golang implementation to set your executable as default url scheme handler:
var k registry.Key
var err error
prefix := "SOFTWARE\\Classes\\"
urlScheme := "aaa"
basePath := prefix + urlScheme
permission := uint32(registry.QUERY_VALUE | registry.SET_VALUE)
baseKey := registry.CURRENT_USER
programLocation := "\"C:\\Windows\\notepad.exe\""
// create key
registry.CreateKey(baseKey, basePath, permission)
// set description
k.SetStringValue("", "Notepad app")
k.SetStringValue("URL Protocol", "")
// set icon
registry.CreateKey(registry.CURRENT_USER, "lumiere\\DefaultIcon", registry.ALL_ACCESS)
k.SetStringValue("", softwareToOpen+",1")
// create tree
registry.CreateKey(baseKey, basePath+"\\shell", permission)
registry.CreateKey(baseKey, basePath+"\\shell\\open", permission)
registry.CreateKey(baseKey, basePath+"\\shell\\open\\command", permission)
// set open command
k.SetStringValue("", softwareToOpen+" \"%1\"")
Getting custom URL after having your app set as default is quite straightforward
You can do this:
func main() {
url := os.Args[1:]
log.Printf("my custom aaa url is: %s", url)
}
I am going through Gmail API docs(https://developers.google.com/gmail/api), I am able to read all the user emails which are present in the inbox.
eg snippet (reading complete list of emails):
for {
req := svc.Users.Messages.List("me")
r, _ := req.Do()
for _, m := range r.Messages {
msg, _ := svc.Users.Messages.Get("me", m.Id).Do()
date := ""
for _, h := range msg.Payload.Headers {
if h.Name == "Date" {
date = h.Value
break
}
}
msgs = append(msgs, message{
...
})
}
}
Now, when new emails come I want to read them as well (either immediately or after some time). I can write a scheduled job for that purpose, But I am not sure if I can fetch email after a particular timestamp or after an email identifier. I don't want to read a whole bunch of emails, again and again, to figure out the new emails, in this way, there is a lot of unnecessary computation being involved. Is there any way I can make this task easier?
Looking at the docs, it looks like it supports a query parameter, q.
The query parameter supports the same options as available in the Gmail search bar:
Only return messages matching the specified query. Supports the same query format as the Gmail search box. For example, "from:someuser#example.com rfc822msgid:somemsgid#example.com is:unread". Parameter cannot be used when accessing the api using the gmail.metadata scope.
This means you can do something like "after:YYYY/MM/DD" or with a timestamp "after:1616819452".
req := svc.Users.Messages.List("me").Q("after:2021/01/01")
See the full usage here https://pkg.go.dev/google.golang.org/api/gmail/v1#UsersMessagesListCall.Q
I have previously been using this:
data, err := redis.Bytes(c.Do("GET", key))
to make sure that data returned is a slice of bytes.
However, I now need to add an extra command to the Redis request so I have something like this:
c.Send("MULTI")
c.Send("GET", key)
c.Send("EXPIRE", key)
r, err := c.Do("EXEC")
but now I can't seem to make the GET command return a slice of bytes. I've tried adding redis.Bytes like below but no luck.
c.Send("MULTI")
redis.Bytes(c.Send("GET", key))
c.Send("EXPIRE", key)
r, err := c.Do("EXEC")
In redis, the EXEC command returns an array containing the results of all the commands in the transaction.
redigo provides a Values function, which converts an array command reply to a []interface{}.
c.Send("MULTI")
c.Send("GET", key)
c.Send("EXPIRE", key)
r, err := redis.Values(c.Do("EXEC"))
r[0] now has the reply from your GET command as a interface{}, so you'll need to do a type assertion to get the slice of bytes you're expecting:
data := r[0].([]byte)
References
func Values: https://godoc.org/github.com/garyburd/redigo/redis#Values
Type assertions: https://golang.org/ref/spec#Type_assertions
MULTI is used to send several commands in an atomic way to Redis, by creating a transaction. This is not a pipeline at all.
None of the commands will be actually executed before the EXEC call so it is impossible to obtain the value when you call GET from within a transaction.
From the docs:
When a Redis connection is in the context of a MULTI request, all commands will reply with the string QUEUED (sent as a Status Reply from the point of view of the Redis protocol). A queued command is simply scheduled for execution when EXEC is called.
In redigo pipelining is done in a different way:
http://godoc.org/github.com/garyburd/redigo/redis#hdr-Pipelining
What you want to do is something like this (untested):
c.Send("GET", key)
c.Send("EXPIRE", key)
c.Flush()
v := redis.Bytes(c.Receive()) // reply from GET
_, err = c.Receive() // reply from EXPIRE