$ git clone https://socialnetwork.ion.nu/socialnetwork.git
commit 00fbcf33aec0eb140e39f0ab5964e38ed9c0454d
Author: Alicia <...>
Date: Wed Jan 18 22:20:48 2017 +0100
Implemented more of circles (friendslists)
diff --git a/Makefile b/Makefile
index 390b28c..d3f053f 100644
--- a/Makefile
+++ b/Makefile
@@ -13,3 +13,6 @@ peertest: peertest.o peer.o udpstream.o
udptest: udptest.o udpstream.o
$(CC) $^ -o $@
+
+clean:
+ rm -f *.o *.so socialtest peertest udptest
diff --git a/social.c b/social.c
index 2958012..a0d82b3 100644
--- a/social.c
+++ b/social.c
@@ -207,7 +207,7 @@ void social_findfriends(void) // Call a second or so after init (once we have so
}
}
-static struct friendslist* user_getcircle(struct user* user, uint32_t circle)
+struct friendslist* social_user_getcircle(struct user* user, uint32_t circle)
{
if(circle>=user->circlecount)
{
@@ -229,12 +229,29 @@ void social_user_addtocircle(struct user* user, uint32_t circle, const unsigned
{
struct user* friend=social_finduser(id);
if(!friend){friend=user_new(id);}
- struct friendslist* c=user_getcircle(user, circle);
+ struct friendslist* c=social_user_getcircle(user, circle);
++c->count;
c->friends=realloc(c->friends, sizeof(void*)*c->count);
c->friends[c->count-1]=friend;
}
+void social_user_removefromcircle(struct user* user, uint32_t circle, const unsigned char id[20])
+{
+ struct user* friend=social_finduser(id);
+ if(!friend){friend=user_new(id);}
+ struct friendslist* c=social_user_getcircle(user, circle);
+ unsigned int i;
+ for(i=0; i<c->count; ++i)
+ {
+ if(c->friends[i]==friend)
+ {
+ --c->count;
+ memmove(&c->friends[i], &c->friends[i+1], sizeof(void*)*(c->count-i));
+ // TODO: Garbage-collect users who are no longer friends of anyone we know?
+ }
+ }
+}
+
void social_addfriend(const unsigned char id[20], uint32_t circle)
{
struct user* friend=social_finduser(id);
@@ -242,6 +259,7 @@ void social_addfriend(const unsigned char id[20], uint32_t circle)
if(!friend->peer)
{
peer_findpeer(id);
+ // TODO: Request updates from any mutual friends we're connected to in the meantime
}else{
if(!friend->pubkey)
{
@@ -260,7 +278,6 @@ void social_addfriend(const unsigned char id[20], uint32_t circle)
struct update* update=social_update_getfriend(social_self, circle, id);
++social_self->seq;
update->seq=social_self->seq;
- update->type=UPDATE_FRIENDS;
update->timestamp=time(0);
privcpy(update->privacy, social_self->circles[circle].privacy);
update->friends.add=1;
@@ -269,6 +286,21 @@ void social_addfriend(const unsigned char id[20], uint32_t circle)
social_shareupdate(update);
}
+void social_removefriend(const unsigned char id[20], uint32_t circle)
+{
+ social_user_removefromcircle(social_self, circle, id);
+ struct update* update=social_update_getfriend(social_self, circle, id);
+ ++social_self->seq;
+ update->seq=social_self->seq;
+ update->type=UPDATE_FRIENDS;
+ update->timestamp=time(0);
+ privcpy(update->privacy, social_self->circles[circle].privacy);
+ update->friends.add=0;
+ social_update_sign(update);
+ social_update_save(social_self, update);
+ social_shareupdate(update);
+}
+
void social_createpost(const char* msg, struct privacy* privacy)
{
// TODO: Posts attached to users and/or users' updates
@@ -289,7 +321,6 @@ void social_updatefield(const char* name, const char* value, struct privacy* pri
struct update* post=social_update_getfield(social_self, name);
++social_self->seq;
post->seq=social_self->seq;
- post->type=UPDATE_FIELD;
post->timestamp=time(0);
privcpy(post->privacy, *privacy);
post->field.value=strdup(value);
@@ -353,3 +384,23 @@ char social_privacy_check(struct user* origin, struct privacy* privacy, struct u
}
return 0;
}
+
+void social_setcircle(uint32_t circle, const char* name, struct privacy* privacy)
+{
+ struct friendslist* c=social_user_getcircle(social_self, circle);
+ free(c->name);
+ c->name=strdup(name);
+ privcpy(c->privacy, *privacy);
+ // Private circle update
+ struct update* update=social_update_getcircle(social_self, circle);
+ free((void*)update->circle.name);
+ ++social_self->seq;
+ update->seq=social_self->seq;
+ update->timestamp=time(0);
+ // TODO: Is there any situation where we would want this update to be public?
+ update->circle.circle=circle;
+ update->circle.name=strdup(name);
+ privcpy(update->circle.privacy, *privacy);
+ social_update_sign(update);
+ social_update_save(social_self, update);
+}
diff --git a/social.h b/social.h
index 8fb27fe..6bfce28 100644
--- a/social.h
+++ b/social.h
@@ -58,11 +58,15 @@ extern struct user** social_users;
extern unsigned int social_usercount;
extern struct user* social_self; // Most things we need to keep track of for ourself are the same things we need to keep track of for others
extern void social_init(const char* keypath);
+extern struct friendslist* social_user_getcircle(struct user* user, uint32_t circle);
extern void social_user_addtocircle(struct user* user, uint32_t circle, const unsigned char id[20]);
+extern void social_user_removefromcircle(struct user* user, uint32_t circle, const unsigned char id[20]);
extern void social_addfriend(const unsigned char id[20], uint32_t circle);
+extern void social_removefriend(const unsigned char id[20], uint32_t circle);
extern void social_createpost(const char* msg, struct privacy* privacy);
extern void social_updatefield(const char* name, const char* value, struct privacy* privacy);
extern struct user* social_finduser(const unsigned char id[20]);
extern void social_shareupdate(struct update* update);
extern char social_privacy_check(struct user* origin, struct privacy* privacy, struct user* user);
+extern void social_setcircle(uint32_t circle, const char* name, struct privacy* privacy);
#endif
diff --git a/socialtest.c b/socialtest.c
index 33e49e0..8269a7b 100644
--- a/socialtest.c
+++ b/socialtest.c
@@ -26,6 +26,35 @@
#include "social.h"
#include "update.h"
+// Inject after "Will be shown/visible to ..."
+void printprivacy(struct privacy* privacy)
+{
+ if(!privacy->flags)
+ {
+ if(!privacy->circlecount){printf("no one"); return;}
+ printf("the circles ");
+ unsigned int usertotal=0;
+ unsigned int i;
+ for(i=0; i<privacy->circlecount; ++i)
+ {
+ if(i){printf(", ");}
+ struct friendslist* circle=social_user_getcircle(social_self, privacy->circles[i]);
+ printf("'%s'", circle->name?circle->name:"Unnamed circle");
+ usertotal+=circle->count;
+ }
+ printf(", %u users in total", usertotal);
+ }
+ else if(privacy->flags&PRIVACY_ANYONE)
+ {
+ printf("anyone");
+ }
+ else if(privacy->flags&PRIVACY_FRIENDS)
+ {
+ printf("all friends");
+ }
+ else{printf("unknown privacy flag set!");}
+}
+
int main(int argc, char** argv)
{
int sock=socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
@@ -76,13 +105,21 @@ int main(int argc, char** argv)
{
struct update* update=&social_self->updates[i];
time_t timestamp=update->timestamp;
+ printf("\nVisible to ");
+ printprivacy(&update->privacy);
switch(update->type)
{
case UPDATE_FIELD:
- printf("\nField %s%s = %s\n", ctime(×tamp), update->field.name, update->field.value);
+ printf("\nField %s%s = %s", ctime(×tamp), update->field.name, update->field.value);
break;
case UPDATE_POST:
- printf("\nPost %s%s\n", ctime(×tamp), update->post.message);
+ printf("\nPost %s%s", ctime(×tamp), update->post.message);
+ break;
+ case UPDATE_FRIENDS:
+ printf("\nFriend %s%s\n", ctime(×tamp), update->friends.add?"Add":"Remove");
+ break;
+ case UPDATE_CIRCLE:
+ printf("\nCircle %s%u: %s\n", ctime(×tamp), update->circle.circle, update->circle.name);
break;
}
}
@@ -132,30 +169,16 @@ int main(int argc, char** argv)
for(i=0; i<social_self->circlecount; ++i)
{
struct friendslist* circle=&social_self->circles[i];
- printf("%u: %s (%u friends)\n", i, circle->name?circle->name:"Unnamed circle", circle->count);
+ printf("%u: %s (%u friends), additions/removals are visible to ", i, circle->name?circle->name:"Unnamed circle", circle->count);
+ printprivacy(&circle->privacy);
+ printf("\n");
}
}
else if(!strcmp(buf, "privacy"))
{
- if(!privacy.flags)
- {
- printf("%u circles of friends can see updates with this setting:\n", privacy.circlecount);
- for(i=0; i<privacy.circlecount; ++i)
- {
- if(privacy.circles[i]>=social_self->circlecount){printf("Undefined circle\n"); continue;}
- struct friendslist* circle=&social_self->circles[privacy.circles[i]];
- printf("%s (%u friends)\n", circle->name?circle->name:"Unnamed circle", circle->count);
- }
- }
- else if(privacy.flags&PRIVACY_ANYONE)
- {
- printf("Anyone can see updates with this setting\n");
- }
- else if(privacy.flags&PRIVACY_FRIENDS)
- {
- printf("Friends in any circle can see updates with this setting\n");
- }
- else{printf("Unknown privacy flag set!\n");}
+ printf("With this privacy setting updates will be visible to ");
+ printprivacy(&privacy);
+ printf("\n");
}
else if(!strncmp(buf, "privacy flag ", 13))
{
@@ -192,6 +215,17 @@ int main(int argc, char** argv)
printf("Added\n");
}
}
+ else if(!strncmp(buf, "setcircle ", 10))
+ {
+ uint32_t circle=strtoul(&buf[10], 0, 0);
+ printf("Enter name: "); fflush(stdout);
+ unsigned int len=read(0, buf, 1023);
+ buf[len]=0;
+ char* end;
+ while((end=strchr(buf, '\r'))||(end=strchr(buf, '\n'))){end[0]=0;}
+ // Note: we're also setting the privacy setting that will be referenced for future friend additions/removals from this circle, which might not be readily apparent. The generated update that sets the name (and privacy) of the circle is always private.
+ social_setcircle(circle, buf, &privacy);
+ }
else{printf("Unknown command '%s'\n", buf);}
}
if(pfd[1].revents) // UDP
diff --git a/update.c b/update.c
index f23df64..5b63b5f 100644
--- a/update.c
+++ b/update.c
@@ -73,6 +73,10 @@ void social_update_write(struct buffer* buf, struct update* update)
case UPDATE_CIRCLE:
buffer_write(*buf, &update->circle.circle, sizeof(update->circle.circle));
buffer_writestr(*buf, update->circle.name);
+ buffer_write(*buf, &update->circle.privacy.flags, sizeof(update->circle.privacy.flags));
+ buffer_write(*buf, &update->circle.privacy.circlecount, sizeof(update->circle.privacy.circlecount));
+ buffer_write(*buf, update->circle.privacy.circles, update->circle.privacy.circlecount);
+ buffer_write(*buf, &privplaceholder, sizeof(privplaceholder));
break;
}
}
@@ -132,6 +136,7 @@ struct update* social_update_getfield(struct user* user, const char* name)
if(!strcmp(user->updates[i].field.name, name)){return &user->updates[i];}
}
struct update* ret=social_update_new(user);
+ ret->type=UPDATE_FIELD;
ret->seq=0;
ret->signature=0;
ret->field.name=strdup(name);
@@ -149,6 +154,7 @@ struct update* social_update_getfriend(struct user* user, uint32_t circle, const
if(!memcmp(user->updates[i].friends.id, id, 20)){return &user->updates[i];}
}
struct update* ret=social_update_new(user);
+ ret->type=UPDATE_FRIENDS;
ret->seq=0;
ret->signature=0;
ret->friends.circle=circle;
@@ -156,6 +162,26 @@ struct update* social_update_getfriend(struct user* user, uint32_t circle, const
return ret;
}
+struct update* social_update_getcircle(struct user* user, uint32_t circle)
+{
+ unsigned int i;
+ for(i=0; i<user->updatecount; ++i)
+ {
+ if(user->updates[i].type!=UPDATE_CIRCLE){continue;}
+ if(user->updates[i].circle.circle==circle){return &user->updates[i];}
+ }
+ struct update* ret=social_update_new(user);
+ ret->type=UPDATE_CIRCLE;
+ ret->seq=0;
+ ret->signature=0;
+ ret->circle.circle=circle;
+ ret->circle.name=0;
+ ret->circle.privacy.flags=0;
+ ret->circle.privacy.circles=0;
+ ret->circle.privacy.circlecount=0;
+ return ret;
+}
+
#define advance(data, size, length) data+=length; size-=length
#define readbin(data, datalen, buf, buflen) \
if(datalen<buflen){return 0;} \
@@ -185,7 +211,7 @@ struct update* social_update_parse(struct user* user, void* data, unsigned int l
readbin(data, len, &privacy.circlecount, sizeof(privacy.circlecount));
uint32_t privcircles[privacy.circlecount];
privacy.circles=privcircles;
- readbin(data, len, privacy.circles, privacy.circlecount);
+ readbin(data, len, privacy.circles, sizeof(uint32_t)*privacy.circlecount);
// Placeholder, potentially supporting lists of individuals in addition to circles
uint32_t privplaceholder;
readbin(data, len, &privplaceholder, sizeof(privplaceholder));
@@ -250,12 +276,39 @@ struct update* social_update_parse(struct user* user, void* data, unsigned int l
if(add)
{
social_user_addtocircle(user, circle, id);
- } // TODO: Removal
+ }else{
+ social_user_removefromcircle(user, circle, id);
+ }
update=social_update_getfriend(user, circle, id);
if(update->seq>seq){return 0;} // Old version
update->friends.add=add;
}
break;
+ case UPDATE_CIRCLE:
+ {
+ uint32_t circle;
+ readbin(data, len, &circle, sizeof(circle));
+ uint32_t namelen;
+ readbin(data, len, &namelen, sizeof(namelen));
+ char name[namelen+1];
+ readbin(data, len, name, namelen);
+ name[namelen]=0;
+ struct privacy privacy;
+ readbin(data, len, &privacy.flags, sizeof(privacy.flags));
+ readbin(data, len, &privacy.circlecount, sizeof(privacy.circlecount));
+ uint32_t privcircles[privacy.circlecount];
+ privacy.circles=privcircles;
+ readbin(data, len, privacy.circles, sizeof(uint32_t)*privacy.circlecount);
+ struct friendslist* c=social_user_getcircle(user, circle);
+ free(c->name);
+ c->name=strdup(name);
+ privcpy(c->privacy, privacy);
+ update=social_update_getcircle(user, circle);
+ free((void*)update->circle.name);
+ update->circle.name=strdup(name);
+ privcpy(update->circle.privacy, privacy);
+ }
+ break;
default: return 0;
}
void* sigbuf=malloc(signaturesize);
diff --git a/update.h b/update.h
index bda758e..f215655 100644
--- a/update.h
+++ b/update.h
@@ -62,6 +62,7 @@ struct update
{
uint32_t circle;
const char* name;
+ struct privacy privacy;
} circle;
};
};
@@ -71,4 +72,5 @@ extern void social_update_sign(struct update* update);
extern void social_update_save(struct user* user, struct update* update);
extern struct update* social_update_getfield(struct user* user, const char* name);
extern struct update* social_update_getfriend(struct user* user, uint32_t circle, const unsigned char id[20]);
+extern struct update* social_update_getcircle(struct user* user, uint32_t circle);
extern struct update* social_update_parse(struct user* user, void* data, unsigned int len); // Both for receiving updates and loading them from file