1 // mmc -- Mattermost client
2 // Copyright (C) 2023-2024 Sergey Matveev <stargrave@stargrave.org>
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
27 "github.com/davecgh/go-spew/spew"
28 "github.com/mattermost/mattermost-server/v6/model"
29 "go.cypherpunks.su/recfile/v2"
30 "go.stargrave.org/mmc/internal"
33 const CmdFile = "/FILE "
35 func writePosts(where string, users map[string]*model.User, posts []mmc.Post) error {
39 unlock, err := mmc.Lock(path.Join(where, mmc.OutRecLock))
44 fd, err := os.OpenFile(
45 path.Join(where, mmc.OutRec),
46 os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o666,
52 w := recfile.NewWriter(fd)
54 for _, post := range posts {
55 if err = mmc.PostToRec(w, users, post); err != nil {
58 lastPostId = post.P.Id
60 tmp, err := os.CreateTemp(where, "last")
64 err = os.Chmod(tmp.Name(), os.FileMode(0666&^UmaskCur))
70 if _, err = tmp.WriteString(lastPostId + "\n"); err != nil {
75 if err = tmp.Close(); err != nil {
79 if err = os.Rename(tmp.Name(), path.Join(where, mmc.Last)); err != nil {
85 exec.Command(*Newwin, where).Run()
90 func updatePosts(c *model.Client4, users map[string]*model.User, where, chId string) error {
91 data, err := os.ReadFile(path.Join(where, mmc.Last))
93 if os.IsNotExist(err) {
98 lastPostId := strings.TrimRight(string(data), "\n")
103 time.Sleep(mmc.SleepTime)
104 list, resp, err := c.GetPostsAfter(
105 chId, lastPostId, n, mmc.PerPage, "", false,
108 spew.Fdump(DebugFd, list, resp)
110 if resp.StatusCode == http.StatusNotFound {
117 for _, post := range list.ToSlice() {
118 posts = append(posts, mmc.Post{P: post, E: model.WebsocketEventPosted})
120 if err = writePosts(where, users, posts); err != nil {
123 if len(posts) < mmc.PerPage {
130 func makePost(c *model.Client4, chId, text string) (*model.Post, error) {
131 text = strings.TrimRight(text, " \n")
135 post := &model.Post{ChannelId: chId}
137 for _, line := range strings.Split(text, "\n") {
138 if !strings.HasPrefix(line, CmdFile) {
139 lines = append(lines, line)
142 fn := strings.TrimPrefix(line, CmdFile)
143 data, err := os.ReadFile(fn)
147 resp, _, err := c.UploadFile(data, chId, path.Base(fn))
151 post.FileIds = append(post.FileIds, resp.FileInfos[0].Id)
153 post.Message = strings.Join(lines, "\n")
154 post, _, err := c.CreatePost(post)